关于javascript中this指向问题的介绍

this在javascript中和在其他面向对象语言中是不同的,this在javascrript相对比较灵活,this在javascript中跟定义的位置是没有关系的,而是跟调用的方式和调用的位置是有关系的,并且,this在javascript中是在运行过程中动态绑定的。

this的4种绑定规则

1.默认绑定:独立函数的调用

//说明:以下代码的测试环境均为Chrome浏览器,node环境的打印结果还请大家自行测试,主要的区别在于window对象
//案例一:
function foo(){
	console.log(this);
}
foo();//这里是独立调用,foo函数中打印的this会指向window

//案例二
function foo1(){
	console.log(this);
	foo(2);
}
function foo2(){
	console.log(this);
	foo3();
}
function foo3(){
	console.log(this);
}
foo1();//这里虽然在函数实现了相互之间的调用,但是仍然还是独立的函数调用,this仍然指向window

//案例三:
function foo4(func){
	func();
}
var obj = {
	name:'obj',
	foo5(){
		console.log(this)
	}
}
foo4(obj.foo5);//这里虽然将一个函数的作为参数传入了另一个函数中去,但是对于调用的函数foo4来讲,仍然是独立的函数调用,this仍然会指向window

总结:在javascript中,只要函数是独立调用的,那么this必定会指向window


2.隐式绑定
隐式绑定简单理解就是通过对象进行调用函数,隐式调用有一个条件就是必须在调用的对象内部有一个函数的引用(比如一个属性),如果没有这个引用的存在,那么在代码被执行时会报一个找不到该函数的错误,也正是这通过这个函数的引用,间接的将this绑定到了这个对象上去。

//说明:以下代码的测试环境均为Chrome浏览器,node环境的打印结果还请大家自行测试,主要的区别在于window对象 
//案例一:
function foo(){
	console.log(this);
}
var obj = {
	name:'obj',
	foo:foo
}
obj.foo();//这里obj对象中有foo的引用,obj又调用了foo函数,符合隐式绑定,这时,this也就指向了obj对象

//案例二:
function foo2(){
	console.log(this);
}
var obj1 = {
	name:'obj1',
	foo2:foo2
}
var obj2 = {
	name:'obj2',
	obj1:obj1
}
obj2.obj1.foo2();//这里obj2中有obj1的引用,obj1中又有foo2的引用,虽然是obj2调用了obj1,调用了foo2,但是实际上仍然是obj1调用了foo,所以this会指向到obj1,而不是obj2

//案例三:
function foo3(){
	console.log(this);
}
var obj3 = {
	name:'obj3',
	foo3:foo3
}
var foo4 = obj3.foo3;
foo4();//这里可以简单理解为是将obj3.foo3这个函数的调用赋值给了foo4,之后foo4的调用实际就是独立的函数调用,this会指向window

总结:隐式绑定的情况下,看是谁发起的函数调用,谁发起,this就指向谁


3.显示绑定
显示绑定就是通过javascript的内置函数call/apply/bind进行调用函数,显示绑定不需要像隐式绑定一样必须在函数内部有一个引用,显示绑定会对函数进行强制调用。

//说明:以下代码的测试环境均为Chrome浏览器,node环境的打印结果还请大家自行测试,主要的区别在于window对象 
//call和apply
function foo(num1,num2){
	console.log(num1 + num2,this);
}
foo.call('aaa',1,2);//这里使用了call进行显示绑定,this会指向aaa
foo.apply('bbb',[1,2]);//这里使用了apply进行显示绑定,this会指向bbb
//补充:call和apply实现发效果和作用是一样的,唯一的区别就是在传参时,call和apply的第一个参数都是一个对象,代码执行以后会将this绑定到这个对象上去,后面的参数是函数执行时需要传入的参数,call是通过普通传参的方式将形参的实参传入,apply是将形参的实参通过一个数组的方式进行传入。

