this指針使用及call(),apply()及bind()的使用

目錄

一.理解this指針意義
二.用call(),apply(),bind()解決指針指向問題
三.bind()的使用場景與少用之處html

一.理解this指針意義

讓咱們先理解好this指針的定義:segmentfault

this引用的是函數執行的環境對象數組

this永遠指向的是最後調用它的對象,也就是看它執行的時候是誰調用的閉包

通俗地講,就是誰調用this,this就指向誰,咱們分類舉例app

舉例前先看下本文會一直用到的變量及定義的函數函數

var theName = "Joe";    //全局變量

function showName() {
   var theName = "Li";
   alert(this.theName);
}

1.全局直接調用方法

showName();    //彈出「Joe」

由於是window對象調用showName(),因此this指向window啦,故彈出"Joe"this

2.對象中調用全局下的方法

var student1 = {
   theGrade : 100,
   theName : "Han",
   showName : showName,
   showGrade : function () {
      alert(this.theGrade);
   }
};
student1.showName();//彈出「Han」
student1.showGrade();//彈出「100」

由於是在student1對象調用函數,故彈出的是對應student1對象中的"Han"和「100」啦spa

3.對象中調用其餘對象的方法

var student2 = {
   theGrade: 60,
   showGrade: student1.showGrade
};
student2.showGrade();    //彈出"60"

即便student2對象調用了student1對象下的方法showGrade(),由於是student2對象調用,故彈出的還是student2的"60"prototype

4.對象的方法賦給全局變量執行

var outFunction = student1.showGrade;
outFunction();//彈出「undefined」

將sutdent1對象的函數賦值給oufFuncction,而outFunction是在window對象下調用的,故彈出「undefined」設計

5.構造函數下的this指針

function setStudent() {
   this.theName = "Ming";
}
var student3 = new setStudent();
alert(student3.theName);//彈出「Ming」,new改變this指向

構造函數下,new改變了指針指向,指向了student3

6.事件監聽中建立閉包的this指針

關鍵:閉包保存建立時的環境!!!

舉個例子

爲了更好理解閉包與指針的關係,咱們先定義一個全局變量,一個函數,和一個對象

var example = 'window';//全局變量

function showExample() {
   console.log(this.example);
}

var exampleObject = {
   example : 'Object',
   showExample_in_Object : function (arg1, arg2) {
      console.log(this.example);
      console.log(arg1,arg2)
   }
};

接着,咱們設置一個事件監聽來講明問題:

//事件監聽
var btn = document.getElementById("btn");
btn.onclick = function (ev) {
   console.log(this); //this指向按鈕,執行匿名函數的是btn
   this.example = 'ele';
   console.log(this.example);//彈出"ele"
   showExample(); //閉包保存函數建立時的環境,故this指向window對象 
   exampleObject.showExample_in_Object();//this指向exampleObject
};

結果:

clipboard.png

接下來分段說明各個指針

其中

    this.example = 'ele';

    console.log(this.example);

其中的this指向btn,因此顯示的是‘ele’

    showExample();      

    exampleObject.showExample_in_Object();    

匿名函數中爲閉包,閉包保存函數建立時的環境,故this分別指向window和exampleObject

補充對閉包中this的理解:https://segmentfault.com/q/10...

以上是部分this指針的理解

若是我在事件監聽中想要減小代碼重複,或者是調用其餘對象的屬性呢?

若是我想用btn.addEventListener()時指向的某個特定對象呢?

這就能夠引出下面call(),apply()與bind()的應用了

7.函數中自執行函數指向

function User(id){
    this.id = id;
}
User.prototype.test = function(){
    console.log(this);//指向b對象

   (function(){
    console.log(this) //指向window
})()
}
var a = new User('a')
a.test();

由於自執行函數是由window執行的
若是此時使用箭頭函數

function User2(id){
    this.id = id;
}
User.prototype.test = function(){
    console.log(this); //指向b對象

   (() =>{
    console.log(this) //指向b對象
})()
}
var b = new User2('b');
b.test();

