关于javascript中this指向的问题,总结如下。如有不妥之处,敬请指正。在 javascript中,this的重点不是定义函数的时候确定的,而是调用的时候确定的。换句话说,函数的调用方式决定了this指向什么。请记住:这只是指向我们调用函数的对象的指针。 这里把this在javascript中的调用方式分为以下几种:1、直接调用: 直接调用是指通过funName(..)调用。此时,函数内部的this指向全局变量。functionfoo(){console.log(this===global);}foo();//true 注意:直接调用并不是指在全局作用域内调用,在任何作用域下都可以通过funName(..)这样调用。下面两个例子也属于直接调用方式: a。使用bind函数改变外层函数的作用域,然后在内层直接调用。this点仍然是一个全局变量:functionfoo(){console.log(this===global);}functionfoo1(){foo();};varfoo2=foo1.bind({});//改变foo1的作用域functionfoo2();//true仍然指向全局变量 b,函数表达式,将一个函数赋值给一个变量,然后直接调用调用这个函数,它的this指向仍然是一个全局变量:varobj={foo:function(){console.log(this===obj);//falseconsole.log(this===global);//true}}varf=obj.foo;f();2、方法调用: 方法调用是指Object调用它的方法函数,类似于obj.foo(..)的调用方式。此时,this指向调用该方法的对象。请注意,最终调用该方法的是对象。varobj={foo1:function(){console.log(this===obj);}}obj.foo2=function(){console.log(this===obj);}functionfoo3(){控制台。日志(这===obj);}obj.foo3=foo3;obj.foo1();//trueobj.foo2();//trueobj.foo3();//true3,newcall: 在es5中,以newConstructor()的形式调用一个构造函数,会创建这个构造函数的一个实例,这个实例的this指向创建的实例。如以下示例所示,在构造函数中使用this.name不会更改全局变量名称的值。varname="global";functionPerson(name){this.name=name;}varp=newPerson("local");console.log(p.name);console.log(name);以上三个情况是一种普通的调用方式,还有一些特殊的调用方式如下:比如es6中的bind、call、apply、arrowfunctions。4.bind函数对this的作用 bind函数是用来绑定this的点,返回一个绑定函数,绑定this的点。注意:绑定函数的this指向不能再改。varobj={};functionfoo1(){console.log(this===obj);}foo1();//此时false属于上面的直接调用方法,所以它的this指向globalvarfoo2=foo1.bind(obj);foo2();//true被绑定函数的this指向它的绑定对象/***注意:被绑定函数的this不能改变*/varfoo3=foo2.bind({'a':1});foo3();//真foo2.apply({'a':1});//真foo2.call({'a':1});//true5、apply和call指向this apply和call的影响也可以用来改变this的方向,返回执行结果。bind、apply、call的区别和实现可以参考我的博客:《bind、call、apply的区别与实现》,这里不再赘述。需要注意的一点是apply和call不能改变绑定函数(bind返回的函数)的this点。varobj={};functionfoo1(){console.log(this===obj);}varfoo2=foo1.bind({'a':1});/***注意:this没有绑定它是一个固定函数,所以它的返回值仍然为真,即apply改变了它的this点。*/foo1.apply(obj);//true/***注意:这是一个绑定函数,所以它的this点不能通过apply和call改变。*/foo2.apply(obj);//false6,es6箭头函数中的this 箭头函数没有自己的this绑定,它使用的this是其直接父函数的this。也就是说,箭头函数内部的this由其直接外层函数(方法)决定,外层函数中的this由其调用方法决定。constobj={foo:function(){constinner=()=>{console.log(this===obj);};内();},far:function(){return()=>{console.log(this===obj);}}}/***inner()中的this是foo的this,它的指向取决于foo的调用方式*/obj.foo();//truevarfoo1=obj.foo;foo1();//false现在应该指向globalconstfar1=obj.far();far1();//trueconstfar2=obj.far;far2()();//false现在应该指向global6.1箭头函数常见错误及其解决方案:在对象上定义一个函数:consttest={array:[1,2,3],sum:()=>{console.log(这个===窗口);//=>truereturnthis.array.reduce((result,item)=>result+item);}};test.sum();//TypeError:Cannotreadproperty'reduce'ofundefined原因是箭头函数没有自己的this值,箭头函数内部的this值是从封闭范围继承的。对象方法中的this指向调用该方法的对象。如果使用箭头函数,则this与调用对象方法的环境的this值相同。因为test.sum()是在全局环境下调用的,此时this指向的是全局。解决方法也很简单。使用函数表达式或方法简写(ES6中已经支持)来定义方法,这可以确保这是由运行时包含它的上下文决定的。consttest={array:[1,2,3],sum(){console.log(this===test);//=>truereturnthis.array.reduce((result,item)=>result+item);}};test.sum();//6定义原型方法在对象原型上定义函数也遵循同样的规则functionPerson(name){this.name=name;}Person.prototype.sayName=()=>{console.log(这个===窗口);//=>truereturnthis.name;};constcat=newPerson('Mew');cat.sayName();//=>undefined使用传统的函数表达式可以解决问题//=>truereturnthis.name;};constcat=newPerson('Mew');cat.sayName();//=>Mew定义了事件回调函数this是JS中一个非常强大的特性,它允许动态调用函数改变上下文,然后箭头函数在声明时直接绑定到this对象,所以它不再是动态的。在客户端,将事件侦听器函数绑定到DOM元素是很常见的。当触发DOM事件时,回调函数中的this指向DOM。但是,箭头函数在声明时绑定到执行上下文。无法动态改变上下文,当需要动态上下文时它的缺点就凸显出来:constbutton=document.getElementById('myButton');button.addEventListener('click',()=>{console.log(this===window);//=>truethis.innerHTML='Clickedbutton';});因为这个回调的箭头函数是在全局上下文中定义的,所以它的this是window。也就是说,箭头函数预定义的context是不可修改的,所以this.innerHTML等价于window.innerHTML,没有意义。使用函数表达式在运行时动态改变this:constbutton=document.getElementById('myButton');button.addEventListener('click',function(){console.log(this===button);//=>truethis.innerHTML='点击按钮';});如果定义了构造函数,使用箭头函数会报错。显然,箭头函数不能用作构造函数。constMessage=(text)=>{this.text=text;};consthelloMessage=newMessage('HelloWorld!');//抛出“TypeError:Messageisnotaconstructor”理论上这是做不到的,因为this对象是在创建箭头函数的时候绑定的,它不会指向对象实例。箭头函数带来了很多方便。适当的使用箭头函数可以让我们避免使用早期的.bind()函数或者需要固定上下文的地方,让代码更加简洁。箭头函数带来了很多方便。适当的使用箭头函数可以让我们避免使用早期的.bind()函数或者需要固定上下文的地方,让代码更加简洁。 以上是我在JavaScript中对this的理解。欢迎您提出意见。欢迎访问我的个人博客了解更多信息。参考资料:1、《JavaScript 的 this 指向问题深度解析》2、《ES6使用箭头函数注意点》
