国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

從一道面試題,到“我可能看了假源碼”

rockswang / 1042人閱讀

摘要:返回的綁定函數(shù)也能使用操作符創(chuàng)建對象這種行為就像把原函數(shù)當(dāng)成構(gòu)造器。同時(shí),將第一個(gè)參數(shù)以外的其他參數(shù),作為提供給原函數(shù)的預(yù)設(shè)參數(shù),這也是基本的顆粒化基礎(chǔ)。

今天想談?wù)勔坏狼岸嗣嬖囶},我做面試官的時(shí)候經(jīng)常喜歡用它來考察面試者的基礎(chǔ)是否扎實(shí),以及邏輯、思維能力和臨場表現(xiàn),題目是:“模擬實(shí)現(xiàn)ES5中原生bind函數(shù)”。
也許這道題目已經(jīng)不再新鮮,部分讀者也會(huì)有思路來解答。社區(qū)上關(guān)于原生bind的研究也很多,比如用它來實(shí)現(xiàn)函數(shù)“顆粒化(currying)”,
或者“反顆粒化(uncurrying)”。
但是,我確信有很多細(xì)節(jié)是您注意不到的,也是社區(qū)上關(guān)于這個(gè)話題普遍缺失的。
這篇文章面向有較牢固JS基礎(chǔ)的讀者,會(huì)從最基本的理解入手,一直到分析ES5-shim實(shí)現(xiàn)bind源碼,相信不同程度的讀者都能有所收獲。
也歡迎大家與我討論。

bind函數(shù)究竟是什么?

在開啟我們的探索之前,有必要先明確一下bind到底實(shí)現(xiàn)了什么:
1)簡單粗暴地來說,bind是用于綁定this指向的。(如果你還不了解JS中this的指向問題,以及執(zhí)行環(huán)境上下文的奧秘,這篇文章暫時(shí)就不太適合閱讀)。

2)bind使用語法:

fun.bind(thisArg[, arg1[, arg2[, ...]]])

bind方法會(huì)創(chuàng)建一個(gè)新函數(shù)。當(dāng)這個(gè)新函數(shù)被調(diào)用時(shí),bind的第一個(gè)參數(shù)將作為它運(yùn)行時(shí)的this,之后的一序列參數(shù)將會(huì)在傳遞的實(shí)參前傳入作為它的參數(shù)。本文不打算科普基礎(chǔ),如果您還不清楚,請參考MDN內(nèi)容。

3)bind返回的綁定函數(shù)也能使用new操作符創(chuàng)建對象:這種行為就像把原函數(shù)當(dāng)成構(gòu)造器。提供的this值被忽略,同時(shí)調(diào)用時(shí)的參數(shù)被提供給模擬函數(shù)。

初級實(shí)現(xiàn)

了解了以上內(nèi)容,我們來實(shí)現(xiàn)一個(gè)初級的bind函數(shù)Polyfill:

Function.prototype.bind = function (context) {
    var me = this;
    var argsArray = Array.prototype.slice.call(arguments);
    return function () {
        return me.apply(context, argsArray.slice(1))
    }
}

這是一般“表現(xiàn)良好”的面試者所能給我提供的答案,如果面試者能寫到這里,我會(huì)給他60分。
我們先簡要解讀一下:
基本原理是使用apply進(jìn)行模擬。函數(shù)體內(nèi)的this,就是需要綁定this的實(shí)例函數(shù),或者說是原函數(shù)。最后我們使用apply來進(jìn)行參數(shù)(context)綁定,并返回。
同時(shí),將第一個(gè)參數(shù)(context)以外的其他參數(shù),作為提供給原函數(shù)的預(yù)設(shè)參數(shù),這也是基本的“顆粒化(curring)”基礎(chǔ)。

初級實(shí)現(xiàn)的加分項(xiàng)

上面的實(shí)現(xiàn)(包括后面的實(shí)現(xiàn)),其實(shí)是一個(gè)典型的“Monkey patching(猴子補(bǔ)丁)”,即“給內(nèi)置對象擴(kuò)展方法”。所以,如果面試者能進(jìn)行一下“嗅探”,進(jìn)行兼容處理,就是錦上添花了,我會(huì)給10分的附加分。

Function.prototype.bind = Function.prototype.bind || function (context) {
    ...
}
顆粒化(curring)實(shí)現(xiàn)