由於箭頭函數不會綁定this,因此指向上一層的b對象

二.用call(),apply(),bind()解決指針指向問題

1.call()與apply()

call()與apply()的做用都是在特定的做用域中調用函數,實際上等於設置函數體內設置this對象的值

簡單地說,就是能夠改變函數的執行環境

call()與allpy()效果相同,僅是傳參形式不一樣,以下所示

call():

fun.call(thisArg, arg1, arg2, ...)

thisArg : fun函數運行時指定的this值

arg1,arg2,.. (可選):指定的各個參數
apply():

func.apply(thisArg, [argsArray])

thisArg : fun函數運行時指定的this值

[argsArray](可選) : 傳參數組或者傳參類數組

下面直接看例子吧

咱們以上面的例子進行修改,爲了對比傳參的形式,咱們對showExample函數添加兩個參數

function showExample(arg1,arg2) {
   console.log(this.example);
   console.log(arg1,arg2);
}

接下來即是btn的點擊事件函數修改,咱們令showExample函數指向exampleObject

//call與apply的應用
btn.onclick = function (ev) {
   showExample.call(exampleObject,111,222); //彈出'Object' ,111與222是傳參示例
   showExample.apply(exampleObject,[111,222]); //彈出'Object' ,[111,222]是傳參示例
};
彈出'Object' ,111與222是傳參示例
   showExample.apply(exampleObject,[111,222]); //彈出'Object' ,[111,222]是傳參示例
};

clipboard.png

如上,經過call()與apply()的應用,能夠改變函數的指向而屢次運用

若是我想便於調試想使用ele.addEventListener()嘞?

這就要用上bind()方法了

2.bind()的運用

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

MDN : bind()方法建立一個新的函數, 當被調用時,將其this關鍵字設置爲提供的值, ,在調用新函數時,在任何提供以前提供一個給定的參數序列。

咱們再舉個簡單的例子,將exampleObject簡單修改下

var exampleObject = {
   example : 'Object',
   showExample_in_Object : function (arg1, arg2) {
      console.log(this);
      console.log('example:'+ this.example);
      console.log('arg1:' + arg1);
      console.log('arg2:' + arg2);
   }
};

並把showExample_in_Object()函數添加給btn

注意這裏的是函數,不是閉包!

btn.addEventListener('click',exampleObject.showExample_in_Object);

控制檯顯示以下

clipboard.png

            

能夠看出this指向的是btn,而沒法知足咱們使用exampleObject中屬性的須要,同時也沒法進行傳參(用call()與apply()就直接執行函數了!)

(這裏的沒有對第一個參數arg1進行傳參,故默認顯示MouseEvent對象)

這時咱們能夠用bind()方法建立一個新的函數,並讓其指針指向exampleObject,並傳兩個新的參數進去

btn.addEventListener('click',exampleObject.showExample_in_Object.bind(exampleObject,111,222));

clipboard.png

噹噹~指針指向了exampleObject,傳參也成功了~

另外,這裏也有個能夠不使用bind()的方法,就是也用閉包

btn.addEventListener('click',function () {
    exampleObject.showExample_in_Object(111,222);
});

結果同樣,但這種方法不利於代碼的維護,同時也沒法指向特定的對象    

三.bind()的使用場景與少用之處

使用場景:主要用於如上的事件監聽,以及setTimeout()setInterval()

少用之處:被綁定的函數與普通函數相比有更多的開銷,它們須要更多的內存,同時也由於多重函數調用稍微慢一點,因此最好只在必要時使用

以上,若有不對之處,請你們指教

參考資料:

    完全理解this指針:    https://www.cnblogs.com/pssp/...

    MDN:bind():    https://developer.mozilla.org...

    MDN:apply():https://developer.mozilla.org...

    MDN:call():    https://developer.mozilla.org...

    《JavaScript高級程序設計(第3版)》

    《JavaScript語言精粹》

相關文章
相關標籤/搜索