JavaScript this全面解析

先说结论

我们可以顺序应用下面四条规则来判断this的绑定对象:

  1. 如果是由new调用,绑定到新创建的对象。
  2. 如果是由call或者applybind调用,绑定到指定的对象上。
  3. 如果是由上下文对象调用(即this是对象中的方法里使用的),绑定到那个上下文对象上。
  4. 如果是默认情况下,严格模式绑定到undefined,否则绑定到全局对象上。

但是ES6中的箭头函数并不会使用者四条标准的绑定规则。箭头函数会继承外层函数调用的this绑定。

new绑定
function foo(a){
	this.a=a;
}
var bar=new foo(2);
console.log(bar.a);  //2

我们使用new来调用foo(…)时,会构造一个新对象并把它绑定到foo(…)调用中的this上。



显式绑定callapplybind
function foo(){
	console.log(this.a);
}
var obj={
	a:2;
};
foo.call(obj);  //2

call用来将函数foo中的this绑定到obj上。



隐式绑定(上下文对象调用)

如果this所在的函数是对象中的方法的话,this就会指向这个对象。

function foo(){
	console.log(this.a);
}
var obj={
	a:2,
	foo:foo
};
obj.foo();  //2

foo此时是obj对象的一个方法,所以this就会指向obj。

但是对象属性引用链中只有上一层或者说最后一层在调用位置中起作用:

function foo(){
	console.log(this.a);
}
var obj2={
	a:42,
	foo:foo
};
var obj1={
	a:2,
	obj2:obj2
};
obj1.obj2.foo();  //42

隐式丢失也是this隐式绑定中常见的问题:

function foo(){
	console.log(this.a);
}
var obj={
	a:2,
	foo:foo
};
var bar=obj.foo;  //函数别名!
var a="oops, global";  //a是全局对象的属性
bar();  //“oops, global”

此时barobj.foo的一个引用,但实际上它引用的是foo函数本身,因此此时的bar()其实是一个不带任何修饰的函数调用,因此应用了默认绑定。


回调函数丢失this绑定是也是非常常见的问题:

function foo(){
	console.log(this.a);
}
function doFoo(fn){
	fn();  //调用位置
}
var obj={
	a:2,
	foo:foo
};
var a="oops global";  //全局对象属性
doFoo(obj.foo);  //"oops global"

函数doFoo传入了函数作为参数,并在doFoo中调用。我们可以把它看做将函数copy到了doFoo函数体中,调用的时候this指向的是全局作用域。



默认绑定
function foo(){
	console.log(this.a);
}
var a=2;
foo();  //2

在这个例子中,函数调用应用了this的默认绑定,this指向全局对象。

如果使用严格模式(strict mode),则不能将全局对象用于默认绑定,this会绑定到undefined

function foo(){
	"use strict";
	console.log(this.a);
}
var a=2;
foo();  //TypeError: this is undefined


箭头函数中的this

箭头函数不会创建自己的this,它只会从自己的作用域链的上一层继承this。

function foo(){
	return (a)=>{
		console.log(this.a);
	}
}
var obj1={
	a:2
};
var obj2={
	a:3
};
var bar=foo.call(obj1);
bar.call(obj2);  //2,不是3!

foo()内部创建的箭头函数会捕获调用时foo()的this。由于foo()this绑定到obj1,所以bar(引用箭头函数)的this也会绑定到obj1,箭头函数的绑定无法被修改。

再看一个例子:

function foo() {
  setTimeout(() => {
    console.log('id:', this.id);
  }, 100);
}

var id = 21;

foo.call({ id: 42 });
// id: 42

foo调用时传入的是什么对象,this就指向谁。如果是普通函数,执行时this应该指向全局对象window,这时应该输出21(严格模式则输出undefined)。

参考书籍:《你不知道的JavaScript》
详情可见我的博客:http://delaprada.com

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值