上述的實(shí)現(xiàn)方式中,我們返回的參數(shù)列表里包含:atgsArray.slice(1),他的問題在于存在預(yù)置參數(shù)功能丟失的現(xiàn)象。
想象我們返回的綁定函數(shù)中,如果想實(shí)現(xiàn)預(yù)設(shè)傳參(就像bind所實(shí)現(xiàn)的那樣),就面臨尷尬的局面。真正實(shí)現(xiàn)顆粒化的“完美方式”是:

Function.prototype.bind = Function.prototype.bind || function (context) {
    var me = this;
    var args = Array.prototype.slice.call(arguments, 1);
    return function () {
        var innerArgs = Array.prototype.slice.call(arguments);
        var finalArgs = args.concat(innerArgs);
        return me.apply(contenxt, finalArgs);
    }
}

如果面試者能夠給出這樣的答案,我內(nèi)心獨(dú)白會(huì)是“不錯(cuò)啊,貌似你就是我要找的那個(gè)TA~”。但是,我們注意在上邊bind方法介紹的第三條提到:bind返回的函數(shù)如果作為構(gòu)造函數(shù),搭配new關(guān)鍵字出現(xiàn)的話,我們的綁定this就需要“被忽略”。

構(gòu)造函數(shù)場景下的兼容

有了上邊的講解,不難理解需要兼容構(gòu)造函數(shù)場景的實(shí)現(xiàn):

Function.prototype.bind = Function.prototype.bind || function (context) {
    var me = this;
    var args = Array.prototype.slice.call(arguments, 1);
    var F = function () {};
    F.prototype = this.prototype;
    var bound = function () {
        var innerArgs = Array.prototype.slice.call(arguments);
        var finalArgs = args.contact(innerArgs);
        return me.apply(this instanceof F ? this : context || this, finalArgs);
    }
    bound.prototype = new fNOP();
    return bound;
}

如果面試者能夠?qū)懗蛇@樣,我?guī)缀跻o滿分,會(huì)幫忙聯(lián)系HR談薪酬了。當(dāng)然,還可以做的更加嚴(yán)謹(jǐn)。

更嚴(yán)謹(jǐn)?shù)淖龇?/b>

我們需要調(diào)用bind方法的一定要是一個(gè)函數(shù),所以可以在函數(shù)體內(nèi)做一個(gè)判斷:

if (typeof this !== "function") {
  throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
}

做到所有這一切,我會(huì)很開心的給滿分。其實(shí)MDN上有個(gè)自己實(shí)現(xiàn)的polyfill,就是如此實(shí)現(xiàn)的。
另外,《JavaScript Web Application》一書中對bind()的實(shí)現(xiàn),也是如此。

故事貌似要畫上休止符了——

一切還沒完,高潮即將上演

如果你認(rèn)為這樣就完了,其實(shí)我會(huì)告訴你說,高潮才剛要上演。曾經(jīng)的我也認(rèn)為上述方法已經(jīng)比較完美了,直到我看了es5-shim源碼(已適當(dāng)刪減):

bind: function bind(that) {
    var target = this;
    if (!isCallable(target)) {
        throw new TypeError("Function.prototype.bind called on incompatible " + target);
    }
    var args = array_slice.call(arguments, 1);
    var bound;
    var binder = function () {
        if (this instanceof bound) {
            var result = target.apply(
                this,
                array_concat.call(args, array_slice.call(arguments))
            );
            if ($Object(result) === result) {
                return result;
            }
            return this;
        } else {
            return target.apply(
                that,
                array_concat.call(args, array_slice.call(arguments))
            );
        }
    };
    var boundLength = max(0, target.length - args.length);
    var boundArgs = [];
    for (var i = 0; i < boundLength; i++) {
        array_push.call(boundArgs, "$" + i);
    }
    bound = Function("binder", "return function (" + boundArgs.join(",") + "){ return binder.apply(this, arguments); }")(binder);

    if (target.prototype) {
        Empty.prototype = target.prototype;
        bound.prototype = new Empty();
        Empty.prototype = null;
    }
    return bound;
}

看到了這樣的實(shí)現(xiàn),心中的困惑太多,不禁覺得我看了“假源碼”。但是仔細(xì)分析一下,剩下就是一個(gè)大寫的 。。。服!
這里先留一個(gè)懸念,不進(jìn)行源碼分析。讀者可以自己先研究一下。如果想看源碼分析,點(diǎn)擊這篇文章的后續(xù)-源碼解讀。

總結(jié)

