[JS]大話this指針

5分鐘快速掌握版

在剛開始學習JavaScript的時候,常常被js中的this及其相關的方法,例如:bind,apply,call方法迷惑。其實咱們只要根據包含this指針的方法的用途加以區分,就能瞭解this指針所指向的對象:數組

一、直接函數調用,this指針指向全局環境,即Window對象,例如app

二、對象函數調用,this指針指向調用函數的對象自己,例如:函數

var object={
    'name':"vicky",
    'sayName':function(){ console.log(this.name)}
};
object.sayName();   //this指針指向object對象,所以輸出vicky
複製代碼

三、構造函數調用,this指針指向新建立的對象,例如:學習

function object(name){
    this.name=name;
    console.log(this);      //因爲this指向新建立的對象自己,輸出:Object { name: "vikcy" }
    console.log(this.name);  //輸出:"vicky"
}
var myObject=new Object('vicky');  //因爲this指向新建立的對象自己
複製代碼

四、間接函數調用,例如call、apply方法,還有個特殊的bind方法this

詳細分析this指針

一、直接函數調用

this指針指向全局環境,即Window對象spa

在全局環境中直接調用函數時,this對象會指向Window對象,例如:prototype

var name='vicky'
function sayName(name){
    console.log(this.name);
}
sayName();   //this指向window對象,而由於在全局環境中定義了var name='vicky';因此this.name輸出:vicky
window.sayName();  //sayName()效果等同於window.sayName()
複製代碼

二、對象函數調用

this指針指向調用函數的對象自己指針

var name='Bob';
function sayName(){
    console.log(this.name);
}
var object={'name':'vicky'};
object.sayName=sayName;          //sayName沒有寫成sayName(),表示不是執行函數,而是將sayName的指針賦值給object.sayName
object.sayName();               //因爲對象函數調用方法,this指向對象自己,因此輸出:'vicky'
sayName();                     //因爲全局環境調用sayName()等同於window.sayName();輸出:'Bob'
複製代碼

上面的例子已經很好的說明了在全局環境直接調函數調用和對象函數調用時this指針指向的區別。code

三、構造函數調用

this指針指向新建立的對象對象

function object(name){
    this.name=name;
    console.log(this);      //因爲this指向新建立的對象自己,輸出:Object { name: "vikcy" }
    console.log(this.name);  //輸出:"vicky"
}
var myObject=new Object('vicky');  //因爲this指向新建立的對象自己
複製代碼

開篇的例子已經很好的說明了構造函數調用的時候,this指針指向新建立對象的自己。

拓展new關鍵詞(可跳過)

但在這裏我想拓展一下知識,想跟你們聊聊爲何構造函數調用的時候,this指針爲何指向建立對象的自己,new關鍵字到底作了什麼?

其實在經過new關鍵詞去調用構造函數建立對象的時候,經歷了以下的過程:

一、建立新對象,繼承構造函數的prototype

二、調用call()方法,接受參數並修改this的指向,指向這個新對象

三、執行構造函數,若是構造函數有返回對象,則這個對象會取代步驟1建立的新對象,若是構造函數沒有返回值,則返回步驟1建立的對象。

若是用代碼模擬這個過程,能夠大體參考:

var newObject=function(func){
    var o={};  //建立一個新對象
    o.__proto__=func.prototype;  //繼承構造函數prototype
    var k=func.call(o);         //調用call方法,修改this指向,指向這個新建立的對象
    if(typeof k=== 'object'){
        //若是構造函數有返回對象,則取代步驟1建立的對象,返回構造函數所返回的對象
        return k;
    }else{
        //若是構造函數沒有返回對象,則直接返回步驟1建立的對象
        return o;
    }
}
複製代碼

這段模擬的代碼有一點缺陷,缺陷就是call方法的時候沒有模擬接受參數的步驟,不過不影響咱們對new關鍵詞的理解。

如今咱們經過實例,來理解下上面的new關鍵詞運做:

function Dog(name){
    this.name=name;
    console.log(this.name);    //輸出'泰迪'
    console.log(this);        //輸出:Object { name: "泰迪" }
}
Dog.prototype.sayName=function sayName(){
console.log("my name is "+this.name);
}
var animal=new Dog("泰迪");
animal.sayName();       //輸出:'my name is 泰迪'
複製代碼

