原文链接: 掘金-this、apply、call、bind
this永远指向最后调用它的那个对象
Demo1:
var name = "windowName";
function a(){
var name = "innerName";
console.log(this.name); // 在非严格模式下(浏览器环境下)结果为windowName,在严格模式下(Node环境下)结果为undefined
console.log(this); // 在非严格模式下(浏览器环境下)结果为window对象,在严格模式下(Node环境下)报错
}
a();
console.log(this.name); // 在非严格模式下(浏览器环境下)结果为windowName,在严格模式下(Node环境下)结果为{}
Demo2:
var name = "windowName";
var obj = {
name: 'innerName',
fn: function () {
console.log(this.name); // 在非严格和严格模式下结果都是innerName
}
}
obj.fn(); // 注: 这次调用函数的是obj对象
// 补充一点,假如把obj中的name换成name1:
var obj1 = {
name: 'innerName',
fn: function () {
console.log(this.name); //结果就是undefined
}
}
Demo3: 调用时将obj换成window.obj, 由于最后调用的对象依然是obj,所以打印的结果仍然是innerName
Demo4:
// 把obj中的name注释掉
var name = "windowName";
var obj = {
// name: 'innerName',
fn: function () {
console.log(this.name); // undefined
}
}
obj.fn();
fn的最后一个调用对象是obj,而obj中此时并没有name属性,也不会向上一个对象中查找,所以输出结果为undefined
Demo5:
var name = "windowName";
var obj = {
name: null,
fn: function () {
console.log(this.name); // 非严格模式下结果为windowName
}
}
var f = obj.fn;
f();
本例中最关键的一处在于obj.fn的指向给了f,所以此时调用fn函数的对象并不是obj,而是window,所以输出结果为windowName
Demo6:
var name = "windowName";
function fn(){
var name = "innerName";
function innerFn(){
console.log(this.name); // windowName
}
innerFn();
}
fn();
我们会以为innerFn在fn里面调用this会指向fn, 但是最先执行的函数fn它的指向对象是window,所以innerFn中this的指向也是window,所以打印结果为innerName
思考下面的代码:
var name = "windowName";
var obj = {
name: "innerName",
func1: function(){
console.log(this.name);
},
func2: function(){
setTimeout(function(){
this.func1();
},100)
}
}
obj.func2();
解释: 虽然func2的调用对象是obj没错,但是func2中的setTimeout函数的调用对象其实是window对象,this指向的也就是window对象。 window对象中并没有func1函数,所以就报错了。。
2.1 箭头函数改造
箭头函数谨记: 箭头函数的this始终指向函数定义时的this,而非函数执行时。箭头函数中没有this绑定,必须通过查找作用域链来决定其值。如果箭头函数被非箭头函数包含,this绑定的时最近一层非箭头函数的this,否则this为undefined
改造后的代码:
var name = "windowName";
var obj = {
name: "innerName",
func1: function(){
console.log(this.name);
},
func2: function(){
setTimeout( ()=> {
this.fun1(); // innerName
},100)
}
}
obj.func2();
2.2 使用var that = this;保存this指向
var name = "windowName";
var obj = {
name: "innerName",
func1: function(){
console.log(this.name);
},
func2: function(){
var that = this;
setTimeout(function(){
that.fun1(); // innerName
},100)
}
}
obj.func2();
func2中this的指向时调用func2方法的obj, 在调用setTimeout函数之前,我们先将this赋值给that,那么that就指向了obj,在setTimeout函数中that也是指向obj。
2.3 使用apply、call、bind修改this指向
2.3.1 使用apply 原先setTimeout函数中的this是指向window,我们需要将其指向obj,在其函数后面使用.apply(obj)即可改变this指向
2.3.2 call 和 bind 用法与上面相同。
面试考点1: apply和call有什么区别
答: apply和call的区别仅在与传递参数的不同,除绑定对象外,apply传递的是一个数组,而call传递的是参数列表。
例:
var name = "windowName";
var obj = {
name: 'innerName',
fn: function(a,b){
console.log(this.name);
console.log(a+b);
}
}
var a = obj.fn;
a.apply(obj,[1,2]) // apply写法
a.call(obj,1,2) // call写法
面试考点2: apply,call和bind有什么区别?
调用bind时,会创建一个新的函数,必须要我们手动执行
new 的过程: