天天看點

JS函數中的this指向問題

今天我要說的是JS中的this指向,首先我們應該知道在js中函數的幾種調用方式:

  1. 普通函數調用
  2. 作為方法來調用
  3. 作為構造函數來調用
  4. 使用apply/call方法來調用
  5. Function.prototype.bind方法
  6. es6箭頭函數

不管是通過哪種方式函數調用,我們都應該明确一點誰調用這個函數或方法,this關鍵字就指向誰。

1.普通函數調用

function person(){
    this.name="lx";
    console.log(this);//window
    console.log(this.name);//lx
}
person();
console.log(window.name);//lx
           

在這段代碼中person函數作為普通函數調用,實際上person是作為全局對象window的一個方法來進行調用的,即window.person(),是以這個地方是window對象調用了person方法,那麼person函數當中的this即指window,同時window還擁有了另外一個屬性name,值為lx,我在最後也輸出了window.name即lx。

2.作為方法來調用

var name="lx";
var person={
    name:"jay",
    showName1:function(){
        console.log(this.name);
    }
}
person.showName1();//jay
var showName2=person.showName1;
showName2();//lx
第一個是的person對象調用showName1方法,是以this指向person對象,是以輸出jay,第二個将person.showName1方法指派給showName2變量,此時showName2變量相當于window對象的一個屬性,相當于window.showName2,是以this指向的是window,輸出lx
           
var personA={
    name:"lx",
       showName:function(){
           console.log(this.name);//jay
       }
}
var personB={
    name:"jay",
    sayName:personA.showName
}    
personB.sayName();
           

這裡的showName方法肅然是在personA這個對象中定義,但是調用的時候卻是在personB這個對象中調用,是以this對象指向的是personB

3.作為構造函數調用

function  Person(name){
    this.name=name;
}
var personA=Person("lx");
console.log(personA.name); //會報錯
console.log(window.name);//輸出lx
//上面代碼沒有進行new操作,相當于window對象調用Person("lx")方法,那麼this指向window對象,并進行指派操作window.name="lx".
var personB=new Person("lx");
console.log(personB.name);// 輸出lx
           

new操作符

function person11(name){
    var o={};
    o.__proto__=Person.prototype;  //原型繼承
    Person.call(o,name);
    return o;
}
var personB=person11("lx");
console.log(personB.name);  // 輸出  lx
           

上面這段代碼模拟了new操作符(執行個體化對象)的内部過程

4.call/apply方法的調用

在JS裡,函數也是對象,是以函數也有方法,從Function.prototype上繼承到Function.prototype.call/Function.prototype.apply方法。

call/apply方法最大的作用就是能改變this關鍵字的指向。

var name="jay";
var Person={
    name:"lx",
    showName:function(){
        console.log(this.name);
    }
}
    Person.showName.call(Person); //輸出lx
    Person.showName.call();//輸出 jay
           

雖然showName方法定義在Person對象裡面,但是使用call方法後,将showName方法裡面的this指向了window,是以最後會輸出jay,這裡call方法裡面的參數為空,預設指向window。

5. Function.prototype.bind方法

var name="jay";
function Person(name){
    this.name=name;
    this.sayName=function(){
        setTimeout(function(){
            console.log("my name is "+this.name);
        },)
    }
}
var person=new Person("lx");
person.sayName(); //輸出my name is jay
//這裡的setTimeout()定時函數,相當于window.setTimeout(),由window這個全局對象對調用,是以this的指向為window, 則this.name則為jay
           

難麼該怎麼輸出my name is lx?

var name="jay";
function Person(name){
    this.name=name;
    this.sayName=function(){
        setTimeout(function(){
            console.log("my name is "+this.name);
        }.bind(this),)//這個地方使用的bind()方法,綁定setTimeout裡面的匿名函數的this一直指向Person對象
    }
}
var person=new Person("lx");
person.sayName(); //輸出my name is lx
           

這裡setTimeout(function(){console.log(this.name)}.bind(this),50);,匿名函數使用bind(this)方法後建立了新的函數,這個新的函數不管在什麼地方執行,this都指向的Person,而非window,是以最後的輸出為my name is lx而不是my name is jay。

這裡的第六種方法是 es6箭頭函數,es6的内容看的稍微有點少,了解的不是很全面,是以我就不再做詳細的書寫了,感興趣的大牛可以度娘了解一下。

繼續閱讀