【build your own xxx】實現你本身的call和apply

圖片描述

新開一個坑,起名爲【build your xxx】,本身造一些小輪子。
工做中不要重複造輪子,可是以學習的目的去造輪子卻意義重大。
以前貌似在知乎上看到一個問題是說如何使用JavaScript實現它原生的call和apply方法,今天我來實現一番。git

call

首先看看call是幹什麼的,從MDN上扒一張圖:
call
舉個例子github

function showName(gender, age){
    console.log(this.name, " ", gender, " ", age)
}
var obj = {
    name: "亞古"
}
showName.call(obj, "female", 22)// 亞古   female   22

梳理思路
能夠看出來Func.call(obj, arg1, arg2...)實現了這麼幾件事:數組

  1. 以obj.Func的方式調用
  2. 把參數arg1, arg2 ...傳遞給Func
  3. 不對obj和Func形成反作用

實現app

Function.prototype.Zcall = function (othis) {
    othis.fn = this;
    othis.fn();
}
showName.Zcall(obj) // 亞古   undefined   undefined

第一個步驟已經實現了,可是很明顯的是這樣子會對傳入的othis形成反作用,即給othis對象平白無故添加了一個方法,因此:學習

Function.prototype.Zcall = function (othis) {
    othis.fn = this;
    othis.fn();
    delete othis.fn;
}

反作用已經消除了,接下來就是參數的問題,這裏有個問題是參數個數是不定的,貌似能夠使用一個數組來arr保存住arguments裏面的參數,而後再執行othis.fn(arr)。可是,這樣等於說只給fn傳了一個數組參數,並不能達到目的。此時問題轉化爲咱們如何實現像 othis.fn(arguments[0], arguments[1], arguments[2] ...) 這樣的語句呢?
此時能夠想起一個不怎麼經常使用的方法eval
eval
簡單的說就是能夠把字符串解析爲JavaScript語句來執行。
藉助eval,改寫Zcall方法:ui

Function.prototype.Zcall = function (othis) {
    othis.fn = this;
    let args = [];
    for(let i = 1, len = arguments.length;i < len;i++) {
        args.push("arguments[" + i + "]");
    }

    // othis.fn();
    eval("othis.fn(" + args + ")");
    delete othis.fn;
}

其實就是用args把arguments用字符串的方式保存住,而後在eval方法中再把字符串從新解析爲語句。this

apply

同理來實現apply:spa

Function.prototype.Zapply = function (othis) {
    othis.fn = this;
    let argsArr = arguments[1];
    if (!arguments[1]) {
        let args = [];
        for(let i = 0, len = arguments[1].length;i < len;i++) {
            args.push("arguments[1][" + i + "]");
        }

        eval("othis.fn(" + args + ")");
    }else{
        othis.fn();
    }
    
    delete othis.fn;
}

參考資料:
MDN-eval
MDN-apply
JavaScript深刻之call和apply的模擬實現prototype

相關文章
相關標籤/搜索