this绑定分为4种情况
1. 默认绑定 (独立调用)
2. 隐式绑定 (某个对象发起的函数调用)
3. 显示绑定 (call apply bind)
4. new操作符绑定(new 构造函数)
this分析
一、 默认绑定
javascript内置API的回调函数的this指向,取决于API内部实现时对回调的调用方式
例题:
1. setTimeout
// setTimeout的回调中的this是 window
setTimeout(function () {
console.log(this, "this1"); //浏览器中this是window,node环境是Timeout对象,
}, 1000)
setTimeout(() => {
console.log(this, "this2");// window
}, 1000)
2. forEach
//forEach的回调如果是非箭头函数,this可以被改变
const arr = [1, 2, 3, 4, 5]
const obj = {
name: 'nihao'
};
arr.forEach((item, idx) => {
console.log(this, "this"); //回调是箭头函数,this是window
})
arr.forEach(function (item, idx) {
console.log(this, "this2"); //回调不是箭头函数,this可以被改变,this是obj对象
}, obj)
二、隐式绑定
const object = {
name: 'dk',
sayName1() {
return this.name
},
sayName2: () => {
return this.name
}
};
console.log(object.sayName1(), "obj1")
console.log(object.sayName2(), "obj2")
分析:
1. 通过使用 对象.函数() 的调用方式,sayName1的this被隐式绑定为了object对象
2. 箭头函数的this是定义箭头函数时的外部的作用域的this,与调用对象(object)无关。
打印:
dk obj1
undefined obj2 //sayName2函数是箭头函数,sayName2所处的外部作用域是全局作用域GO
三、显式绑定
显示绑定通过call、apply、bind改变this
例题:
var obj1 = {
a: 1
}
var obj2 = {
a: 2,
bar: function () {
console.log(this.a)
},
foo: function () {
setTimeout(function () {
console.log(this)
console.log(this.a)
}.call(obj1), 0)
}
}
var a = 3
obj2.bar()
obj2.foo()
打印:
2
{a: 1}
1
四、new操作符绑定this
例题:
function Foo() {
getName = function () { console.log(1); }; //不定义直接赋值,会将getName方法放在window上。如果想放在Foo实例的属性上,需要使用this.getName定义。
return this;
}
Foo.getName = function () { console.log(2); };
Foo.prototype.getName = function () { console.log(3); };
var getName = function () { console.log(4); }; //执行时getName赋值为这个函数
function getName() { console.log(5) }; //函数声明提升, 并优先级高于const getName这个
Foo.getName(); //第1行
getName(); //第2行
Foo().getName(); //第3行
getName(); //第4行
new Foo.getName();//第5行
new Foo().getName(); //第6行
new new Foo().getName(); //第7行
备注:
变量的getName声明和函数的声明getName会提升,函数的优先级>变量的优先级,getName会被声明为函数
执行代码时,getName被赋值为了打印4的函数,所以此时window上的getName是打印4的函数
执行顺序:new Foo() > Foo() > new Foo
分析:
执行第一行,Foo.getName(),打印2
执行第二行,getName() ,即执行window.getName() 打印4
执行第三行,Foo().getName(),先执行Foo(),window上的getName被赋值为打印1的函数,返回window对象,再执行window.getName() 打印1
执行第4行,getName(),执行window.getName,打印1
执行第5行,new Foo.getName(),调用Foo.getName打印2,返回Foo.getName类型的对象
执行第6行,new Foo().getName(),执行new Foo()返回Foo实例,调用实例上的getName,打印3
执行第7行,new new Foo().getName(),执行new Foo()返回Foo实例,再执行实例.getName()的,打印3
打印结果:
2
4
1
1
2
3
3