this在js中一直是谜一样的存在着,在面试中也是经常会被问道,接下来总结下我所理解的this
首先引入秘密花园中对this的工作原理,文中指出有五种情况,分别是:

  • 全局范围内
1
this;	//在全局范围内使用`this`,它将会指向全局对象
  • 函数调用
1
foo();	//this指向全局对象
  • 方法调用
1
test.foo();	//this指向test对象
  • 调用构造函数
1
new foo();	//函数与new一块使用即构造函数,this指向新创建的对象
  • 显式的设置this
1
2
3
4
function foo(a, b, c) {}
var bar = {};
foo.apply(bar, [1, 2, 3]); //this被设置成bar
foo.call(bar, 1, 2, 3); //this被设置成bar

从函数调用理解this

有这样一道题

1
2
3
4
5
6
7
8
var obj = {
func: function(){
console.log(this);
}
}
var foo = obj.func;
obj.func() //this是obj
foo() //this是window

解释函数结果为什么不一样?

这道题可以从函数调用来理解,从我看到的博文中有这样的解释,秘密花园中的函数调用,方法调用,显式的设置this都属于函数调用,相当于函数调用的三种方式,可以写成

1
2
3
foo(params);
obj.child.foo(params);
foo.call(context, params); //apply同理

而且前两种都可以写成第三种形式

1
2
foo(params); =>> foo.call(undefined, params);
obj.child.foo(); =>> obj.child.foo.call(obj.child, params);

所以说函数调用都是foo.call(context, params)的变体,即函数调用只有一种。这样this的值就是文中的contextthis就是你函数调用时传入的context

举例代码中:

1
2
3
4
function foo() {
console.log(this);
}
foo();

当你无法确认this指代的值时,转化成call形式会更好理解

1
2
3
4
function foo() {
console.log(this);
}
foo.call(undefined); //or foo.call();

函数执行结果为window,在浏览器中有一条规定,传入contextnullundefined时,则为全局对象(window对象);严格模式下contextundefined

举例代码中:

1
2
3
4
5
6
var obj = {
func: function foo() {
console.log(this);
}
}
obj.foo();

转化为call形式为

1
2
3
4
5
6
var obj = {
func: function foo() {
console.log(this);
}
}
obj.foo.call(obj);

很明显,this指代obj。

Event Handler 中的this

1
2
3
btn.addEventListener('click' ,function handler(){
console.log(this) // 请问这里的 this 是什么
})

handler 中的this是什么?用上面的方法好像没法转化了,因为不知道addEventListener内源码实现,查看文档MDN

通常来说this的值是触发事件的元素的引用,这种特性在多个相似的元素使用同一个通用事件监听器时非常让人满意。

当使用 addEventListener() 为一个元素注册事件的时候,句柄里的 this 值是该元素的引用。其与传递给句柄的 event 参数的 currentTarget 属性的值一样。

所以可以假设浏览器addEventListener是这样实现的

1
2
// 当事件被触发时
handler.call(event.currentTarget, event) // this => event.currentTarget

以上就是对this的理解。