亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

bind方法的javascript實(shí)現(xiàn)及函數(shù)柯里化

Tamic / 3194人閱讀

摘要:而模擬的方法返回的函數(shù)用作構(gòu)造函數(shù)時(shí),生成的對(duì)象為。同樣,使用運(yùn)算符時(shí),綁定構(gòu)造函數(shù)和未綁定構(gòu)造函數(shù)并無兩樣。標(biāo)準(zhǔn)的方法創(chuàng)建一個(gè)新函數(shù)稱為綁定函數(shù),新函數(shù)與被調(diào)函數(shù)綁定函數(shù)的目標(biāo)函數(shù)具有相同的函數(shù)體在規(guī)范中內(nèi)置的屬性。

這是一道面試題,題目給出了使用bind方法的樣例,要求用javascript實(shí)現(xiàn)這個(gè)方法,面試官還很善意的提醒我函數(shù)柯里化,然而,我還是不會(huì)這道題目,所以回來這會(huì)《javacript權(quán)威指南》和《javacript 高級(jí)教程》開始學(xué)習(xí)相關(guān)知識(shí)。

一、javacript實(shí)現(xiàn)bind方法

bind()是在ECMAScript5中新增的方法,但是在ECMAScript3中可以輕易的模擬bind()。

版本一

這部分參考了《javacript權(quán)威指南》權(quán)威指南的p191ECMAScript3版本的Function.bind()方法的實(shí)現(xiàn)。

