# Heading
# 概述
在绝大多数情况下,函数的调用方式决定了this的值。this不能在执行期间被赋值,并且在每次函数被调用时this的值也可能会不同。ES5引入了bind方法来设置函数的this值,而不用考虑函数如何被调用的,ES2015 引入了支持this词法解析的箭头函数(它在闭合的执行环境内设置this的值)。
# 不同场景下的this指向
# 全局环境
无论是否在严格模式下,在全局执行环境中(在任何函数体外部)this 都指向全局对象。 浏览器中,全局对象是window node中,全局对象是global。以下均采用window代表全局对象。
console.log(this === window); // true
1
# 函数(运行内)环境
- 简单调用
function f1(){
return this; //this指向window
}
f1() === window;
function f2(){
"use strict"; // 严格模式
return this; //this指向undefined
}
f2() === undefined; // true
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
- call or apply 如果要想把 this 的值从一个环境传到另一个,就要用 call 或者apply 方法。
var obj = {a: 'fromObj'};
var a = 'fromWindow';
function fn(arg) {
return this.a; // this的值取决于函数的调用方式
}
fn(); // 'fromWindow'
fn.call(obj); // 'fromObj'
fn.apply(obj); // 'fromObj'
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
- bind ECMAScript 5 引入了 Function.prototype.bind。调用f.bind(obj)会创建一个与f具有相同函数体和作用域的函数,但是在这个新函数中,this将永久地被绑定到了bind的第一个参数,无论这个函数是如何被调用的。
function f(){
return this.a;
}
var g = f.bind({a:"azerty"});
console.log(g()); // azerty
var h = g.bind({a:'yoo'}); // bind只生效一次!
console.log(h()); // azerty
var o = {a:37, f, g, h};
console.log(o.f(), o.g(), o.h()); // 37, azerty, azerty
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
- 箭头函数 函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。 this指向取决于外层函数的this指向。
var globalObject = this;
var foo = (() => this);
console.log(foo() === globalObject); // true
var obj = {foo};
console.log(obj.foo() === globalObject); // true
// 尝试使用call来设定this
console.log(foo.call(obj) === globalObject); // true
// 尝试使用bind来设定this
foo = foo.bind(obj);
console.log(foo() === globalObject); // true
//other eg:
var obj = {
bar: function() {
var x = (() => this);//它的this被永久绑定到了它外层函数bar的this
return x;
}
};
var fn = obj.bar();//被obj调用的,bar的this指向obj
fn() === obj //true
var fn2 = obj.bar;
fn2()() == window //true 被window调用的,bar的this指向objwindow
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
- 作为对象的方法 当函数作为对象里的方法被调用时,它们的 this 是调用该函数的对象。 this 的绑定只受最靠近的成员引用的影响。
var o = {
prop: 37,
f: function() {
return this.prop;
}
};
console.log(o.f()); //37
var o = {prop: 37};
function independent() {
return this.prop;
}
o.f = independent;
console.log(o.f()); //37
o.b = {g: independent, prop: 42};
console.log(o.b.g()); // 42
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
- 原型链中的 this 如果该方法存在于一个对象的原型链上,那么this指向的是调用这个方法的对象,就像该方法在对象上一样。
var o = {
f: function() {
return this.a + this.b;
}
};
var p = Object.create(o);
p.a = 1;
p.b = 4;
console.log(p.f()); // 5
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
getter 与 setter 中的 this 用作 getter 或 setter 的函数都会把 this 绑定到设置或获取属性的对象。
作为构造函数 当一个函数用作构造函数时(使用new关键字),它的this被绑定到正在构造的新对象。 虽然构造器返回的默认值是this所指的那个对象,但它仍可以手动返回其他的对象(如果返回值不是一个对象或者null,则返回this对象)。
/*
* 构造函数这样工作:
*
* function MyConstructor(){
* // 函数实体写在这里
* // 根据需要在this上创建属性,然后赋值给它们,比如:
* this.fum = "nom";
* // 等等...
*
* // 如果函数具有返回对象的return语句,
* // 则该对象将是 new 表达式的结果。
* // 否则,表达式的结果是当前绑定到 this 的对象。
* //(即通常看到的常见情况)。
* }
*/
function C(){
this.a = 37;
}
var o = new C();
console.log(o.a); // logs 37
function C2(){
this.a = 37;
return {a:38};
}
o = new C2();
console.log(o.a); // logs 38
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
作为一个DOM事件处理函数 当函数被用作事件处理函数时,它的this指向触发事件的元素(一些浏览器在使用非addEventListener的函数动态添加监听函数时不遵守这个约定)。
作为一个内联事件处理函数 当代码被内联on-event 处理函数调用时,它的this指向监听器所在的DOM元素:
<button onclick="alert(this.tagName.toLowerCase());">
Show this
</button>
1
2
3
2
3
显示button
在这种情况下,没有设置内部函数的this,所以它指向 global/window 对象(即非严格模式下调用的函数未设置this时指向的默认对象)。
<button onclick="alert((function(){return this})());">
Show inner this
</button>
1
2
3
2
3
显示[object Window]