有史以来最全的this指南

作为一个front-end engineer,我们时不时的会遭遇this的伏击,今天就让我们掀开this的神秘面纱吧

一、全局执行

console.log(this) // Window

可以看到,全局作用域中的this指向的是当前全局对象Window。

二、函数中执行

1.非严格模式下:

function func(){
    console.log(this) // Window
}
func();

在非严格模式下,this指向Window

2.严格模式下:

'use strict'

function func(){
    console.log(this)  //undefined
}

func();

三、作为对象的的方法调用

var obj = {
    name:'123',
    func:function(){
        console.log(this.name) // '123'
    }
}
obj.func();

当一个函数被当作一个对象的方法调用的时候,this指向当前的对象obj

---

var obj = {
    name:'222',
    func:function(){
        console.log(this) // Window
    }
}

var t = obj.func;
t();

如果把对象的方法赋值给一个变量,调用该方法时,this指向Window。(我的理解为:t是全局变量,t = window.t,this遵循谁调用,就指向谁的原则,故而指向了Window)。

四、作为一个构造函数使用

1.在js中,为了实现类,我们需要定义一些构造函数,在调用一个构造函数的时候加上new这个关键字:

function Person(name){
	this.name = name;
	console.log(this); // Person
}
var p1 = new Person('lee');

此时,this指向这个构造函数调用的时候实例化出来的对象。

当然,构造函数其实也是一个函数,若将构造函数当作普通函数来调用,this指向Window:

function Person(name) {
    this.name = name;
    console.log(this); //Window
}

var p2 = Person('GG');

五、在定时器中使用

setInterval(function(){
    console.log(this);
},2000)
setTimeout(function(){
    console.log(this)
},0)

如果没有特殊的指向,setInterval和setTimeOut的回调函数中this的指向都是Window。这是因为JS的定时器方法是定义在Window下的。

六、箭头函数
 

var func = () => {
    console.log(this) // window
}    
var obj = {
    name:'123',
    fun:function(){
        console.log(this) 
    }
}
obj.fun() // obj

普通函数作为对象的一个函数被调用,this指向obj,箭头函数作为对象的一个函数被调用,this指向Window.

关于箭头函数中的this指向:

var obj = {
    name:'kk',
    func:function(){
        settimeout(function(){
            console.log(this)
        })
    }
}

obj.func() //window
var obj = {
    name:'hh',
    func:function(){
        setTimeout(()=>{
            console.log(this)
        },0)
    }
}
obj.func() //obj

若在对象的函数中,普通函数作为定时器延时执行的函数调用,this 指向 Window;箭头函数作为定时器延时执行的函数调用, this 指向定义时所在的对象,也就是 func 中的 this,即 obj。

箭头函数中 this 的值取决于该函数外部非箭头函数的 this 的值,且不能通过 call() 、 apply() 和 bind() 方法来改变 this 的值。

七、call  apply bind

call:

fun.call(this,arg)

它会立即执行函数,第一个参数是指定执行函数中this的上下文,后面的参数是执行函数需要传入的参数。

apply

fun.apply(this,[])

它也会立即执行函数,第一个参数是指定执行函数中this的上下文,第二个参数是一个数组,是传给执行函数的参数。

bind

function.bind(thisArg[, arg1[, arg2[, ...]]])

它不会执行函数,而是返回一个新的函数,这个新的函数被指定了 this 的上下文,后面的参数是执行函数需要传入的参数。

示例:

function Person(name,age){
    			this.name = name;
			this.age = age;
			console.log(this);
		}
		var obj = {
			name:'kk',
			age:6
		}
		Person.call(obj,'mm',10);
		// obj,{name:'mm',10};
		Person.apply(obj,['mm',10]);
		// obj,{name:'mm',10};
		var p1 = Person.bind(obj,'mm',10)
		var p2 = new p1();
		//Person {name:'mm',age:10}

在此例中,this都指向了obj,都正常运行,call、apply会立即执行,call和apply的区别在于参数的传递。call接受多个参数,apply参数只接受一个数组;bind不是立即执行函数,它返回一个函数,需要执行p2才能返回结果,bind接收多个参数列表。

 

如何改变this的指向

1.使用es6的箭头函数

       var name = 'hh';
		var obj = {
			name:'kk',
			func1:function(){
				console.log(this.name)
			},
			func2:function(){
				setTimeout(function(){
					this.func1();
				},1000)
			}
		}
		obj.func1();//kk
		obj.func2()//Uncaught TypeError: this.func1 is not a function

obj.func1中this指向调用此函数的obj,所以this.name是kk

obj.func2中的setTimeout是window下的settimeout,故而settimeout中的this指向的是window,全局中没有func1这样函数,故而报错。

var name = 'hh';
		var obj = {
			name:'kk',
			func1:function(){
				console.log(this.name)
			},
			func2:function(){
				setTimeout(function(){
					this.func1();
				},1000)
			}
		}
		obj.func1();//kk
		obj.func2()// kk

这时候,没有报错,因为箭头函数的this的值取决于该函数外部非箭头函数的this的值,也就是func2的this的值,即obj。

2.在函数内部使用 _this = this

var name = 'hh';
		var obj = {
			name:'kk',
			func1:function(){
				console.log(this.name)
			},
			func2:function(){
                let _this = this
				setTimeout(function(){
					_this.func1();
				},1000)
			}
		}
		obj.func1();//kk
		obj.func2() //kk

func2也可以正常运行,在func2中,首先设置var _this = this, 这里的this指向func2的对象obj,为了防止在func2的setTimeout 被window调用而导致的在setTimeot中的this为window,我们将this(指向变量obj)赋值给一个变量_this,这样,在func2中我们使用的_this就是指向对象obj了。

3.使用call、apply、bind

call:

var name = "hh";

var obj = {
    name:'kk',
    func1: function (){
        console.log(this.name)
    },
    func2:function(){
        setTimeout(function(){
            this.func1();
        }.call(obj),1000)
    }
},
obj.func2();// kk

apply:

var name = 'hh';
		var obj = {
			name:'kk',
			func1:function(){
				console.log(this.name)
			},
			func2:function(){
				setTimeout(function(){
					this.func1();
				}.apply(obj),1000)
			}
		}
		
		obj.func2() //kk

bind:

var name = 'hh';
		var obj = {
			name:'kk',
			func1:function(){
				console.log(this.name)
			},
			func2:function(){
				setTimeout(function(){
					this.func1();
				}.bind(obj)(),1000)
			}
		}
		
		obj.func2() //kk

call,apply,bind都能改变this的上下文对象,所以也没有报错,可以正常执行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值