成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

把玩 JavaScript 中的 bind

shenhualong / 2798人閱讀

摘要:此模式調(diào)用函數(shù)的時候,被綁定到全局對象。構(gòu)造器調(diào)用模式如果在一個函數(shù)前面帶上來調(diào)用,那么背地里將會創(chuàng)建一個連接到該函數(shù)的成員的新對象,同時會被綁定到新對象上。

前言

今天閑著無聊隨便逛了逛MDN,忽而看到一個方法Function.prototype.bind(),突然發(fā)現(xiàn)除了使用這個方法之外都沒有仔細(xì)琢磨過這個方法。于是乎,找到了kill time的事情-寫博客。

基礎(chǔ)知識簡介

隨便看看資料發(fā)現(xiàn)這玩意其實不簡單,理解起來需要不少基礎(chǔ)知識,在這里羅列一些,也算是一個總結(jié)和復(fù)習(xí)。

函數(shù)

下面這段話來自《JavaScript語言精粹》,名副其實地描述了函數(shù)的精髓。

  

調(diào)用一個函數(shù)會暫停當(dāng)前函數(shù)的執(zhí)行,傳遞控制權(quán)和參數(shù)給新函數(shù)。除了聲明時定義的形式參數(shù),每個函數(shù)還接收兩個附加的參數(shù):this和arguments。參數(shù)this在面向?qū)ο缶幊讨蟹浅V匾闹等Q于調(diào)用的模式。在JavaScript里面一共有四種調(diào)用模式:方法調(diào)用模式、函數(shù)調(diào)用模式、構(gòu)造器調(diào)用模式和apply調(diào)用模式。這些模式在如何初始化關(guān)鍵參數(shù)this上面存在差異。

方法調(diào)用模式

當(dāng)一個函數(shù)被保存為對象的一個屬性時,我們稱它為一個方法。當(dāng)一個方法被調(diào)用的時候,this被綁定到該對象。

var info = {
    name: "yuanzm",
    sayName: function() {
        console.log(this.name);
    }
}
info.sayName();    //yuanzm
函數(shù)調(diào)用模式

當(dāng)一個函數(shù)并非為一個對象的屬性的時候,他就是被當(dāng)做一個函數(shù)來調(diào)用的。此模式調(diào)用函數(shù)的時候,this被綁定到全局對象。這是語言設(shè)計上的一個錯誤。倘若語言設(shè)計正確,this應(yīng)該是綁定到外部函數(shù)的this變量。

var name = "yuanzm"
var sayName = function() {
    console.log(this.name);
}
sayName();// yuanzm
構(gòu)造器調(diào)用模式

如果在一個函數(shù)前面帶上new來調(diào)用,那么背地里將會創(chuàng)建一個連接到該函數(shù)的prototype成員的新對象,同時this會被綁定到新對象上。(JavaScript原型相關(guān)知識這里不做贅述)

function Info(name) {
    this.name = name;
}
Info.prototype.sayName = function() {
    console.log(this.name);
}
var info = new Info("yuanzm");
info.sayName();//yuanzm
Apply調(diào)用模式

根據(jù)MDN的定義

  

The apply() method calls a function with a given this value and arguments provided as an array (or an array-like object).

var numbers = [5, 6, 2, 3, 7];
var max = Math.max.apply(null, numbers);
類數(shù)組

一個類數(shù)組被定義為:

具有:指向?qū)ο笤氐臄?shù)字索引下標(biāo)以及 length 屬性告訴我們對象的元素個數(shù)

不具有:諸如 push 、 forEach 以及 indexOf 等數(shù)組對象具有的方法

符合上述定義的類數(shù)組是長下面這樣子的:

var my_object = {
    "0": "zero",
    "1": "one",
    "2": "two",
    "3": "three",
    "4": "four",
    length: 5
};

