this的确定很多是取决于它的执行环境和它是如何执行的、但也有特例。
!!!!以下我们都从非严格模式下的出发判断的!!!! 首先非严格模式下的this不会是undefined和null,是window。 严格模式下this则会出现这两个值。 在严格模式下的undefined和null 在非严格模式下指向window。
首先让我们从箭头函数看起
一、箭头函数
我们常说箭头函数中没有this 他的this取决于它被创建时,它所处的环境中的this。这么说虽然有些宽泛但还是正确的。
让我们看一段代码
let func = ()=>{
console.log(this)
}
let obj = {
a:function(){
console.log(this) //{a:f}
func()
}
}
obj.a()//window
从这段代码,我们可以看出箭头函数的func中的this 在创建时就已经确定了。
所以在我们发现是箭头函数时候 只需要找到它的声明环境就可以啦
二、通过 “对象.” 访问时候
这里要注意 只要是通过 “对象.” 访问的函数它的this就指向这个对象。
let obj = {
a:function(){
console.log(this) //{a:f}
}
}
obj.a() //{a:f}
其实这么说还是不太严谨 、我猜大家也会想如果对象中的方法是一个箭头函数呢?
let obj = {
a:()=>{
console.log(this) //window
}
}
obj.a() //window
通过上面这段代码我们可以看出这样的话this的指向 取决于 箭头函数,而不再取决于 “对象.”
因此我们确定箭头函数的优先据是最高的,因此下方提及的都不包含箭头函数
让我能给我们再看一段代码
function func() {
console.log(this);
}
let obj = {
name: "123",
};
obj.a = func;
obj.a(); //{name: '123', a: ƒ}
---------------------------
let func = () => {
console.log(this);
};
let obj = {
name: "123",
};
obj.a = func;
obj.a(); //window
上方的两段代码 也都符合之前说的规则。所以我们的判断是没错的。 综合我们也可以看出一(箭头函数)的优先级要高于二(对象.)
三、函数的直接调用
直接调用函数的其this指向window。
function func() {
console.log(this);
}
func()//window
我们看两个特别的情况 (以下情况也属于函数的直接调用)
let obj ={
a:function(){
console.log(this) //{a: ƒ}
function fun(){
console.log(this)//window
}
fun()
}
}
obj.a()
let obj = {
a:function(){
console.log(this)
}
}
obj.a() //obj
let fun = obj.a;
fun()//window
四、new
当我们用new来调用构造函数时候、构造函数中的this就一定指向这个新创建的对象。
function func() {
this.name = "aaa";
this.func = function () {
console.log(this)
};
}
let p = new func();
p.func()//func {name: 'aaa', func: ƒ}
console.log(p.name);//aaa
注意:箭头函数不可以用new关键字调用
const func = () => {
this.name = "aaa";
this.func = function () {
console.log(this);
};
};
let p = new func();
//Uncaught TypeError: func is not a constructor
五、bind、apply、call
先让我们温习一下这三个的基本知识
- 它们三个都可以用来改变方法的中this的指向。
call、apply和bind的区别
- call 和 apply都会自动的调用方法,而 bind 只会修改this指向但不会自动调用方法。
- call 、 bind 传参数直接跟在this后依次写,而apply则需要以数组形式传参。
//bind
function func () {
console.log(this)
};
let a = 1,b = 2;
func.bind(a)() //Number {1}
func.bind(a).bind(b)();////Number {1}
//我们可以看出多次bind 只会响应第一次bind的this
------------------------------
//apply
func.apply(a) //Number {1}
func.apply(a).apply(b);//Number {1} Uncaught TypeError: Cannot read properties of undefined (reading 'apply')
------------------------------
//call
func.call(a) //Number {1}
func.call(a).call(b);//Number {1} Uncaught TypeError: Cannot read properties of undefined (reading 'call')
由上可看出只有 bind可以多次bind 并且其只响应第一次的。
接下来让我们对比一下 bind和apply、call的优先级
function func() {
console.log(this);
}
let a = 1,
b = 2;
func.bind(a).apply(b);//Number {1}
func.bind(b).call(a)//Number {2}
我们可以看出 bind要优先级高于apply 和 call
六、全局下的this指向window 这里不在赘述啦!!!
最后最后让我们总结一下规律:
箭头函数、new、bind、apply 和 call、对象.(obj.)、直接调用。 从高到低依次确定this的指向。