通過比對幾版的polyfill實(shí)現(xiàn),對于bind應(yīng)該有了比較深刻的認(rèn)識(shí)。作為這道面試題的考察點(diǎn),肯定不是讓面試者實(shí)現(xiàn)低版本瀏覽器的向下兼容,因?yàn)槲覀冇辛薳s5-shim,es5-sham處理兼容性問題,并且無腦兼容我也認(rèn)為是歷史的倒退。
回到這道題考查點(diǎn)上,他有效的考察了很重要的知識(shí)點(diǎn):比如this的指向,JS的閉包,原型原型鏈功力,設(shè)計(jì)程序上的兼容考慮等等硬素質(zhì)。
在前端技術(shù)快速發(fā)展迭代的今天,在“前端市場是否飽和”“前端求職火爆異常”“前端入門簡單,錢多人傻”的浮躁環(huán)境下,對基礎(chǔ)內(nèi)功的修煉就顯得尤為重要,這也是你在前端路上能走多遠(yuǎn)、走多久的關(guān)鍵。

PS:百度知識(shí)搜索部大前端繼續(xù)招兵買馬,有意向者火速聯(lián)系。。。

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

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/116488.html

相關(guān)文章

  • 一道面試可能了假源碼[2]

    摘要:函數(shù)是這樣子聲明的使用了系統(tǒng)自己的構(gòu)造函數(shù)來聲明,第一個(gè)參數(shù)是,函數(shù)體內(nèi)又。構(gòu)造函數(shù)調(diào)用情況正常方式調(diào)用無窮無盡當(dāng)然,里還歸納了幾項(xiàng)比較簡單,我就不再翻譯了。 上一篇從一道面試題,到我可能看了假源碼中,由淺入深介紹了關(guān)于一篇經(jīng)典面試題的解法。最后在皆大歡喜的結(jié)尾中,突生變化,懸念又起。這一篇,就是為了解開這個(gè)懸念。 如果你還沒有看過前傳,可以參看前情回顧: 回顧1. 題目是模擬實(shí)現(xiàn)ES...

    chanthuang 評論0 收藏0
  • 一道面試可能了假源碼

    摘要:返回的綁定函數(shù)也能使用操作符創(chuàng)建對象這種行為就像把原函數(shù)當(dāng)成構(gòu)造器。同時(shí),將第一個(gè)參數(shù)以外的其他參數(shù),作為提供給原函數(shù)的預(yù)設(shè)參數(shù),這也是基本的顆粒化基礎(chǔ)。 今天想談?wù)勔坏狼岸嗣嬖囶},我做面試官的時(shí)候經(jīng)常喜歡用它來考察面試者的基礎(chǔ)是否扎實(shí),以及邏輯、思維能力和臨場表現(xiàn),題目是:模擬實(shí)現(xiàn)ES5中原生bind函數(shù)。也許這道題目已經(jīng)不再新鮮,部分讀者也會(huì)有思路來解答。社區(qū)上關(guān)于原生bind的研...

    Carson 評論0 收藏0
  • 一道面試可能了假源碼

    摘要:返回的綁定函數(shù)也能使用操作符創(chuàng)建對象這種行為就像把原函數(shù)當(dāng)成構(gòu)造器。同時(shí),將第一個(gè)參數(shù)以外的其他參數(shù),作為提供給原函數(shù)的預(yù)設(shè)參數(shù),這也是基本的顆粒化基礎(chǔ)。 今天想談?wù)勔坏狼岸嗣嬖囶},我做面試官的時(shí)候經(jīng)常喜歡用它來考察面試者的基礎(chǔ)是否扎實(shí),以及邏輯、思維能力和臨場表現(xiàn),題目是:模擬實(shí)現(xiàn)ES5中原生bind函數(shù)。也許這道題目已經(jīng)不再新鮮,部分讀者也會(huì)有思路來解答。社區(qū)上關(guān)于原生bind的研...

    jlanglang 評論0 收藏0
  • 深入理解js

    摘要:詳解十大常用設(shè)計(jì)模式力薦深度好文深入理解大設(shè)計(jì)模式收集各種疑難雜癥的問題集錦關(guān)于,工作和學(xué)習(xí)過程中遇到過許多問題,也解答過許多別人的問題。介紹了的內(nèi)存管理。 延遲加載 (Lazyload) 三種實(shí)現(xiàn)方式 延遲加載也稱為惰性加載,即在長網(wǎng)頁中延遲加載圖像。用戶滾動(dòng)到它們之前,視口外的圖像不會(huì)加載。本文詳細(xì)介紹了三種延遲加載的實(shí)現(xiàn)方式。 詳解 Javascript十大常用設(shè)計(jì)模式 力薦~ ...

    caikeal 評論0 收藏0

發(fā)表評論

0條評論

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