这篇文章想用JavaScript来解释一下,希望能帮助大家理解this的工作机制。作为一个JavaScript程序员,学习这个对你的开发有很大的帮助。可以说利大于弊。这篇文章的灵感来自我最近的作品——我即将出版的书的第一章——《JavaScript 应用程序设计 |JavaScript Application Design》(注意:你现在可以购买更早的版本),我在其中写了范围如何工作的各个方面。矛盾的是,这可能就是你对此的感受:疯了,不是吗?在这篇简短的文章中,我想揭开它的神秘面纱。这是如何工作的如果函数作为对象的方法被调用,那么this将被分配给对象。varparent={method:function(){console.log(this);}};parent.method();//<-parent注意这个行为是非常“脆弱”的,如果你得到一个方法引用并调用它,那么this的值将不再是parent,而是window全局对象。这让大多数开发人员感到困惑。varparentless=parent.method;parentless();//<-Window最重要的是,您应该查看调用链以了解被调用函数是对象的属性还是自身。如果作为属性调用,this的值将成为属性的对象,否则this的值将被赋值给全局对象或window。如果在严格模式下,this的值将是未定义的。在用作构造函数的情况下,当使用new关键字时,this将被赋值为正在创建的实例对象。functionThisClownCar(){console.log(this);}newThisClownCar();//<-ThisClownCar{}请注意,在这种情况下,无法识别是否应将函数用作构造函数,因此省略了new关键字结果in结果将是全局对象,正如我们在上面看到的,没有父调用。ThisClownCar();//<-Window改变this.call、.apply和.bind方法操作调用函数的方式,帮助我们定义this的值和传递给函数的参数值。Function.prototype.call可以有任意数量的参数,第一个参数赋值给this,其余传递给调用函数。Array.prototype.slice.call([1,2,3],1,2)//<-[2]Function.prototype.apply的行为类似于.call,但它传递给函数的参数是一个数组,而不是比任意参数。String.prototype.split.apply('13.12.02',['.'])//<-['13','12','02']Function.prototype.bind创建一个将始终使用的特殊函数传递给.bind的参数作为this的值,并且可以分配部分参数,创建原始函数的curride版本。vararr=[1,2];varadd=Array.prototype.push.bind(arr,3);//effectivelythesameasarr.push(3)add();//effectivelythesameasarr.push(3,4)add(4);console.log(arr);//<-[1,2,3,3,4]thisinthescopechain在下面的例子中,this不会在作用域链中保持不变。这是规则中的一个缺陷,经常给业余开发者造成混淆。functionscoping(){console.log(this);returnfunction(){console.log(this);};}scoping()();//<-Window//<-Window有一个常用的方法来创建一个局部变量保留对此的引用,并且不能在子作用域中具有相同的变量。子作用域中的同名变量将覆盖父作用域中对this的引用。functionretaining(){varself=this;returnfunction(){console.log(self);};}retaining()();//<-Window除非你真的想同时使用父scope的this,以及this的当前值,出于某些莫名其妙的原因,我更喜欢使用.bind函数的方法。这可用于将父作用域的this分配给子作用域。functionbound(){returnfunction(){console.log(this);}.bind(this);}bound()();//<-Window其他问题?您对此有任何疑问吗?那这个呢?如果您认为我错过了任何其他边缘案例或优雅的解决方案,请告诉我。如果您喜欢这篇文章,请务必查看我即将出版的新书《JavaScript 应用程序设计 |JavaScript Application Design》,您可以访问链接购买早期版本。原文链接:http://blog.jobbole.com/54267/
