this绑定规则
原则:谁调用了这个函数,那么this就会指向谁
默认绑定
默认绑定下,this会指向window对象(可以看作默认是由window对象调用了这个函数
var c = 3;
(function () {
var c = 2;
console.log(this.c) //3
})()
隐式绑定
如果是一个对象调用一个方法,那么this隐式绑定到这个对象上(对象调用了函数
var a = 2;
const obj = {
a: "1",
sayHi: function() {
console.log(this.a); //1
}
}
obj.sayHi();
硬绑定(call,bind,apply)
硬性绑定会直接改变默认的this指向,将this指向传入的对象,如以下代码
function fn1() {
console.log(this); //window
}
//默认this指向window对象
fn1();
//使用了call,将this硬性绑定到{x : 100}这个对象上, 并立即执行fn1()
fn1.call({ x: 100 }); //{x : 100}
//使用bind,同理将this硬性绑定到{y : 2000}这个对象上
const fn2 = fn1.bind({ y: 2000 });
fn2(); //{y : 2000}
构造函数绑定
this默认指向这个构造函数
function Lover(name) {
this.name = name;
this.sayName = function () {
console.log(`lover is ${this.name}`);
}
}
var name = "1";
var x = new Lover("2")
x.sayName(); //2
用class的写法同理
class People {
constructor(name) {
this.name = name
}
sayName() {
console.log(this.name)
}
}
var name = 1;
const x = new People("2")
x.sayName(); //2
再来巩固一下,看看以下三个都分别打印了什么?
var name = '人'
function special() {
console.log(this.name)
}
var girl = {
name: '女人',
detal: function () {
console.log(this.name)
},
woman: {
name: '小花',
detal: function () {
console.log(this.name)
}
},
special: special
}
girl.detal();
girl.woman.detal();
girl.special();
分析:
- girl.detal()显然是触发的隐式绑定的规则,所以this指向的是girl,打印“女人”
- girl.woman.detal()也触发了隐式绑定,但这次函数的调用者是woman对象,所以this指向的woman,打印“小花“
- gril.special()同理,还是隐式绑定,this指向的girl对象,打印"女人"
特殊情况
- 箭头函数中的this与上一级的this指向相同
var a = 2;
const obj = {
a: "1",
sayHi: () => {
console.log(this.a); //2
}
}
obj.sayHi();
由于箭头函数没有自己的的this,所以this会指向上一级,也就是window,所以会打印2
- 箭头函数不能通过call,bind强制绑定this的指向,这个道理和上面一样,箭头函数都没有自己的this,怎么改变绑定?就像下面代码一样
var name = 1;
const obj = {
name: '2',
sayName: () => {
console.log(this.name);
}
}
obj.sayName.call({name: 3}); //打印1
- setTimeout() 和 setInterval()
实际上这个也好理解,因为是window.setTimeout(fn, xxx), 所以在fn里面的this默认会指向window,比如如下代码
var name = 1;
const obj = {
name: '2',
sayName: function(){
setTimeout( function(){
console.log(this.name)
}, 0)
}
}
obj.sayName(); //打印1
再举个例子
var name = 1;
const obj = {
name: '2',
sayName: function(){
setTimeout( ()=>{
console.log(this.name)
}, 0)
}
}
obj.sayName(); //打印2
这里把setTimeout里面的改成箭头函数,则默认this会指向上一层的this指向,也就是obj,所以会打印2