1. 程式人生 > >JS中this關鍵字、call、apply方法

JS中this關鍵字、call、apply方法

箭頭函數 bind 改變 定義 defined 其他 屬性 同時 需要

首先,必須搞清楚在JS裏面,函數的幾種調用方式:

  • 普通函數調用

  • 作為方法來調用

  • 作為構造函數來調用

  • 使用apply/call方法來調用

  • Function.prototype.bind方法

  • es6箭頭函數

誰調用這個函數或方法,this關鍵字就指向誰。

普通函數調用

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

在這段代碼中person

函數作為普通函數調用,實際上person是作為全局對象window的一個方法來進行調用的,即window.person();

所以這個地方是window對象調用了person方法,那麽person函數當中的this即指window,同時window還擁有了另外一個屬性name,值為xl.

var name="xl";
function person(){
 console.log(this.name);
 }
   person(); //輸出 xl

同樣這個地方person作為window的方法來調用,在代碼的一開始定義了一個全局變量name,值為xl,它相當於window的一個屬性,即window.name="xl"

,又因為在調用person的時候this是指向window的,因此這裏會輸出xl.

作為方法來調用

在上面的代碼中,普通函數的調用即是作為window對象的方法進行調用。顯然this關鍵字指向了window對象.

再來看下其他的形式

var name="XL";
    var person={
        name:"xl",
        showName:function(){
            console.log(this.name);
        }
    }
    person.showName();  //輸出  xl
   //這裏是person對象調用showName方法,很顯然this關鍵字是指向person對象的,所以會輸出name
var showNameA=person.showName; showNameA(); //輸出 XL //這裏將person.showName方法賦給showNameA變量,此時showNameA變量相當於window對象的一個屬性,因此showNameA()執行的時候相當於window.showNameA(),即window對象調用showNameA這個方法,所以this關鍵字指向window

再換種形式:

var personA={
        name:"xl",
        showName:function(){
            console.log(this.name);
        }
    }
    var personB={
        name:"XL",
        sayName:personA.showName
    }
    
    personB.sayName();  //輸出 XL
    //雖然showName方法是在personA這個對象中定義,但是調用的時候卻是在personB這個對象中調用,因此this對象指向

作為構造函數來調用

function  Person(name){
        this.name=name;
    }
    var personA=Person("xl");   
    console.log(personA.name); // 輸出  undefined
    console.log(window.name);//輸出  xl
    //上面代碼沒有進行new操作,相當於window對象調用Person("xl")方法,那麽this指向window對象,並進行賦值操作window.name="xl".
    
    var personB=new Person("xl");
    console.log(personB.name);// 輸出 xl
    //這部分代碼的解釋見下

call/apply方法的調用

在JS裏函數也是對象,因此函數也有方法。從Function.prototype上繼承到Function.prototype.call/Function.prototype.apply方法
call/apply方法最大的作用就是能改變this關鍵字的指向.

Obj.method.apply(AnotherObj,arguments);

var name="XL";
    var Person={
        name:"xl",
        showName:function(){
            console.log(this.name);
        }
    }
    Person.showName.call(); //輸出 "XL"
    //這裏call方法裏面的第一個參數為空,默認指向window。
    //雖然showName方法定義在Person對象裏面,但是使用call方法後,將showName方法裏面的this指向了window。因此最後會輸出"XL";
    funtion FruitA(n1,n2){
        this.n1=n1;
        this.n2=n2;
        this.change=function(x,y){
            this.n1=x;
            this.n2=y;
        }
    }
    
    var fruitA=new FruitA("cheery","banana");
    var FruitB={
        n1:"apple",
        n2:"orange"
    };
    fruitA.change.call(FruitB,"pear","peach");
    
    console.log(FruitB.n1); //輸出 pear
    console.log(FruitB.n2);// 輸出 peach

FruitB調用fruitAchange方法,將fruitA中的this綁定到對象FruitB上。

Function.prototype.bind()方法

var name="XL";
    function Person(name){
        this.name=name;
        this.sayName=function(){
            setTimeout(function(){
                console.log("my name is "+this.name);
            },50)
        }
    }
    var person=new Person("xl");
    person.sayName()  //輸出  “my name is XL”;
                       //這裏的setTimeout()定時函數,相當於window.setTimeout(),由window這個全局對象對調用,因此this的指向為window, 則this.name則為XL

那麽如何才能輸出"my name is xl"呢?

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

這裏setTimeout(function(){console.log(this.name)}.bind(this),50);,匿名函數使用bind(this)方法後創建了新的函數,這個新的函數不管在什麽地方執行,this都指向的Person,而非window,因此最後的輸出為"my name is xl"而不是"my name is XL"

另外幾個需要註意的地方:
setTimeout/setInterval/匿名函數執行的時候,this默認指向window對象,除非手動改變this的指向。在《javascript高級程序設計》當中,寫到:“超時調用的代碼(setTimeout)都是在全局作用域中執行的,因此函數中的this的值,在非嚴格模式下是指向window對象,在嚴格模式下是指向undefined”。本文都是在非嚴格模式下的情況。

var name="XL";
    function Person(){
        this.name="xl";
        this.showName=function(){
            console.log(this.name);
        }
        setTimeout(this.showName,50);
    }
    var person=new Person(); //輸出 "XL"
    
    //在setTimeout(this.showName,50)語句中,會延時執行this.showName方法
    //this.showName方法即構造函數Person()裏面定義的方法。50ms後,執行this.showName方法,this.showName裏面的this此時便指向了window對象。則會輸出"XL";

修改上面的代碼:

var name="XL";
    function Person(){
        this.name="xl";
        var that=this;
        this.showName=function(){
            console.log(that.name);
        }
        setTimeout(this.showName,50)
    }
    var person=new Person(); //輸出 "xl"



    //這裏在Person函數當中將this賦值給that,即讓that保存Person對象,因此在setTimeout(this.showName,50)執行過程當中,console.log(that.name)即會輸出Person對象的屬性"xl"

本文引用自http://www.cnblogs.com/lisha-better/p/5684844.html

JS中this關鍵字、call、apply方法