上面的這段代碼,已經可以證明了如下幾點:

一、構造函數this指針指向新建立的對象

二、建立新對象,繼承構造函數的prototype

三、調用call()方法,接受參數並修改this的指向,指向這個新對象

對於

執行構造函數,若是構造函數有返回對象,則這個對象會取代步驟1建立的新對象,若是構造函數沒有返回值,則返回步驟1建立的對象。

這一點,咱們在看下下面這個實例:

function Cat(){
    console.log(this);   //輸出:Object {  }
    console.log("cat"); 
}
function Dog(name){
    this.name=name;
    console.log(this.name);
    console.log(this);    //輸出:Object { name: "泰迪" }
    return new Cat();    //關鍵代碼,在構造函數返回了一個對象
}
var animal=new Dog("泰迪");   //輸出:Object {  }
複製代碼

這段代碼咱們能夠證明:

執行構造函數,若是構造函數有返回對象,則這個對象會取代步驟1建立的新對象,若是構造函數沒有返回值,則返回步驟1建立的對象。

這一點,咱們在Dog的構造函數最後返回了一個Cat的對象,因此animal指針指向的是構造函數中返回的new Cat()的對象實例。

四、間接函數調用,例如call、apply方法,還有個特殊的bind方法

call(this指針要指向的對象,參數1,參數2,.....)

call方法能夠動態的設置函數體內的this指向,例如:

function Cat(age,name){
    this.name='cat';
    console.log(this);
    console.log('cat: age:'+age+",name:"+name);
}
var cat=new Cat(4,'Bob');    //輸出:Cat {name: "cat"}和cat: age:4,name:Bob
Cat.call(this,3,'Tom');     //因爲調用了call方法,輸出:this指向了Window和cat: age:3,name:Tom
複製代碼

先看

var cat=new Cat(4,'Bob'); 這行代碼,這裏的this指向的是新建的Cat對象,輸出的「cat: age:4,name:Bob」也是在對象初始化時候傳入的。

Cat.call(this,3,'Tom'); 這行代碼,這裏的this指向的是Window對象,由於:咱們在全局環境調用了 Cat.call(this,3,'Tom'); 方法,這裏call函數第一個參數(this指針要指向的對象)咱們傳入了this,而全局環境下的this指向的正好就是window對象,而第三和第四個參數,咱們分別定義了age=>3,name=>'Tom'

apply(this指針要指向的對象,參數數組或arguments對象)

apply方法和call方法的做用相同,惟一不一樣的是call方法要將參數一一傳入,而apply方法傳入的是數組或者arguments對象。arguments對象包含了函數的全部參數。

實例:

function Cat(age,name){
    this.name='cat';
    console.log(this);
    console.log('cat: age:'+age+",name:"+name);
}
var cat=new Cat(4,'Bob');    //輸出:Cat {name: "cat"}和cat: age:4,name:Bob
Cat.apply(this,[3,'Tom']);     //因爲調用了apply方法,輸出:this指向了Window和cat: age:3,name:Tom
function getCat(age,name){
    Cat.apply(this, arguments);    //arguments包含了函數的參數
}
getCat(5,"kitty");           //因爲調用了apply方法,輸出:this指向了Window和cat: age:5,name:kitty
複製代碼
bind(this指針要指向的對象)

bind這個方法會建立一個函數的實例,其 this 值會被綁定到傳給 bind()函數的值。

window.color = "red"; 
var o = { color: "blue" }; 
function sayColor(){ 
    console.log(this.color); 
    
} 
var objectSayColor = sayColor.bind(o); 
objectSayColor(); //因爲調用了 sayColor.bind(o),bind函數返回的函數實例中的this直接綁定了o這個對象,
                    因此即便在全局環境調用函數objectSayColor,也會輸出:"blue"
window.objectSayColor();   //輸出:"blue"
複製代碼

最後覆盤:

因此要了解this指向時,咱們應該先弄清楚函數調用的方式,最後問本身這個this指向的對象是從何而來。

我是大麥,若是喜歡個人文章,請點個贊。

相關文章
相關標籤/搜索