前面提到的arguments也是類數(shù)組。很多時候,處理類數(shù)組最省事的方法就是將它轉(zhuǎn)化成數(shù)組。那么就涉及到一個非常有意思的話題:將類數(shù)組轉(zhuǎn)換成數(shù)組。
將類數(shù)組轉(zhuǎn)換成數(shù)組非常簡單,調(diào)用Array自帶的方法即可:

Array.prototype.slice.call(arguments);

其中call換成apply也是一樣的。
簡單解釋一下,slice方法常規(guī)的調(diào)用方式為array.slice(start, end),會對array中的一段做淺復(fù)制,首先復(fù)制array[start], 一直復(fù)制到array[end]。前面提到過apply(或call)會切換一個函數(shù)調(diào)用的上下文,也就是Array.prototype.slice.call(arguments);手動綁定了需要操作的array為arguments,由于arguments和數(shù)組一樣具有下標(biāo),所以這個方法也是可行的,因而產(chǎn)生了一個新的數(shù)組,這個數(shù)組具有普通數(shù)組的所有方法,同時具有arguments每一個下標(biāo)對應(yīng)的值。

bind 簡介

前面說了這么多,主角終于登場了!不過為了凸顯它的作用,還是需要拋出一段達(dá)不到我們需求的代碼。

var name = "yuan"
var info = {
    name: "yuanzm",
    sayName: function() {
        console.log(this.name);
    }
}
var sayName = info.sayName;
// 我們本身是希望得到y(tǒng)uanzm的,但是確得到了yuan這個結(jié)果。為什么會得到這個結(jié)果,前面的長篇大論起作用了。
// 如果是采用info.sayName()這種調(diào)用方式,符合函數(shù)的方法調(diào)用模式,函數(shù)內(nèi)部的this是info對象;
// 如果令一個變量sayName為info.sayName,這個時候再調(diào)用函數(shù),就是普通的函數(shù)調(diào)用模式了,結(jié)果自然為yuan。
sayName();    // yuan 

那么我們使用bind就是希望最后得到的結(jié)果為yuanzm

現(xiàn)在我們可以好好介紹bind了。根據(jù)MDN的定義:

  

The bind() method creates a new function that, when called, has its this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called.

翻譯過來就是,bind()方法會創(chuàng)建一個新函數(shù),稱為綁定函數(shù).當(dāng)調(diào)用這個綁定函數(shù)時,綁定函數(shù)會以創(chuàng)建它時傳入 bind()方法的第一個參數(shù)作為 this,傳入 bind() 方法的第二個以及以后的參數(shù)加上綁定函數(shù)運行時本身的參數(shù)按照順序作為原函數(shù)的參數(shù)來調(diào)用原函數(shù)。
他的語法是:

fun.bind(thisArg[, arg1[, arg2[, ...]]]);
解決問題

有了bind,上述問題我們就能夠得到想要的結(jié)果了:

var name = "yuan"
var info = {
    name: "yuanzm",
    sayName: function() {
        console.log(this.name);
    }
}
var sayName = info.sayName.bind(info);
sayName();    // yuanzm

bind的用法在MDN上面描述得很詳細(xì),本文的目的也不是為了照搬MDN,所以這里有關(guān)bind使用的部分就到這兒,接下來我們?nèi)タ纯碕avascript庫中bind的實現(xiàn)

Prototype中的bind

很久之前Prototype的bind寫法是下面這樣的(注釋為本人所加):

