一.理解this指針意義
二.用call(),apply(),bind()解決指針指向問題
三.bind()的使用場景與少用之處html
讓咱們先理解好this指針的定義:segmentfault
this引用的是函數執行的環境對象
數組
this永遠指向的是最後調用它的對象,也就是看它執行的時候是誰調用的
閉包
通俗地講,就是誰調用this,this就指向誰,咱們分類舉例app
舉例前先看下本文會一直用到的變量及定義的函數函數
var theName = "Joe"; //全局變量 function showName() { var theName = "Li"; alert(this.theName); }
showName(); //彈出「Joe」
由於是window對象調用showName()
,因此this指向window啦,故彈出"Joe"this
var student1 = { theGrade : 100, theName : "Han", showName : showName, showGrade : function () { alert(this.theGrade); } }; student1.showName();//彈出「Han」 student1.showGrade();//彈出「100」
由於是在student1對象調用函數
,故彈出的是對應student1對象中的"Han"和「100」啦spa
var student2 = { theGrade: 60, showGrade: student1.showGrade }; student2.showGrade(); //彈出"60"
即便student2對象
調用了student1對象下的方法showGrade()
,由於是student2對象調用
,故彈出的還是student2的"60"prototype
var outFunction = student1.showGrade; outFunction();//彈出「undefined」
將sutdent1對象的函數賦值給oufFuncction,而outFunction是在window對象下調用的
,故彈出「undefined」設計
function setStudent() { this.theName = "Ming"; } var student3 = new setStudent(); alert(student3.theName);//彈出「Ming」,new改變this指向
構造函數下,new改變了指針指向,指向了student3
關鍵:閉包保存建立時的環境!!!
舉個例子
爲了更好理解閉包與指針的關係,咱們先定義一個全局變量,一個函數,和一個對象
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 };
結果:
接下來分段說明各個指針
其中
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()的應用了
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()的做用都是在特定的做用域中調用函數
,實際上等於設置函數體內設置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]是傳參示例 };
如上,經過call()與apply()的應用,能夠改變函數的指向而屢次運用
若是我想便於調試
想使用ele.addEventListener()嘞?
這就要用上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);
控制檯顯示以下
能夠看出this指向的是btn
,而沒法知足咱們使用exampleObject中屬性的須要,同時也沒法進行傳參(用call()與apply()就直接執行函數了!)
(這裏的沒有對第一個參數arg1進行傳參,故默認顯示MouseEvent對象)
這時咱們能夠用bind()方法建立一個新的函數
,並讓其指針指向exampleObject
,並傳兩個新的參數進去
btn.addEventListener('click',exampleObject.showExample_in_Object.bind(exampleObject,111,222));
噹噹~指針指向了exampleObject,傳參也成功了~
另外,這裏也有個能夠不使用bind()的方法,就是也用閉包
啦
btn.addEventListener('click',function () { exampleObject.showExample_in_Object(111,222); });
結果同樣,但這種方法不利於代碼的維護
,同時也沒法指向特定的對象
使用場景:主要用於如上的事件監聽
,以及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語言精粹》