javascript-关键字this

JavaScript - 关键字 this

关键字 this 是在函数调用过程中,自动生成的一个内部对象,只能在函数的内部中使用,不能在执行期间被赋值。函数的调用方式的不同决定了 this 的值。此外,在 严格模式非严格模式this 的值也会有差别。
简而言之,this 总是指向调用该函数的对象

全局上下文

1
console.log(this === window); // true

无论是否在严格模式下,在全局执行上下文中 this 都指代全局对象 window

函数上下文

直接调用

1
2
3
4
5
function f1() {
return this;
}

f1(); // window

非严格模式下,函数直接被调用,在浏览器中,this 指向 window

1
2
3
4
5
6
function f1() {
'use strict'; // 严格模式
return this;
}

f1(); // undefined

严格模式下,函数直接被调用,thisundefined

作为对象的方法调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var o = { prop: 37};

function independent() {
return this.prop;
}

o.f = independent;

o.f(); // 37, f函数中的 this 为调用该函数的对象,即 o

o.b = {
g: independent,
prop: 39
};

o.b.g(); // 39,g函数中的 this 为调用该函数的对象,即 o.b

作为对象的方法调用函数时,它们的 this 是调用该函数的对象

作为构造函数

当一个函数用作构造函数时,它的 this 被绑定到正在构造的新对象,构造器返回的默认值是 this 所指的那个对象。但构造器也可以 return 其他的对象(如果 return 的不是一个对象,则返回 this 对象),这样与 this 绑定的默认对象就被丢失了。

作为一个 DOM 事件处理函数

当函数用作事件处理函数时,其 this 指向触发事件的元素,即 this === e.currentTarget。只有触发事件的对象是注册了事件监听器的对象时,this === e.target,而 e.currentTarget === e.target 同时也相等

作为一个内联事件处理函数

1
2
3
4
<!-- 在显示的弹窗中会显示 button -->
<button onclick="alert(this.tagName.toLowerCase());">
click
</button>

this 指向监听器所在的 DOM 元素

原型链中的 this

1
2
3
4
5
6
7
8
9
10
11
12
var o = {
f: function () {
return this.a + this.b;
}
};

var p = object.create(o);

p.a = 1;
p.b = 2;

p.f(); // 3

对象 p 没有自己的 f 属性,它的 f 属性继承自它的原型,this 的查找过程是从 p.f 的引用开始的,因为 f 是作为 p 的方法调用的,所以它的 this 还是指向 p

apply / call 调用

1
2
3
4
5
6
7
8
9
10
11
var obj = { a: 'Custom'};

var a = 'Global';

function foo() {
return this.a;
}

foo(); // 直接调用,返回'Global'
foo.apply(obj); // apply调用,返回'Custom'
foo.call(obj); // call调用,返回'Custom'

使用函数对象的 callapply 方法可以改变函数的调用对象,将 this 的值从一个上下文传到另一个。但有一点要注意,如果传入的 this 不是一个对象,JavaScript将尝试使用内部 ToObject 操作将其转换为对象

bind 方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function foo() {
return this.a;
}

var g = foo.bind({ a: "qwer"});
g(); // "qwer"

var h = g.bind({ b: "asdf"});
h(); // "qwer",bind只生效一次

var o = {a: "zxcv", foo: foo, g: g, h: h};
o.foo(); // “zxcv”
o.g(); // "qwer"
o.h(); // "qwer"

使用函数对象的 bind 方法会创建一个与 foo 具有相同函数体和作用域的函数,但在这个 新函数 中,this永久 绑定到了 bind 的第一个参数,且无论这个参数是如何被调用的

箭头函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 创建一个含有 bar 方法的 obj 对象,bar返回一个函数,这个函数返回自己的 this 值
var obj = {
bar: function *( {
var x = (() => this);
return x; // 这个返回的函数是以箭头函数创建的,所以 this 的值被永久绑定到了它外层函数的 this,而 bar 里面的 this 值可以在调用时设置
})
};

var fn = obj.bar(); // bar 函数被作为 obj 的一个方法调用,所以其中的 this 绑定到 obj

fn() === obj; // true,箭头函数里面的this 值由 barthis 值决定,也为 obj 这个对象。但是如果这个函数不是箭头函数而是普通函数,那么 fn 执行返回的 this 值默认是全局对象,严格模式下为 undefined

var fn2 = obj.bar; // 这个只是引用了 obj 的方法,没用调用它,所以 this 并没有在此时被指定(this 是在函数调用过程中设置的)

fn2()() === window; //true // 函数被调用 箭头函数返回的 this 值绑定到了,fn2() 的 this,即 window

其实箭头函数中根本没有自己的 this ,其内部的 this 被设置为它被创建时的上下文(一般为函数上下文)中的 this,且这个上下文中的 this 也是在被调用时确定的。这也是为什么箭头函数不能用作构造函数的原因