理解this
JavaScript中的this是其靈活性的表現(xiàn),同時也因為this的多變性與其他語言的不一致,也成為JavaScript的一個難以理解的地方。因此在這里總結(jié)一下this常見的情況,以加深記憶
JavaScript中的this表示執(zhí)行上下文對象,有以下幾種綁定規(guī)則:
1.默認綁定
JavaScript中規(guī)定,函數(shù)中的this默認會和window對象綁定(在嚴格模式下默認綁定會失效)
var name = 'yip'
function a(){
console.log(this.name);
}
a();//yip
2.隱式綁定
當函數(shù)的調(diào)用位置有另外一個上下文對象時,this會和這個上下文對象綁定,簡單來說就是和函數(shù)的調(diào)用者綁定
var name = 'yip';
function a(){
console.log(this.name);
}
var obj = {
name:'xie',
a:a
}
obj.a();//xie
隱式綁定有兩種特殊情況會導致隱式綁定失效
var name = 'yip';
function a(){
console.log(this.name);
}
var obj = {
name:'xie',
a:a
}
var obj1 = {
name : 'zhan'
}
var b = obj.a;
b();//yip,這是第一種情況,這時的b只是取得了obj.a的引用,執(zhí)行時上下文還是沒有綁定
obj.a();//xie
(obj1.a = obj.a)()//yip,這里是第二種情況,間接引用,但是執(zhí)行上下文還是沒有綁定
在計時器setTimeout中,以及把函數(shù)作為參數(shù)傳遞到另一函數(shù)中,也會發(fā)生隱式丟失,在這種情況下,相當于隱式賦值。
var name = 'yip';
function a(){
console.log(this.name);
}
var obj = {
name:'xie',
a:a,
b:function(){
setTimeout(function(){
console.log(this.name);
},1000)
}
}
setTimeout(obj.a,1000);//yip
function argFunc (func){
func();
}
argFunc(a);//yip
obj.b();//yip
3.顯示綁定
JavaScript中有3個特殊的方法。call、apply、bind,可以顯式指定函數(shù)的執(zhí)行上下文
var name = 'yip';
function a(){
console.log(this.name);
}
var obj = {
name:'xie',
a:a
}
var obj1 = {
name : 'zhan'
}
obj.a();//xie
a.call(obj);//xie
a.apply(obj);//xie
var b = a.bind(obj);
b();//xie
bind 與 apply和call 作用相似,但bind返回一個函數(shù),可以在后來被調(diào)用,其執(zhí)行環(huán)境由bind綁定;
ES5以下實現(xiàn)bind
function mybind(func,context){
if(func.bind){
return func.bind(context);
}else{
return function(){
func.apply(context);
}
}
}
構(gòu)造函數(shù)里的this
JavaScript中規(guī)定,任何函數(shù)都可以用new操作符實例化對象,使用new操作符之后,函數(shù)就變?yōu)闃?gòu)造函數(shù),其中的this指向新建的對象。
使用new操作符時,在JavaScript機制中執(zhí)行下列幾步操作
新建一個空對象;
執(zhí)行函數(shù)內(nèi)容;
把this指向新建的對象;
-
返回一個對象,可能是函數(shù)中返回的也可能是新建打的對象
function a(){
this.name = 'yip';
this.sayName = fucntion (){
console.log(this.name);
}
}
var obj = new a();
obj.sayName();//yip
一個簡單的驗證方法是看函數(shù)調(diào)用的前面是否是一個引用對象。
事件處理器中的this
在事件處理器中的this指向事件發(fā)生的對象。
var name = 'yip';
var mybtn = document.getElementById('mybtn');
function callback (){
console.log(this);
}
mybtn.addEventListener("click",callback)//button
ES6箭頭函數(shù)
在ES6中,新增箭頭函數(shù),在箭頭函數(shù)中不使用上面所說的任意一種綁定規(guī)則,而是根據(jù)外層作用域的this來決定this(函數(shù)內(nèi)或者是全局)。
這可以解決在函數(shù)中使用setTimeout發(fā)生的隱式丟失,ES6之前的解決方案是通過聲明一個變量存儲this來實現(xiàn)
var self = this;
ES6中是:
var name = 'yip';
function a(){
console.log(this.name);
}
var obj = {
name:'xie',
a:a,
b:function(){
setTimeout(()=>{
console.log(this.name);
},1000)
}
}
obj.b();//xie
因此常把ES6的箭頭函數(shù)用于事件處理器和計時器中
var name = 'yip';
var mybtn = document.getElementById('mybtn');
callback = () =>{
console.log(this);
}
mybtn.addEventListener("click",callback)//window