思维导图
通过下面的思维导图,我们先对JavaScript的this关键字有一些基本的了解。
函数的“this”
我们在对象内部,想要访问对象的属性,就会需要用到this。
当然我们也可以直接使用对象变量名,但是变量名可以被重新赋值,直接使用变量名总是不保险的,而且也不方便阅读。
代码语言:javascript复制let user = {
name: "John",
age: 30,
sayHi() {
// "this" 指的是“当前的对象”
alert(this.name);
// alert(user.name);
}
};
user.sayHi();
“this”指向调用方法的对象
JS的“this”有更高的灵活性。
我们知道JS的函数,也可以作为对象的属性,一个函数同时可以被赋值给多个对象。
这个时候,函数的this,是指向调用方法的对象。
代码语言:javascript复制let user = { name: "John" };
let admin = { name: "Admin" };
function sayHi() {
alert( this.name );
}
// 在两个对象中使用相同的函数
user.f = sayHi;
admin.f = sayHi;
// 这两个调用有不同的 this 值
// 函数内部的 "this" 是“点符号前面”的那个对象
user.f(); // John(this == user)
admin.f(); // Admin(this == admin)
“this”绑定的规则
凭经验去判断this
的指向,不太容易,我们可以总结出下面四条绑定规则,用来判断this
的指向。
默认绑定
非严格模式下,没有对象时,this会是全局对象(比如浏览器中的window),这就是默认绑定。
代码语言:javascript复制function sayHi(){
console.log("Hi", this);
}
sayHi(); // Hi Window
严格模式下,没有对象时,this是undefined。
代码语言:javascript复制'use strict';
function sayHi(){
console.log("Hi", this);
}
sayHi(); // Hi undefined
隐式绑定
调用对象的方法时,进行隐式绑定,this
指向它的调用者。
这是我们最常见也最容易理解的绑定规则。
代码语言:javascript复制let user = {
name: "John",
age: 30,
sayHi() {
// "this" 指的是“当前的对象”
alert(this.name);
// alert(user.name);
}
};
user.sayHi();
硬绑定
与隐式绑定相对,我们显式得指定this
的对象。
这里我们用到call
、apply
、bind
。
let obj1 = {
name: 'obj1',
sayHi() {
// "this" 指的是“当前的对象”
console.log(this.name);
}
};
let obj2 = {
name: 'obj2'
}
let obj3 = {
name: 'obj3'
}
var tmp = obj1.sayHi.bind(obj2)
tmp() // => 'obj2'
obj1.sayHi.call(obj3) // => 'obj3'
构造函数绑定
New绑定,构造函数的this
指向对象实例。
function Person(){
console.log('Hi', this);
}
let person = new Person(); // => Hi Person {}
规则优先级
先说结论:显式 or new > 隐式 > 默认。
不存在同时使用显示绑定和new绑定的操作。
参考显示绑定时候的例子,可以验证下这个优先级。
代码语言:javascript复制let obj1 = {
name: 'obj1',
sayHi() {
// "this" 指的是“当前的对象”
console.log(this.name);
}
};
let obj2 = {
name: 'obj2'
}
let obj3 = {
name: 'obj3'
}
var tmp = obj1.sayHi.bind(obj2)
tmp() // => 'obj2'
obj1.sayHi.call(obj3) // => 'obj3'
箭头函数没有this
箭头函数的this
,直接指向外层函数的this
。
所以箭头函数也不能用做构造函数。
代码语言:javascript复制let user = {
firstName: "Ilya",
sayHi() {
let arrow = () => alert(this.firstName);
arrow();
}
};
user.sayHi(); // Ilya