call,apply,bind這三個方法在JavaScript中是用來改變函數調用的this指向。那麼改變函數this指向有什麼用呢?咱們先來看一段代碼html
var a= { name:'harden', fn:function () { console.log(this.name); } } var b = a.fn; a.fn();//harden b();//undefined
調用a.fn方法後獲得了harden,但在b方法中我想獲得harden,爲何倒是undefined呢?緣由是方法在執行的時候才能肯定this到底指向誰,實際上this指向的是最終調用函數的對象。這裏當b執行時,實際是window調用了fn函數,那麼fn中的this就指向window。
在開始講call,apply,bind方法前,一塊兒來總結一下this的指向問題。app
整體來講this指向能夠歸納爲一句話:this指向在函數的定義時是不肯定的,只有函數執行時才能肯定this到底指向誰,實際上this的最終指向的是那個調用它的對象。可是這個說法在函數被不少對象包裹的時候並不成立,請看下面例子。
簡單來講就是:誰(哪一個對象)調用的這個函數,那麼這個函數中的this就指向這個對象。函數
例一this
function a(){ var name= "harden"; console.log(this.name); //undefined console.log(this); //Window } a();
由於this最終指向調用他的對象,在上述代碼中實際上是widow觸發的這個方法,那麼this就指向window,window中並無定義a,那麼就打印出undefined。
例二:code
var a = { name:'harden', fn:function() { console.log(this.name);//harden console.log(this);//指向a(能夠本身跑一下) } } a.fn()
這裏的this指向a,由於這裏的fn函數是經過a.fn()
執行的,那麼this天然指向a。
說到這我就有疑問了,若是我用 window.a.fn()
執行函數,this不就指向window了嗎?而後並非這樣的,請看下一個例子。補充一點:window是js的全局對象。
例三:htm
var a = { name:'harden', b:{ name:'james', fn:function() { console.log(this.name);//james console.log(this);//指向b } } } a.b.fn()
咱們看到最終是a調用的方法,那爲何this會指向b呢?如今總結三句話,來徹底理解this的指向問題:對象
狀況一:若是一個函數中有this,可是它沒有被上一級的對象所調用,那麼this指向的就是window(除去嚴格模式外)。
狀況二:若是一個函數中有this,這個函數有被上一級的對象所調用,那麼this指向的就是上一級的對象。
狀況三:若是一個函數中有this,這個函數中包含多個對象,儘管這個函數是被最外層的對象所調用,this指向的也只是它上一級的對象,例子3能夠證實。blog
構造函數中的this:ip
function Fn(){ this.name = "harden"; } var a = new Fn(); console.log(a.name); //harden
這裏的a能夠點出name,由於new關鍵字會改變this的指向。爲何new關鍵字會改變this呢,我本身有兩種見解:
1.在new的過程當中會建立一個實例對象,經過apply等方法 經過 Fn.apply({}) 使this指向這個空對象,最後把fn方法中的材料加工完後返回給a。get
當this遇到return的時候:
function fn() { this.user = 'harden'; return {}; } var a = new fn; console.log(a.user); //undefined function fn() { this.user = 'harden'; return function(){}; } var a = new fn; console.log(a.user); //undefined function fn() { this.user = 'harden'; return 1; } var a = new fn; console.log(a.user); //harden function fn() { this.user = 'harden'; return undefined; } var a = new fn; console.log(a.user); //harden
總結一下:若是返回值是一個對象,那麼this指向的就是那個返回的對象,若是返回值不是一個對象那麼this仍是指向函數的實例。還有一點就是返回null,null也是對象,可是由於他的特殊性,返回後this仍是指向函數自己的實例。理解JavaScript中的指向問題
理解完JavaScript中的指向問題,那麼回到正題:
1.call
a = { name: 'harden' } function b () { console.log(this.name); } b.call(a);//harden b()//undefined
b.call(a)用字面意思來說就是:把函數b添加到對象a的環境中,使函數中的this指向對象a。
call與apply不一樣的地方就是傳參不一樣。
2.apply
a = { name: 'harden' } function b (data1,data2) { console.log(data1,data2); } b.call(a,'a1','a2');//a1 a2 b.apply(a,['a1','a2']);//a1 a2
3.bind
a = { name: 'harden' } function b () { console.log(this.name); } b.bind(a);//不會執行函數 var aaa = b.bind(a); aaa()//harden
bind不會當即調用函數,是把函數返回,bind一般用它來指定回調函數的this。
關於call, apply, bind方法的區別與內部實現