前言:this是在函数被调用时发生绑定的,它指向什么完全取决于函数在哪里被调用。(也就是说,this的指向不是函数被创建时绑定,而是被怎么样的方式调用时绑定的)。可以看看我以前写的【this的指向问题】。
错误一:改变函数引用
var name = 'window'; var obj = { name: 'obj', show: function(){ console.log(this.name); } } var newShow = obj.show; newShow();
输出结果:this指向了window对象了
这时候执行newShow,输出的是window,而不是obj,这里其实涉及到的对象的引用问题。在obj对象里
show: function(){}, 这是函数对象的引用。后面var newShow = obj.show;这时也把函数对象的引用指向了newShow。相当于
var newShow = function(){ console.log(this.name); }
错误二:函数传参
var name = 'window'; var obj = { name: 'obj', show: function(){ console.log(this.name); } } function trigger(fn){ fn(); } trigger(obj.show);
输出结果:this指向了window对象了
这里把obj.show通过传参的方式,传给其他函数中调用,其实这时候也发生了,函数对象的引用改变。
相当于
function trigger(){ var fn = obj.show; fn(); }
错误三:定时器传参
var name = 'window'; var obj = { name: 'obj', show: function(){ console.log(this.name); } } setTimeout(obj.show,1000);
输出结果:this指向了window对象了
其实这里也是发生了传参,obj.show被当成了参数传给了setTimeout内置方法了。
错误四:DOM对象事件
var name = 'window'; var oBtn = document.getElementsByTagName('button')[0]; var obj = { name: 'obj', show: function(){ console.log(this.name); } } oBtn.name = 'DOM'; oBtn.onclick = obj.show;
输出结果:this指向了DOM对象
相当于
oBtn.onclick = function(){ console.log(this.name); }
还是对象函数的引用问题,还有是this的隐式绑定,this被隐式绑定给了DOM对象。
总结:
总的来说,导致this指向改变的原因就是有一个,那就是忽略的函数对象的引用关系(如果不清楚的朋友可以看看对象引用相关的知识点),函数对象的引用改变,也导致this(绑定)指向的改变。
如果对于this的绑定(指向)有不明白的可以看我以前写的【this的指向问题】
五:解决方案
①方案一
<body> <button>点击</button> <script> var name = 'window'; var oBtn = document.getElementsByTagName('button')[0]; var obj = { name: 'obj', show: function(){ console.log(this.name); } } //解决一 var newShow = function(){ obj.show(); }; newShow(); //解决二 function trigger(fn){ fn(); } trigger(function(){ obj.show(); }); //解决三 setTimeout(function(){ obj.show(); },1000); //解决四 oBtn.onclick = function(){ obj.show(); }; </script> </body>
②方案二:通过原生apply()强制改变this指向。
<body> <button>点击</button> <script> var name = 'window'; var oBtn = document.getElementsByTagName('button')[0]; var obj = { name: 'obj', show: function(){ console.log(this.name); } } function bind(fn,obj){ return function(){ return fn.apply(obj, arguments); }; } //问题一 var newShow = bind(obj.show,obj); newShow(); //问题二 function trigger(fn){ fn(); } trigger(bind(obj.show,obj)); //问题三 setTimeout(bind(obj.show,obj),1000); //问题四 oBtn.onclick = bind(obj.show,obj); </script> </body>
补充
错误六:arguments类数组改变this指向问题。
var length = 10; function fn(){ console.log(this.length); } var obj = { length: 5, method: function(fn){ fn(); arguments[0](); } }; obj.method(fn,"111","222");
还是看过我前面文章的朋友应该就知道,调用obj.mehtod这里首先输出的是10,this指向全局。那argument[0]()指向的是哪里,输出的是什么?不是10,也不是5, 输出的却是3。
这时候的this不是指向全局,也不是指向obj,而是指向了arguments了。
接下来我们看下以下例子:
function fn(){ console.log(this.length); } var obj1 = { fn:fn, num1:111, num2:222, length:3 }; obj1.fn(); var obj2 = { 0:fn, 1:111, 2:222, length:4 }; obj2[0](); var arr = [fn,111,222]; arr[0]();看完就豁然开朗了吧。数组是很特殊的对象,他的索引值相当于是obj2对象中的属性值。所以说数组,类数组也会改变this指向问题。