重新整理this指向
好久没有复习this的问题,最近发现又忘记了,需要好好整理一下!
标准函数与箭头函数的不同this行为
this引用的是把函数当成方法调用的上下文对象,指向哪个对象或者这个对象的值是什么取决于使用的方式与环境。在网页的全局上下文中调用函数时,this指向windows
标准函数的this情况
- 直接调用,this指向windows;
- 对象调用,this指向把函数当成方法调用的对象本身;
箭头函数的this情况
在箭头函数中,this引用的是定义箭头函数的上下文:
- 创建箭头函数时,就已经确定了this指向,不会再改变!!!;
- 箭头函数内的this指向外层的this
梳理
1.全局普通函数
注意区分严格模式or非严格模式
let a = 0; // 相当于window.a = 0
function testWindow() {
this.a = 1; //window.a = 1
console.log(this.a); //this指向window,1
console.log(window.a); //1
console.log(this); //window
}
testWindow();
2.对象的函数方法
this指向把函数当成方法去调用的对象
let a=2
let obj = {
a:1,
b:function(){
console.log(this)
console.log(this.a)
}
}
obj.b() //this指向obj
let foo = obj.b
foo() //普通调用,this指向window
3.构造函数,即new
function Test(a) {
this.a = a;
console.log(this.a);
}
Test.prototype.say = function () {
console.log(this);
console.log(this.a);
};
var t = new Test(1);//this指向t
console.log(t); //{a:1}
t.say();//this指向t
4.箭头函数
箭头函数的this看外层是否有函数,如果有函数,外层函数的this即是内部箭头函数的this;如果没有,this便是window 箭头函数的 this 是在创建它时外层 this 的指向。这里的重点有两个:
- 创建箭头函数时,就已经确定了它的 this 指向。
- 箭头函数内的 this 指向外层的 this。
- 所以要知道箭头函数的 this 就得先知道外层 this 的指向,需要继续在外层应用七步口诀。
obj = {
func() {
const arrowFunc = () => {
console.log(this._name)
}
return arrowFunc
},
_name: "obj",
}
obj.func()()//箭头函数外部有函数,则箭头函数的this为外层函数的this;外层函数的this为obj(对象调用)
func = obj.func
func()()//箭头函数外部有函数,则箭头函数的this为外层函数的this,外层函数直接调用,this为window
5.箭头函数与new
function Person(name, age) {
this.name = name;
this.age = age;
this.test1 = function () {
const arrowFunc = () => {
console.log(this.name);
console.log(this.age);
};
arrowFunc();
};
this.test2 = () => {
console.log(this.name);
console.log(this.age);
};
}
let per1 = new Person("test1", 23);
console.log(per1.test1);
per1.test1(); //test里的this指向per1,箭头函数外部有函数test,因此箭头函数的this为test的this,即为per1.因此输出为test1,23
per1.test2(); //test2箭头函数外部有函数为Person,this指向per1,因此结果同上
let test3 = per1.test1;
test3(); //test3为普通调用,arrowFunc里的this为为test3的this即为window,因此为undefined
let test4 = per1.test2; //箭头函数的this,定义了之后就不会改变
test4(); //
let test5 = () => {
console.log(this.name);
console.log(this.age);
};
test5(); //undefined
注意test4与test5的区别
6.call、bind、apply
bind()
是指Function.prototype.bind()
:[Function
] 实例的 bind()
方法创建一个新函数,当调用该新函数时,它会调用原始函数并将其 this
关键字设置为给定的值,同时,还可以传入一系列指定的参数,这些参数会插入到调用新函数时传入的参数的前面。
- 多次bind时只认第一次bind值;
- 箭头函数中的this不会被改变
apply()
和 call()
的第一个参数都是 this,区别在于通过 apply 调用时实参是放到数组中的,而通过 call 调用时实参是逗号分隔的。
bind的优先级最高,即经过bind绑定新的对象后,通过call与apply都无法再进行改变
function func() {
console.log(this)
}
boundFunc = func.bind(1)
boundFunc.apply(2) // 1,口诀 3 优先
总结
- 箭头函数优先级最高;
- new
- 隐式绑定:bind>call===apply
- 对象调用
- 直接调用
obj = {
func() {
const arrowFunc = () => {
console.log(this._name)
}
return arrowFunc
},
_name: "obj",
}
obj.func()()
func = obj.func
func()()
obj.func.bind({ _name: "newObj" })()()
obj.func.bind()()()
obj.func.bind({ _name: "bindObj" }).apply({ _name: "applyObj" })()
- obj.func()返回箭头函数,箭头函数的this与外部函数的this一致,this指向obj,因此运行obj.func()()结果为obj._name:'obj';
- 箭头函数外部有函数func,this指向window,输出undefined;
- obj.func()中的this指向新的对象,箭头函数的this与外部函数this一致,为新bind的对象,即为“newObj”;
- bind参数为null,即为window,
- bind后的对象不能进行修改,因此结果为bindObj