js中call、apply、bind的用法

來源:互聯網
上載者:User

標籤:c   style   class   blog   code   java   

今天看部落格時,看到了這樣的一段js代碼:

var bind = Function.prototype.call.bind(Function.prototype.bind);

我想突然看到這樣的一段代碼,即使js能力再強的人,可能也需要花點時間去理解。像我這樣的菜鳥就更不用說了。其實,原文已經對這端代碼做出瞭解釋,但我還是想用我的想法去解釋這段代碼。

上面那段代碼涉及到了call、bind,所以我想先區別一下call、apply、bind的用法。這三個方法的用法非常相似,將函數綁定到上下文中,即用來改變函數中this的指向。舉個例子:

var zlw = {    name: "zlw",    sayHello: function (age) {         console.log("hello, i am ", this.name + " " + age " years old");     }};var  xlj = {    name: "xlj",};zlw.sayHello(24);// hello, i am zlw 24 years old

下面看看call、apply方法的用法:

zlw.sayHello.call(xlj, 24);// hello, i am xlj 24 years oldzlw.sayHello.apply(xlj, [24]);// hello, i am xlj 24 years old

結果都相同。從寫法上我們就能看出二者之間的異同。相同之處在於,第一個參數都是要綁定的上下文,後面的參數是要傳遞給調用該方法的函數的。不同之處在於,call方法傳遞給調用函數的參數是逐個列出的,而apply則是要寫在數組中。

我們再來看看bind方法的用法:

zlw.sayHello.bind(xlj, 24)(); //hello, i am xlj 24 years oldzlw.sayHello.bind(xlj, [24])(); //hello, i am xlj 24 years old

bind方法傳遞給調用函數的參數可以逐個列出,也可以寫在數組中。bind方法與call、apply最大的不同就是前者返回一個綁定內容相關的函數,而後兩者是直接執行了函數。由於這個原因,上面的代碼也可以這樣寫:

zlw.sayHello.bind(xlj)(24); //hello, i am xlj 24 years oldzlw.sayHello.bind(xlj)([24]); //hello, i am xlj 24 years old

bind方法還可以這樣寫 fn.bind(obj, arg1)(arg2) 。

用一句話總結bind的用法:該方法建立一個新函數,稱為綁定函數,綁定函數會以建立它時傳入bind方法的第一個參數作為this,傳入bind方法的第二個以及以後的參數加上綁定函數運行時本身的參數按照順序作為原函數的參數來調用原函數。

 

現在回到開始的那段代碼:

var bind = Function.prototype.call.bind(Function.prototype.bind);

 我們可以這樣理解這段代碼:

fn.bind(obj)

 fn 相當於 Function.prototype.call , obj 相當於 Function.prototype.bind 。而 fn.bind(obj) 一般可以寫成這樣 obj.fn ,為什麼呢?因為 fn 綁定了 obj , fn 中的 this 就指向了 obj 。我們知道,函數中 this 的指向一般是指向調用該函數的對象。所以那段代碼可以寫成這樣:

var bind = Function.prototype.bind.call;

大家想一想 Function.prototype.call.bind(Function.prototype.bind) 返回的是什嗎?

console.log(Function.prototype.call.bind(Function.prototype.bind)) // call()

返回的是 call 函數,但這個 call 函數中的內容相關的指向是 Function.prototype.bind 。這個 call 函數可以這樣用

var bind = Function.prototype.call.bind(Function.prototype.bind);var zlw = { name: "zlw" };function hello () {  console.log("hello, I am ", this.name);}bind(hello, zlw)() // hello, I am zlw

大家可能會感到疑惑,為什麼是這樣寫 bind(hello, zlw) 而不是這樣寫 bind(zlw, hello) ?既然 Function.prototype.call.bind(Function.prototype.bind) 相當於 Function.prototype.bind.call ,那麼先來看下 Function.prototype.bind.call 怎麼用。 call 的用法大家都知道:

Function.prototype.bind.call(obj, arg)

其實就相當於 obj.bind(arg) 。我們需要的是 hello 函數綁定對象 zlw ,即 hello.bind(zlw) 也就是 Function.prototype.bind.call(hello, zlw) ,所以應該這樣寫 bind(hello, zlw) 。

 

現在又有一個疑問,既然 Function.prototype.call.bind(Function.prototype.bind) 相當於 Function.prototype.bind.call ,我們為什麼要這麼寫:

var bind = Function.prototype.call.bind(Function.prototype.bind);

而不直接這樣寫呢:

var bind = Function.prototype.bind.call;

先來看一個例子:

var name = "xlj";var zlw = {    name: "zlw"     hello: function () {        console.log(this.name);    }};
zlw.hello(); // zlw
var hello = zlw.hello;hello(); // xlj

有些人可能會意外, hello() 的結果應該是 zlw 才對啊。其實,將 zlw.hello 賦值給變數 hello ,再調用 hello() , hello 函數中的 this 已經指向了 window ,與 zlw.hello 不再是同一個上下文,而全域變數 name 是 window 的一個屬性,所以結果就是 xlj 。再看下面的代碼:

var hello = zlw.hello.bind(zlw);hello(); // zlw

結果是 zlw ,這時 hello 函數與 zlw.hello 是同一個上下文。其實上面的疑惑已經解開了,直接這樣寫:

var bind = Function.prototype.bind.call;

 bind 函數中的上下文已經與 Function.prototype.bind.call 中的不一樣了,所以使用 bind 函數會出錯。而這樣寫

var bind = Function.prototype.call.bind(Function.prototype.bind);

 bind 函數中的上下文與 Function.prototype.call.bind(Function.prototype.bind) 中是一樣的。

 

關於這個這段代碼的解釋這到這邊了,感覺語言群組織能力不是很好,文章寫得有些囉嗦了。文中可能會有錯誤,希望大家指正。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.