首页 > 网站 > WEB开发 > 正文

例证关于js中call和apply的误解

2024-04-27 14:08:29
字体:
来源:转载
供稿:网友

例证关于js中call和apply的误解

发现一些文章对call和apply的存在误解,因为误解的解释方式比较容易被理解吧,当然也有批判的,但都只是说说怎么才是对的,没有具体分析误解为什么是误解今天让我们来仔细分析一下,为何不恰当

function add(a, b) {     alert(a + b);}function sub(a, b) {     alert(a - b);}add.call(sub, 3, 1);     //4

说词1:用 add 来替换 sub说词2:call方法前面的东西(add)都交给后面(sub)了说词3:sub 已经接过了add方法恰当理解: 将add执行的上下文由window对象切换为对sub的引用,即this指向从window对象变为对sub的引用,仅此而已,这个例子其实没有什么实际上的意义 以上为从网络上摘选的观点“说词”派说,看上去结果一样,凭什么这个理解就是恰当的?OK,首先,我们来看下什么是上下文:在javaScript中,你的代码将总是有着某种形式的上下文(代码在其内部工作的对象)。上下文是通过变量this工作的,变量this总是引用代码当前所在的那个对象。全局对象实际上是window对象的属性,这意味着即使是在全局上下文里,this变量仍然引用一个对象。搞清了上下文,那么我们来看这样一个函数

function test() {     var myValue = 1;     this.value = 2;}

这个函数中,value很明显是存在于上下文中的而myValue 是无法用this访问到的,类似私有变量的概念问题来了,对于“说词”派的那些理解方式,“私有变量”也被传递了,所以结果是4,没有2看到这里会不会有很奇怪的感觉了?真的是这样么?我们再来分析,改写一下add和sub两个函数:

function add(a, b) {     alert(inner(a, b));}function sub(a, b) {     function inner() {          this.value = arguments[0] - arguments[1];          return this.value     };}add.call(sub, 3, 1);

按照“说词”的解释,alert(inner(a, b)) 被传到 sub 中,那么结果为2事实上,运行这段代码的时候,会发现抛错“inner is not defined”“说词”派可能会站出来反驳了,add 都把 sub 整个覆盖了,肯定没有inner方法了我们继续看,把add改一下

function add(a, b) {     alert(this);}function sub(a, b) {     function inner() {          this.value = arguments[0] - arguments[1];          return this.value     };}add.call(sub, 3, 1); 

然后看输出 哦,买糕的,这是神马情况?怎么把sub函数代码体整个输出了?“说词1”完全不对,sub被替换成add后怎么this还会是sub?“说词2”和“说词2”也不对,如果是把add交个sub或sub接过了add的方法,那么在sub中执行alert(this)的结果是,this指向windowSo,“说词”派,团灭我们再来看一看,什么情况下会把函数代码体本身给输出来?

function test(a, b) { this.value = 1;}console.log('test:', test );console.log('test():', test() );console.log('new test():', new test() ); 

输出结果: 输出函数的引用,才会把函数代码体本身给输出我们再把“sub函数代码体整个输出”现象按“恰当解释”的说法走一边,其实是很容易解释的:call和apply实现的是切换函数对象的上下文把add的上下文this切换到sub的引用上,所以this把sub函数代码体整个给输出来了,事实上,这个做法完全没有什么意义,因为this.value根本就undefined基于这一结论,我们把本文最开始的代码这样改造一下,此时sub才参与工作了

function add(a, b) {     alert(a + b);     this(a, b)     //此处相当于执行sub}function sub(a, b) {     alert(a - b);}add.call(sub, 3, 1);     //4     //2
现在是不是更清晰更本质的认识到call的作用了?

不过,日常开发中,我们需要的是切换到一个有意义的上下文中,也就是this.value在切换上文后,能很方便的取到不同的值,我们发现new一个实例出来的结果为一个{}对象,最符合我们的需要,就像这样

function add(a, b) {     this.inner(a, b);}function sub() {     this.inner = function(a, b) {          alert(a - b);     };}add.call(new sub(), 3, 1);    //2

OK,扯了这么多,最后,再发一例更直接的干货,来看一段代码

function add(a, b) {     this.inner(a, b);}function sub(a, b) {     this.inner = function() {          alert(arguments.callee.caller);     };}add.call(new sub(), 3, 1);
此时arguments.callee相当于this.inner,当this.inner()执行的时候,arguments.callee才有效 再次根据“说词”派的解释,this.inner(a, b)交给了sub来执行,执行者是sub,那么this.inner()的caller必定指向sub 事实上并非如此,输出结果:

输出的结果是add也就是说,call仅仅是将add的上下文替换成了sub,执行者仍然是add,不是sub

转载请注明出处:http://www.cnblogs.com/tevinli/p/4558107.html


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表