文章是本人大三期间的学习笔记,一些论断取自书籍和网上博客,碍于当时的技术水平有一些写得不够好的地方,可以在评论处理智讨论~
this 关键字是 JavaScript 最复杂的机制之一,对学习 web 前端而言,this 的学习至关重要。
总的来说,this 是在执行时进行绑定的,并不是在定义时绑定,它的上下文取决于函数调用时的各种条件。下面,我来介绍下 JavaScript 中的4种常见绑定规则。
1. 默认绑定
var a = "global";
function foo() {
var a = "foo";
console.log(this.a);
}
foo(); //global
即函数在全局环境调用执行时,this 就代表全局对象 Global(非严格模式下)
var a = "global";
function foo() {
"use strict";
var a = "foo";
console.log(this.a);
}
foo(); //TypeError: Cannot read property 'a' of undefined
如果使用严格模式(strict mode),this 会绑定到 undefined。
2. 隐式绑定
var a = "global";
var obj = {
a: "obj",
foo: function() {
console.log(this.a);
}
}
obj.foo(); //obj
函数作为某个对象的方法(method
)调用时,this 绑定到上级对象。(如果是多重对象的调用,this 也还是绑定在上一级对象上,例如 obj2.obj.foo()
,这样调用,this 绑定在 obj 上)
隐式丢失
var a = "global";
var obj = {
a: "obj",
foo: function() {
function foo1() {
console.log(this.a);
}
foo1();
}
}
obj.foo(); //global
这里的函数调用比上面的程序多了一层函数的嵌套,绑定的 this 就发生了变化,变成了 winodw 全局对象(非严格模式下)。
产生这个情况的原因,这里附上犀牛书上的解释(第6版 171页)
和变量不同,关键字 this 没有作用域的限制,嵌套的函数不会从调用它的函数中继承 this。如果嵌套函数作为方法(
method
)调用,其 this 的值指向调用它的对象。如果嵌套函数作为函数(function
)调用,其 this 值不是全局对象(非严格模式下)就是 undefined (严格模式下)。
最常用的方法就是加一行 var self = this;
,
var a = "global";
var obj = {
a: "obj",
foo: function() {
var self = this;
function foo1() {
console.log(self.a);
}
foo1();
}
}
obj.foo(); //obj
或者借助 es6 中的箭头函数
var a = "global";
var obj = {
a: "obj",
foo: function() {
var foo1 = () => {
console.log(self.a);
}
foo1();
}
}
obj.foo(); //obj
3. 显示绑定
var a = "global";
var obj = {
a: "obj",
foo: function() {
console.log(this.a);
}
}
var obj2 = {a: "obj2"};
obj.foo.apply(obj2); //obj2
obj.foo.call(obj2); //obj2
obj.foo.bind(obj2)(); //obj2
使用 apply()
、call()
、bind()
改变函数的调用对象,它的第一个参数就表示改变后的调用这个函数的对象。(程序中 foo 中的 this 被绑定在 obj2 上了!)
注: apply()、call()、bind() 的参数为空时,默认绑定全局对象。
4. new 绑定
var x = "global!";
function obj(){
this.x = "obj!";
}
var o = new obj();
console.log(o.x); //global!
在 JavaScript 中,构造函数只是一些使用 new 操作符时被调用的函数,函数通过 new 调用后,若函数没有返回其他函数,那么自动返回一个新对象,this 绑定在这个新对象上。
使用 new 调用函数,会自动执行下面的操作:
- 创建一个全新的对象。
- 这个新对象会被执行 [[prototype]] 连接。
- 这个新对象会被绑定到函数调用的 this。
- 如果函数没有返回其他对象,那么 new 表达式中的函数调用会自动返回这个新对象。
一般来说,this 绑定的优先级: new > 显示绑定 > 隐式绑定 > 默认绑定。