Function.prototype.bind = function(){ 
    // bind作為Function的prototype屬性,每一個函數(shù)都具有bind方法,其中的this指向調(diào)用該方法的函數(shù)(也即一個函數(shù)對象實例)
    var fn = this;
    // 前面說過,這個方法是為了將類數(shù)組轉(zhuǎn)換成數(shù)組
    var args = Array.prototype.slice.call(arguments);
    // 數(shù)組的shift方法會移除數(shù)組的第一個元素,在bind方法的參數(shù)里面,第一個參數(shù)就是需要綁定this的對象
    var object = args.shift();
    return function(){ 
        return fn.apply(object,
        // 現(xiàn)在的args是移除了最初參數(shù)中第一個參數(shù)后的數(shù)組,也就是新函數(shù)的預(yù)設(shè)的初始參數(shù)。
        // array.concat(items...)方法產(chǎn)生一個新數(shù)組,它包含一份array的淺復(fù)制,并把一個或者多個參數(shù)item附加在其后。
        // 如果參數(shù)item是一個數(shù)組,那么它的元素會被分別添加。
        // 于是這一行代碼產(chǎn)生了一個參數(shù)數(shù)組,這個數(shù)組由預(yù)設(shè)的初始參數(shù)(如果存在)和新傳遞的參數(shù)組成。
        args.concat(Array.prototype.slice.call(arguments))); 
    }; 
};

在最新的版本1.7.2(2015.06.23查閱官網(wǎng))中https://github.com/sstephenson/prototype/blob/master/src/prototype/lan...,bind是下面這樣子的:

function bind(context) {
    if (arguments.length < 2 && Object.isUndefined(arguments[0]))
        return this;

    if (!Object.isFunction(this))
        throw new TypeError("The object is not callable.");

    var nop = function() {};
    var __method = this, args = slice.call(arguments, 1);

    var bound = function() {
        var a = merge(args, arguments);
        // Ignore the supplied context when the bound function is called with
        // the "new" keyword.
        var c = this instanceof bound ? this : context;
        return __method.apply(c, a);
    };

    nop.prototype   = this.prototype;
    bound.prototype = new nop();

    return bound;
}

可見,除了加了一些異常情況判斷,核心代碼和之前并無大差別。

結(jié)語

總得來說apply、call和bind都是為了手動綁定this對象,目的上沒有什么區(qū)別。但是bind和另外兩者的明顯的區(qū)別是,bind會產(chǎn)生一個新的函數(shù),這個函數(shù)還可以有預(yù)設(shè)的參數(shù),這在很多時候會比apply和call更加好用。合理利用apply、call和bind會使得javaScript代碼更加優(yōu)雅。

參考資料

[1] Function.prototype.apply()
[2] JavaScript 的怪癖 8:“類數(shù)組對象”
[3] how does Array.prototype.slice.call() work?
[4] JavaScript’s Apply, Call, and Bind Methods are Essential for JavaScript Professionals

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/85752.html

相關(guān)文章

  • Laravel深入學(xué)習(xí)2 - 控制反轉(zhuǎn)容器

    摘要:控制反轉(zhuǎn)容器控制反轉(zhuǎn)使依賴注入變得更加便捷。有瑕疵控制反轉(zhuǎn)容器是實現(xiàn)的控制翻轉(zhuǎn)容器的一種替代方案。容器的獨立使用即使沒有使用框架,我們?nèi)匀豢梢栽陧椖恐惺褂冒惭b組件來使用的控制反轉(zhuǎn)容器。在沒有給定任何信息的情況下,容器是無法實例化相關(guān)依賴的。 聲明:本文并非博主原創(chuàng),而是來自對《Laravel 4 From Apprentice to Artisan》閱讀的翻譯和理解,當(dāng)然也不是原汁原味...

    worldligang 評論0 收藏0
  • Python爬蟲建站入門手記——從零開始建立采集站點(二:編寫爬蟲)

    摘要:接上回第二部分,編寫爬蟲。進(jìn)入微信嵌套選擇圖片和上傳圖片接口,實現(xiàn)一鍵上傳圖片,遇到問題看吧,我現(xiàn)在已經(jīng)可以通過爬蟲獲取的提問標(biāo)題了。微信故意省略想做小偷站的,看到這里基本上就能搞出來了。下一篇,采集入庫 上回,我裝了環(huán)境 也就是一對亂七八糟的東西 裝了pip,用pip裝了virtualenv,建立了一個virtualenv,在這個virtualenv里面,裝了Django,創(chuàng)建了一個...

    Codeing_ls 評論0 收藏0

發(fā)表評論

0條評論

閱讀需要支付1元查看
<