一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第25天,点击查看活动详情。
前端开发的第三年,突然发现,对于JS,我还有很多不懂的地方,趁着最近需求少,不如静下心来,从头把JS再学一遍,查漏补缺。
本系列以廖雪峰的《JavaScript教程》和《现代 JavaScript 教程》两个电子书作为线索,对其中需要进一步了解的知识,会阅读更多的文章,并作为扩展知识记录下来。
新手建议先阅读上面两个电子书,本系列更适合用来复习旧知识和查漏补缺。
思维导图
通过下面的思维导图,我们先对JavaScript的this关键字有一些基本的了解。
函数的“this”
我们在对象内部,想要访问对象的属性,就会需要用到this。
当然我们也可以直接使用对象变量名,但是变量名可以被重新赋值,直接使用变量名总是不保险的,而且也不方便阅读。
let user = {
name: "John",
age: 30,
sayHi() {
// "this" 指的是“当前的对象”
alert(this.name);
// alert(user.name);
}
};
user.sayHi();
“this”指向调用方法的对象
JS的“this”有更高的灵活性。
我们知道JS的函数,也可以作为对象的属性,一个函数同时可以被赋值给多个对象。
这个时候,函数的this,是指向调用方法的对象。
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),这就是默认绑定。
function sayHi(){
console.log("Hi", this);
}
sayHi(); // Hi Window
严格模式下,没有对象时,this是undefined。
'use strict';
function sayHi(){
console.log("Hi", this);
}
sayHi(); // Hi undefined
隐式绑定
调用对象的方法时,进行隐式绑定,this指向它的调用者。
这是我们最常见也最容易理解的绑定规则。
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绑定的操作。
参考显示绑定时候的例子,可以验证下这个优先级。
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。
所以箭头函数也不能用做构造函数。
let user = {
firstName: "Ilya",
sayHi() {
let arrow = () => alert(this.firstName);
arrow();
}
};
user.sayHi(); // Ilya