this

this提供了一种更加优雅的方式来隐式”传递”一个对象引用,因此可以将API设计得更加简洁并且易于复用。this是在运行时进行绑定的,并不是在编写时绑定,它的上下文取决于函数调用时的条件。

默认绑定

全局上下文

在全局运行上下文中(在任何函数体外部),this指代全局对象,无论是否在严格模式下。

1
2
3
4
5
6
7
console.log(this.document === document); // true
// 在浏览器中,全局对象为 window 对象:
console.log(this === window); // true
this.a = 37;
console.log(window.a); // 37

独立函数调用

  • 非strict模式下,this指向全局对象。
1
2
3
4
5
function f1(){
return this;
}
f1() === window; // true
  • strict模式下,this会绑定到undefined。
1
2
3
4
5
6
function f2(){
"use strict"; // 这里是严格模式
return this;
}
f2() === undefined; // true

隐式绑定

在某个上下文对象中调用,this指向相应的对象

1
2
3
4
5
6
7
8
9
10
function foo(){
console.log(this.a);
}
var obj = {
a: 2,
foo: foo
};
abj.foo();//2

隐式丢失

被隐式绑定的函数会丢失绑定对象,也就是说它会引用默认绑定,从而把this绑定到全局对象或者undefined上,取决于是否是严格模式。

  • 函数别名
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/*引用的是foo函数本身,因此应用了默认绑定*/
function foo(){
console.log(this.a);
}
var obj = {
a: 2,
foo: foo
}
var bar = obj.foo; //函数别名!
var a = "oops,global"; //a是全局对象
bar(); //"oops,global"
  • 回调函数
1
2
3
4
5
6
7
8
9
10
11
12
13
/*引用的是foo函数本身,因此应用了默认绑定*/
function foo(){
console.log(this.a);
}
var obj = {
a: 2,
foo: foo
}
var a = "oops,global"; //a是全局对象
bar(); //"oops,global"; //"oops,global"

显式绑定

call,apply和bind方法

call(),apply()方法的区别在于call()方法接受的是若干个参数的列表,而apply()方法接受的是一个包含多个参数的数组。bind()方法返回的是一个新的函数,call,apply方法返回的是含有this和arguments的函数值。这三种方法的第一个参数都是显式的传入this,后面的参数则为arguments。

1
2
3
4
5
6
7
8
9
10
11
12
13
var obj = {
x: 81,
};
var foo = {
getX: function() {
return this.x;
}
}
console.log(foo.getX.bind(obj)()); //81
console.log(foo.getX.call(obj)); //81
console.log(foo.getX.apply(obj)); //81

API调用的”上下文”

DOM事件处理函数中的 this

DOM事件处理函数中的 this指向(event.currentTarget)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 被调用时,将关联的元素变成蓝色
function bluify(e){
console.log(this === e.currentTarget); // 总是 true
// 当 currentTarget 和 target 是同一个对象是为 true
console.log(this === e.target);
this.style.backgroundColor = '#A5D9F3';
}
// 获取文档中的所有元素的列表
var elements = document.getElementsByTagName('*');
// 将bluify作为元素的点击监听函数,当元素被点击时,就会变成蓝色
for(var i=0 ; i<elements.length ; i++){
elements[i].addEventListener('click', bluify, false);
}

内联事件处理函数中的 this

当代码被内联处理函数调用时,它的this指向监听器所在的DOM元素

1
2
3
<button onclick="alert(this.tagName.toLowerCase());">
Show this
</button>

new绑定

当一个函数被作为一个构造函数来使用(使用new关键字),它的this与即将被创建的新对象绑定。
注意:当构造器返回的默认值是一个this引用的对象时,可以手动设置返回其他的对象,如果返回值不是一个对象,返回this。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function C(){
this.a = 37;
}
var o = new C();
console.log(o.a); // logs 37
/*this绑定的默认对象被取消*/
function C2(){
this.a = 37;
return {a:38};
}
o = new C2();
console.log(o.a); // logs 38

箭头函数绑定

箭头函数继承外层函数调用的this绑定

1
2
3
4
5
6
7
8
9
10
11
function foo(){
这里的this在词法上继承自foo()
setTimeout(()=>{
console.log(this.a);
},100);
}
var obj = {
a: 2
};
foo.call(abj); //2

总结

绑定方式 this指向
默认绑定 this指向全局对象,strict模式函数独立函数调用指向undefined
隐式绑定 this指向相应的对象
显式绑定 call,apply,bind的this指向第一个参数;DOM事件处理函数中的this指向event.currentTarget;内联事件处理函数中的this指向DOM元素
new绑定 this默认指向被创建的对象,若构造函数的返回值为对象,则指向返回值
箭头函数 this继承外层函数调用的this绑定