发现一些文章对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
新闻热点
疑难解答