//bind bind可以将this总是绑定到一个对象上去,而不是像call和apply一样,使用一次绑定一次
function foo1(){
	console.log(this);
}
var obj = {
	name:'obj'
}
var foo2 = foo1.bind(obj);
foo2();//这里的foo虽然是独立的函数调用,但是之前是将foo1通过bind绑定到了obj上,之后再赋值给foo2上,所以最终的this会指向obj,而不是window

总结:如果在函数调用过程中出现了call、apply、bind等内置函数的使用,一定是会显示绑定this的


4.new绑定
使用new关键字来调用函数,是创建了一个新的对象,这个新的对象会被执行prototype,新对象会绑定到函数调用的this上去,this也是在这个步骤中完成的绑定的,如果函数没有返回其他对象,表达式会返回这个新的对象的。

//说明:以下代码的测试环境均为Chrome浏览器,node环境的打印结果还请大家自行测试,主要的区别在于window对象 
//案例:
function Foo(name){
	this.name = name;
	console.log(this);
}
var f = new Foo(foo);//使用了new关键字来调用函数
console.log(f);//这里的this会打印出f对象

总结:如果在函数的调用中使用了new关键字,那么就去看函数通过使用new关键字创建了那个对象,创建了谁,this就会指向谁

以上就是this的4中绑定规则的介绍。


绑定优先级
上面说到了this有4中绑定规则,那么如果2种或者2种以上的规则同时出现时,this的绑定会执行那一种规则呢?这就是this绑定的优先级了。
优先级:new绑定 > 显示绑定 > 隐式绑定 > 默认绑定
注意:new绑定不能和call、apply同时进行使用,也就不存在所谓的优先级问题了,但是new绑定可以和bind进行同时使用,但是new绑定的优先级要高于bind。


特殊绑定
1.忽略显示绑定
如果在显示绑定时,传入了一个null和undefined,那么会自动忽略这个显示绑定,使用默认绑定的规则。

//说明:以下代码的测试环境均为Chrome浏览器,node环境的打印结果还请大家自行测试,主要的区别在于window对象 
//在使用call、apply、bind时,如果传入了null和undefined,会自动将this绑定成全局对象,也就是使用默认绑定的规则
function foo(){
	console.log(this);
}
var obj = {
	name:'obj
}

foo.call(obj);//显示绑定,this指向了obj对象
foo.call(null);//显示绑定传入null,忽略显示绑定,使用默认绑定,this指向了window
foo.call(undefined);//显示绑定传入了undefined,忽略显示绑定,使用默认绑定,this指向了window

foo.apply(obj);//显示绑定,this指向了obj对象
foo.apply(null);//显示绑定传入null,忽略显示绑定,使用默认绑定,this指向了window
foo.apply(undefined);//显示绑定传入了undefined,忽略显示绑定,使用默认绑定,this指向了window

var foo1 = foo.bind(null);
foo1();//显示绑定传入null,忽略显示绑定,使用默认绑定,this指向了window

2.间接函数的引用
如果创建了一个函数的简介引用,那么这种情况也会使用默认绑定规则

//说明:以下代码的测试环境均为Chrome浏览器,node环境的打印结果还请大家自行测试,主要的区别在于window对象 
function foo(){
	console.log(this);
}
var obj = {
	name:'obj,
	foo:foo
}
var obj1 = {
	name:'obj1
}

obj.foo();//隐式绑定,this指向了obj
(obj1.foo = obj.foo)();//函数间接引用,使用默认绑定规则,this指向了window

箭头函数的this
在箭头函数中是不会绑定this的,无论是那种绑定方式都是不会生效的,箭头函数中的this会向上层作用域中进行查找,使用上层作用域的this。
这里需要主要强调的是箭头函数是不能和new同时进行使用的

//说明:以下代码的测试环境均为Chrome浏览器,node环境的打印结果还请大家自行测试,主要的区别在于window对象 
var obj = {
	data:[],
	getData:() => {
		setTimeout(() => {
			console.log(this);//这里的箭头函数是没有this的,它会向上层作用域中进行查找,也就是window
		})
	}
}

这里对javascript中的this指向问题做了一个简单介绍,如果有不足或者错误的地方,还请码友指出,我也及时更正和学习!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值