1. 程式人生 > 實用技巧 >不用es6 實現call, apply, bind

不用es6 實現call, apply, bind

    //簡單模擬Symbol屬性
    function jawilSymbol(obj) {
        var unique_proper = "00" + Math.random();
        if (obj.hasOwnProperty(unique_proper)) {
            // arguments.callee(obj)//如果obj已經有了這個屬性,遞迴呼叫,直到沒有這個屬性
            jawilSymbol(obj)
        } else {
            return unique_proper;
        }
    }

    Function.prototype.myApply 
= function(context) { // 獲取呼叫`myApply`的函式本身,用this獲取,如果context不存在,則為window var context = context || window var fn = jawilSymbol(context); // 保證唯一性 context[fn] = this // 通過arguments獲取引數 var arg = arguments[1] var returnValue = null; if (arg == undefined) { //
沒有傳參直接執行 returnValue = context[fn]() } else { var forStr = 'context[fn]('; for(var i = 0; i < arg.length; i++) { forStr += i == arg.length - 1 ? arg[i] : arg[i] + ',' } forStr += ')'; //得到"context.fn(arg1,arg2,arg3...)"這個字串在,最後用eval執行
returnValue = eval(forStr); //還是eval強大 } // 從上下文中刪除函式引用 delete context.fn return returnValue // 返回 函式的返回值 } // 簡單模擬call函式 Function.prototype.myCall = function(context) { // arguments的第一個引數是要指向的物件 return this.myApply([].shift.myApply(arguments), arguments) } // 簡單模擬bind Function.prototype.bind = Function.prototype.bind || function(context) { if (typeof this !== "function") { throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable"); } var me = this; // 必須使用call不然會出現找不到引數問題 這裡使用的是上面實現的call var args = Array.prototype.slice.myCall(arguments, 1);// 取 除了引數的第一個元素的其它元素 並返回一個新陣列 // 相容建構函式場景 var F = function() {} F.prototype = this.prototype var bound = function() { // 因為bind返回的還是一個函式 可能還會傳參 這裡取出來並返回 var innerArgs = Array.prototype.slice.myCall(arguments) // 把在bind繫結時傳的引數 與 呼叫bind返回的函式傳的參 進行合併 var finalArgs = args.concat(innerArgs) /* * bind返回的函式如果作為建構函式,搭配new關鍵字出現的話,我們的繫結this就需要“被忽略”。 * this instanceof F ? this : context || this * 檢查 this(指呼叫bind的函式)的prototype(原型)是否出現在F例項物件的原型鏈上 * true則存在 使用它自己的this * false不存在 使用傳進來的第一個引數(即context)當this 若context為null則使用this(非嚴格模式下指window) */ return me.myApply(this instanceof F ? this : context || this, finalArgs) } bound.prototype = new F() return bound } // 測試 bind var obj = { name: 'jawil' } function sayHello(age) { return { name: this.name, age: age } } console.log(sayHello.bind(obj,24)()); // {name: "jawil", age: 24}