一、this指向的5种情况
this,函数的执行主体(不等价于执行上下文),取决于谁把这个函数执行的。大体上把this执行主体分为一下5类。
- 事件绑定中的 this
- 普通函数执行中的 this
- 箭头函数执行中的 this
- 构造函数中的 this
- 基于 call/apply/bind 强制改变中的 this
二、事件绑定中的this
给dom元素的某个事件行为绑定方法,当时间触发方法执行,方法中的this就是当前dom元素本身。
document.body.onclick = function () {
console.log(this)
}
document.body.addEventListener('click', function () {
console.log(this)
})
注:IE6-IE8中基于attachEvent实现事件绑定,事件触发方法执行时,方法中的this不在元素本身,一般情况下都是指向window
/* document.body.attachEvent('onclick', function () {
console.log(window)
console.log(this)
}) */
三、普通函数执行中的this
1、函数执行,看函数前是否有“点”,有“点”,“点”前面是谁,this就指向谁,如果没有“点”,this就指向window(js严格模式下是undefined)
function fn(){
console.log(this);
}
fn(); //window
let obj={
fn:function(){
console.log(this);
},
fn1:{
fn2:function(){
console.log(this);
}
}
}
obj.fn(); //obj
obj.fn1.fn2(); //obj.fn1
闭包中的this 一般都指向window
let obj={
fn:function(){
return function(){
console.log(this);
}
}
}
obj.fn()();
2、自执行函数执行,其内的 this 一般都是window,严格模式下为undefined
3、回调函数中的this为window或者undefined,除非做过特殊处理(如:数组的forEach方法·)
[1,2,3].forEach(function(){
console.log(this); //window
});
//forEach对内部this进行处理
[1,2,3].forEach(function(){
console.log(this); //{a:10}
},{a:10})
四、箭头函数中的this
箭头函数中没有自己的this,所用到的this都是上下文中的this
箭头函数可以保留this的指向,因为它本身没有。
let obj = {
n: 1000,
fn() {
setTimeout(function () {
// this ==> window
console.log(this)
}, 500)
setTimeout(() => {
// this 所处上下文中的this => obj
console.log(this)
}, 1000);
}
}
obj.fn()
五、基于 call/apply/bind 强制改变中的 this
call/apply/bind 都可以强制改变this的指向
1、call和apply 都是立即执行函数,并且改变函数中的this,再并且给函数传递参数
- call执行的函数,如果有参数,则以“,”方式一个个去添加
- apply执行的函数,如果有参数,则以数组的方式来传递
function fn(a,b){
console.log(this);
return a+b;
}
fn(1,2);
var o={a:100};
fn.call(o,1,2); //call
fn.apply(o,[1,2]); //apply
注意:在非严格模式下,第一个参数不传入或传入null或传入undefined,this都改变为window;严格模式下,不传是undefined,否则传入谁,this就改为谁
call和apply方法执行步骤(原理)
- 先给参数1添加一个属性并且让这个属性值赋值为 fn
- 执行自定义属性方法
- 删除刚添加的自定义属性方法
2、bind并不会把函数立即执行,它是预先处理函数中的this和参数的
bind绑定的函数有参数,和call中的参数传递一样
bind方法在react中大量使用
var obj = {
id: 1,
name: '张三'
}
function fn(a, b) {
console.log(this, a, b)
}
document.querySelector('#box').onclick = fn.bind(obj,1,2)