关于this指向问题一直是js基础的热门问题,最近参与公司面试问过很多面试者总觉得有点模糊。所以自己想着总结一下:
this的指向在函数定义的时候是确定不了的,只有在函数执行的时候,指向调用它的对象。
一、全局环境
在全局环境中,this都是指向全局对象window。
console.log(this); //window
二、函数环境
1、普通函数
普通函数调用是window的调用,this 指向window。
function fn(){
console.log(this);//window ,严格模式返回undefined
}
fn(); // window.fn(),window可以省略
示例:
let a = 'aa';
fuunction fn(){
console.log(this.a); //undefined
}
fn();
var a = 'aa';
fuunction fn(){
console.log(this.a); //'aa'
}
fn();
let定义的是局部变量,var定义的是全局变量。
2、构造函数
当函数作为构造函数时,它的 this 会被绑定到实例上。
function fn(){
console.log(this); // this指向func
}
let func = new fn();
示例:
function fn(){
this.a = 'aa';
}
let func = new fn()
console.log(func.a); //'aa'
3、对象调用
那个对象调用 this 就指向那个对象。
let obj = {
fn:function(){
console.log(this); //obj
}
}
obj.fn();
示例:
let obj = {
a:'aa',
fn:function(){
return this.a;
}
}
console.log(obj.fn);//'aa'
4、箭头函数
箭头函数里面,没有 this;this 继承外面的环境。
let fn = (()=>{console.log(this)});//window
示例:
let obj={
a:222,
fn:function(){
setTimeout(()=>{console.log(this.a)});
}
};
obj.fn();//222
箭头函数的外部环境是fn,fn是obj调用的,this指向obj
5、定时器 / 计时器
this 指向window
setInterval(function(){
console.log(this); //window
},1000)
示例:
var a = 111
let obj={
a:222,
fn:function(){
setTimeout(function(){console.log(this.a)});
}
};
obj.fn();//111
6、匿名函数
this指向 window
(function(){
console.log(this);//window
})()
三、DOM事件和内联事件
1、DOM事件
当函数被当做监听事件处理函数时, 其 this 指向触发该事件的元素 (针对于addEventListener事件)
function fn(){
console.log(this); //指向btn
}
let btn = document.getElementById('btn');
btn.addEventListener('click',fn,false);
2、内联事件
内联事件中的this指向分两种情况:
①、当代码被内联处理函数调用时,它的this指向监听器所在的DOM元素
②、当代码被包括在函数内部执行时,其this指向等同于 函数直接调用的情况,即在非严格模式指向全局对象window, 在严格模式指向undefined
<button onclick="console.log(this)"></button> //当前DOM
<button onclick="(function(){console.log(this)})"></button> // window
四、改变this指向(call / apply)
call 和 apply 的作用,完全一样,唯一的区别就是在参数上面。
1、call 接收的参数不固定,第一个参数是函数体内 this 的指向,第二个参数以下是依次传入的参数。
2、apply接收两个参数,第一个参数也是函数体内 this 的指向。第二个参数是一个集合对象(数组或者类数组)
let fn = function(a,b,c){
console.log(a,b,c)
}
let arr =[1,2,3]
fn.call(window,arr) => [1,2,3] undefined undefined
fn.apply(window,arr) => 1,2,3
let obj1={
a:222
};
let obj2={
a:111,
fn:function(){
alert(this.a);
}
}
obj2.fn.call(obj1) =>222
虽然调用的是obj2,但是call把this指向了obj1,所以obj2.fn的执行环境是obj1