if(!Function.prototype.bind){
    Function.prototype.bind = function(o){
        // 將`this`和`arguments`的值保存在變量中,以便在后面嵌套的函數(shù)中可以使用它們
        var self = this,
            boundArgs = arguments;
        //bind方法的返回值是一個(gè)函數(shù)
        return function(){
            var args = [],//創(chuàng)建一個(gè)實(shí)參列表,將傳入的bind()的第二個(gè)及后續(xù)的實(shí)參都傳入這個(gè)函數(shù)。
                i;
            for(i=1;i
版本一存在的問題

上述ECMAScript3版本的Function.bind()方法和ECMAScript5中定義的bind()有些出入,主要有以下三個(gè)方面。

真正的bind()方法(ECMAScript5中定義的bind())返回一個(gè)函數(shù)對(duì)象,這個(gè)函數(shù)對(duì)象的length屬性是綁定函數(shù)的形參個(gè)數(shù)減去綁定實(shí)參的個(gè)數(shù)。而模擬的bind()方法返回的函數(shù)對(duì)象的length屬性的值為0.

真正的bind()方法可以順帶用作構(gòu)造函數(shù),此時(shí)將忽略傳入bind()this,原始函數(shù)就會(huì)以構(gòu)造函數(shù)的形式調(diào)用,其實(shí)參也已經(jīng)綁定。而模擬的bind()方法返回的函數(shù)用作構(gòu)造函數(shù)時(shí),生成的對(duì)象為Object()。

真正的bind()方法所返回的函數(shù)并不包含prototype屬性(普通函數(shù)固有的prototype屬性是不能刪除的),并且將這些綁定的函數(shù)用作構(gòu)造函數(shù)時(shí)所創(chuàng)建的對(duì)象從原始的未綁定的構(gòu)造函數(shù)中繼承prototype。同樣,使用instanceof運(yùn)算符時(shí),綁定構(gòu)造函數(shù)和未綁定構(gòu)造函數(shù)并無兩樣。

版本二

針對(duì)上述ECMAScript3版本的Function.bind()方法存在的問題,《JavaScript Web Application》一書中給出的版本有針對(duì)性的修復(fù)了這些問題。

Function.prototype.bind = function(context){
    var args = Array.prototype.slice.call(arguments,1),//要點(diǎn)3
        self = this,
        F = function(){};//要點(diǎn)1
        bound = function(){
            var innerArgs = Array.prototype.slice.call(arguments);
            var finalArgs = args.concat(innerArgs);
            return self.apply((this instanceof F ? this : context),finalArgs);//要點(diǎn)2
        };
        F.prototype = self.prototype;
        bound.prototype = new F();
        return bound;
}

要點(diǎn)1,解釋

如下這段代碼,實(shí)際上用到了原型式繼承。這跟ECMAscript5中的Object.creat()方法只接受一個(gè)參數(shù)時(shí)是一樣的。

F = function(){};//要點(diǎn)1
...
F.prototype = self.prototype;
bound.prototype = new F();

要點(diǎn)2,解釋

如下這段代碼,是要判斷通過bind方法綁定得到的函數(shù),是直接調(diào)用還是用作構(gòu)造函數(shù)通過new來調(diào)用的。

this instanceof F ? this : context

為了分析這段代碼的具體含義,需要知道通過構(gòu)造函數(shù)生成對(duì)象時(shí),new操作符都干了啥。比如如下代碼:

var a = new B()

(1).首先創(chuàng)建一個(gè)空對(duì)象,var a = {};
(2).將構(gòu)造函數(shù)的作用域賦給新對(duì)象(因此,this就指向了這個(gè)新對(duì)象);
(3).執(zhí)行構(gòu)造函數(shù)中的代碼(為這個(gè)新對(duì)象添加屬性), B.call(a);
(4).繼承被構(gòu)造函數(shù)的原型,a._proto_ = B.prototype;
(5).返回這個(gè)新對(duì)象。

標(biāo)準(zhǔn)的bind方法

創(chuàng)建一個(gè)新函數(shù)(稱為綁定函數(shù)),新函數(shù)與被調(diào)函數(shù)(綁定函數(shù)的目標(biāo)函數(shù))具有相同的函數(shù)體(在 ECMAScript 5 規(guī)范中內(nèi)置的call屬性)。當(dāng)目標(biāo)函數(shù)被調(diào)用時(shí)this值綁定到bind()的第一個(gè)參數(shù),該參數(shù)不能被重寫。綁定函數(shù)被調(diào)用時(shí),bind() 也接受預(yù)設(shè)的參數(shù)提供給原函數(shù)。一個(gè)綁定函數(shù)也能使用new操作符創(chuàng)建對(duì)象:這種行為就像把原函數(shù)當(dāng)成構(gòu)造器。提供的this值被忽略,同時(shí)調(diào)用時(shí)的參數(shù)被提供給模擬函數(shù)。

通過原型鏈的繼承可以判斷綁定函數(shù)是否用作了構(gòu)造函數(shù),通過new操作符來調(diào)用。假設(shè)目標(biāo)函數(shù)為funObj,綁定函數(shù)為funBind.即

var funBind = funObj.bind(context);
var obj = new funBind();

上面代碼具有如下繼承關(guān)系(這里畫出繼承關(guān)系圖更容易理解):

obj instanceof funBind // true

funBind.prototype instanceof F //true

F.prototype = self.prototyep

a instanceof B原理,是判斷B.prototype是否存在于a的原型鏈中。因此有

obj instanceof F // true

此外,要點(diǎn)2這里還用到了借用構(gòu)造函數(shù)來實(shí)現(xiàn)繼承,如下代碼

self.apply(this,finalArgs)

要點(diǎn)3,解釋

這里實(shí)際上是將類數(shù)組對(duì)象轉(zhuǎn)化為數(shù)組,因?yàn)轭悢?shù)組對(duì)象,比如arguments、nodelist;雖然很像數(shù)組,比如具有length屬性,但是不是數(shù)組,比如,沒有concat、slice這些方法.

常用的將類數(shù)組對(duì)象轉(zhuǎn)為數(shù)組的方法有

(1).Array.prototype.slice.call
(2).擴(kuò)展運(yùn)算符...,比如[...arguments]
(3). Array.from();

版本二測(cè)試

測(cè)試1

可見,版本二并沒有解決版本一的問題1和3

測(cè)試2

可見版本二解決了版本一的問題2

版本二的精簡(jiǎn)版

版本二中要點(diǎn)1和要點(diǎn)2看著很不爽,于是,我給精簡(jiǎn)了一下,測(cè)試結(jié)果與版本二相同。

Function.prototype.bind = function(context){
    var args = Array.prototype.slice.call(arguments,1),//要點(diǎn)3
        self = this,
        //F = function(){};//要點(diǎn)1
        bound = function(){
            var innerArgs = Array.prototype.slice.call(arguments);
            var finalArgs = args.concat(innerArgs);
            //return self.apply((this instanceof F ? this : context),finalArgs);//要點(diǎn)2
            return self.apply((this instanceof self ? this : context),finalArgs);//要點(diǎn)2
        };
        //F.prototype = self.prototype;
        //bound.prototype = new F();
        bound.prototype = self.prototype;
        return bound;
}

測(cè)試結(jié)果如下:

二、bind函數(shù)應(yīng)用

關(guān)于bind函數(shù)的應(yīng)用這里只提兩點(diǎn)在我使用這個(gè)方法的時(shí)候,遇到的讓我剛開始比較懵逼仔細(xì)一想還真是這么回事的問題。

一段神奇的代碼
var unBindSlice = Array.prototype.slice;
var bindSlice = Function.prototype.call.bind(unBindSlice);
...

bindSlice(arguments);

測(cè)試一下

這段代碼的作用就是將一個(gè)類數(shù)組對(duì)象轉(zhuǎn)化為真正的數(shù)組,是下面這段代碼的另一種寫法而已

Array.prototype.slice.call(arguments);

將一個(gè)函數(shù)對(duì)象作為bindcontext,這種寫法的作用是,為需要特定this值的函數(shù)創(chuàng)造捷徑。

bind函數(shù)只創(chuàng)建一個(gè)新函數(shù)而不執(zhí)行

私以為這是bindcallapply方法的一個(gè)重要差別,callapply這兩個(gè)方法都會(huì)立即執(zhí)行函數(shù),返回的是函數(shù)執(zhí)行后的結(jié)果。而bind函數(shù)只創(chuàng)建一個(gè)新函數(shù)而不執(zhí)行。

之前看過一段錯(cuò)誤的代碼,就是用apply改變一個(gè)構(gòu)造函數(shù)的this,緊接著又用這個(gè)構(gòu)造函數(shù)創(chuàng)建新對(duì)象,毫無疑問這是錯(cuò)誤的,遺憾的是找不到這段錯(cuò)誤代碼的出處了。

三、函數(shù)柯里化

函數(shù)柯里化是與函數(shù)綁定緊密相關(guān)的一個(gè)主題,它用于創(chuàng)建已經(jīng)設(shè)置好了一個(gè)或者多個(gè)參數(shù)的函數(shù)。函數(shù)柯里化的基本方法與函數(shù)綁定是一樣的:使用一個(gè)閉包返回一個(gè)函數(shù)。

柯里化函數(shù)通常創(chuàng)建步驟如下:調(diào)用另一個(gè)函數(shù)并為它傳入要柯里化的函數(shù)和必要參數(shù)。同樣方式如下:

function curry(fn){
    var args = Array.prototype.slice.call(arguments,1);
    return function(){
        var innerArgs = Array.prototype.slice.call(arguments);
        var finalArgs = args.concat(innerArgs);
        return fn.apply(null, finalArgs);
    };
}

有沒有感到很熟悉,其實(shí)上面bind方法的兩個(gè)實(shí)現(xiàn)版本都用到了函數(shù)柯里化,區(qū)別在于,這里的通用函數(shù)沒用考慮到執(zhí)行環(huán)境。

曾經(jīng)看過一段類似函數(shù)柯里化的代碼,私以為很巧妙,如下:

假如有一個(gè)對(duì)象數(shù)組,想要根據(jù)對(duì)象的某個(gè)屬性來對(duì)其進(jìn)行排序。而傳遞給sort方法的比較函數(shù)只能接受兩個(gè)參數(shù),即比較的值,這樣就無法指定排序的對(duì)象屬性了。如何將需要三個(gè)參數(shù)的函數(shù)轉(zhuǎn)化為滿足要求的僅需要兩個(gè)參數(shù)?要解決這個(gè)問題,可以定義一個(gè)函數(shù),它接收一個(gè)屬性名,然后根據(jù)這個(gè)屬性名創(chuàng)建并返回一個(gè)比較函數(shù),如下:

function createComparisionFunction(property){
    return function(obj1,obj2){
        return obj1[property]-obj2[property];
    };
}
四、參考文獻(xiàn)

1.Javascript中bind()方法的使用與實(shí)現(xiàn).
2.javascript原生一步步實(shí)現(xiàn)bind分析.
3.JS中的bind方法與函數(shù)柯里化.

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/86648.html

相關(guān)文章

  • 【進(jìn)階 6-2 期】深入高階函數(shù)應(yīng)用之柯里

    摘要:引言上一節(jié)介紹了高階函數(shù)的定義,并結(jié)合實(shí)例說明了使用高階函數(shù)和不使用高階函數(shù)的情況。我們期望函數(shù)輸出,但是實(shí)際上調(diào)用柯里化函數(shù)時(shí),所以調(diào)用時(shí)就已經(jīng)執(zhí)行并輸出了,而不是理想中的返回閉包函數(shù),所以后續(xù)調(diào)用將會(huì)報(bào)錯(cuò)。引言 上一節(jié)介紹了高階函數(shù)的定義,并結(jié)合實(shí)例說明了使用高階函數(shù)和不使用高階函數(shù)的情況。后面幾部分將結(jié)合實(shí)際應(yīng)用場(chǎng)景介紹高階函數(shù)的應(yīng)用,本節(jié)先來聊聊函數(shù)柯里化,通過介紹其定義、比較常見的...

    stackvoid 評(píng)論0 收藏0
  • 高階函數(shù)應(yīng)用 —— 柯里與反柯里

    摘要:柯里化通用式上面的柯里化函數(shù)沒涉及到高階函數(shù),也不具備通用性,無法轉(zhuǎn)換形參個(gè)數(shù)任意或未知的函數(shù),我們接下來封裝一個(gè)通用的柯里化轉(zhuǎn)換函數(shù),可以將任意函數(shù)轉(zhuǎn)換成柯里化。 showImg(https://segmentfault.com/img/remote/1460000018998373); 閱讀原文 前言 在 JavaScript 中,柯里化和反柯里化是高階函數(shù)的一種應(yīng)用,在這之前...

    wyk1184 評(píng)論0 收藏0
  • JavaScript 函數(shù)式編程技巧 - 柯里

    摘要:作為函數(shù)式編程語言,帶來了很多語言上的有趣特性,比如柯里化和反柯里化。在一些函數(shù)式編程語言中,會(huì)定義一個(gè)特殊的占位變量。個(gè)人理解不知道對(duì)不對(duì)延遲執(zhí)行柯里化的另一個(gè)應(yīng)用場(chǎng)景是延遲執(zhí)行。不斷的柯里化,累積傳入的參數(shù),最后執(zhí)行。作為函數(shù)式編程語言,JS帶來了很多語言上的有趣特性,比如柯里化和反柯里化。 這里可以對(duì)照另外一篇介紹 JS 反柯里化 的文章一起看~ 1. 簡(jiǎn)介 柯里化(Currying)...

    edgardeng 評(píng)論0 收藏0
  • JavaScript柯里

    摘要:簡(jiǎn)介柯里化,又稱部分求值,是把接收多個(gè)參數(shù)的函數(shù)變成接受一個(gè)單一參數(shù)最初函數(shù)的第一個(gè)參數(shù)的函數(shù),并且返回接受剩余的參數(shù)而且返回結(jié)果的新函數(shù)的技術(shù)。按照作者的說法,所謂柯里化就是使函數(shù)理解并處理部分應(yīng)用。的思想極大地助于提升函數(shù)的復(fù)用性。 簡(jiǎn)介 柯里化(Currying),又稱部分求值(Partial Evaluation),是把接收多個(gè)參數(shù)的函數(shù)變成接受一個(gè)單一參數(shù)(最初函數(shù)的第一個(gè)...

    since1986 評(píng)論0 收藏0
  • Javascript currying柯里詳解

    摘要:面試題實(shí)現(xiàn)結(jié)果,題的核心就是問的的柯里化先說說什么是柯里化,看過許多關(guān)于柯里化的文章,始終搞不太清楚,例如柯里化是把接受多個(gè)參數(shù)的函數(shù)變換成接受一個(gè)單一參數(shù)最初函數(shù)的第一個(gè)參數(shù)的函數(shù),并且返回接受余下的參數(shù)且返回結(jié)果的新函數(shù)的技術(shù)。 面試題:實(shí)現(xiàn)add(1)(2)(3) //結(jié)果 = 6,題的核心就是問的js的柯里化 先說說什么是柯里化,看過許多關(guān)于柯里化的文章,始終搞不太清楚,例如...

    mengbo 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

Tamic

|高級(jí)講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<