前言: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 oHtml = document.documentElement;
var obj = {
name: 'obj',
show: function(){
console.log(this.name);
}
}
oHtml.name = 'DOM';
oHtml.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指向问题。