【JavaScript】常见的隐式改变this指向的几种错误

前言: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指向问题。


猜你喜欢

转载自blog.csdn.net/w390058785/article/details/80078138