bind 的深刻淺出

目標:手寫bind

官方定義:

  • 描述: bind()方法建立一個新的函數,在調用時設置this關鍵字爲提供的值。並在調用新函數時,將給定參數列表做爲原函數的參數序列的前若干項。
  • 返回值 : 返回一個原函數的拷貝,並擁有指定的this值和初始參數。

大白話講 第一個參數 就是給this 這個東西 賦值,剩下的參數的意思是 用於bind 生成的新函數的參數,新函數的參數就等於 bind傳入的除了第一個參數的剩下參數,而後再加上新函數本身傳入的參數。瀏覽器

bind特性

  1. bind是函數的方法
  2. bind的第一個參數是this,剩下的參數做爲新函數的前若干項的參數
  3. bind方法返回的是個函數,須要再次調用纔會執行
  4. new的優先級比bind 高 this 不能被改變

手摸手實現bind

if (!Function.prototype.bind) { //若是瀏覽器不兼容 咱們就本身搞一個唄

    Function.prototype.bind = function(oThis){ // oThis 就是傳入的第一個參數 目標 讓它變成this的指向
        if(typeof this != 'function'){
            throw new TypeError("這東西是函數的方法,別的就別用了哈~")
        }
        
        var aArgs = Array.prototype.slice.call(arguments,1), // 第一個參數不是指this嘛,咱們把剩下的參數淺拷貝一份
            fToBind = this, // 這就是咱們的 this , 咱們要把這個this 改一改
            fBound = function() {  // 這東西 就是咱們最後返出去的 新函數 咱們要把它的 1. this改一改 2. 參數改一改
                //this instanceof fBound === true時,說明返回的fBound被當作new的構造函數調用
                //== false的時候說明當作了普通函數來調用,this爲bind的第一個參數
                return fToBind.apply(this instanceof fBound?this:oThis,aArgs.concat(Array.prototype.slice.call(arguments)));
            }
        //原型鏈 再指向 原來this的原型鏈
        fBound.prototype = this.prototype;
        //返回咱們整的這個新函數
        return fBound;
    }
}

複製代碼

這樣看起來 貌似是搞定了,this也改變了,參數也搞定了,原型鏈也搞定了,是否是整完了???實際上 還有個坑app

function fn() {};
var bFn = fn.bind(null);
fn.prototype.value = 1;
console.log(bFn.prototype.value) //1
複製代碼

這是什麼鬼,這怎麼 產生新函數 還把原函數給改了 原型鏈 傳遞的明顯有問題啊 對象按引用傳遞 這樣 咱們用一箇中專的函數來處理這個問題函數

if(!Function.prototype.bind){
    Function.prototype.bind = function(){
        if(typeof this != "function"){
            throw new TypeError("這裏報錯提示")
        }
        var aArgs = Array.prototype.slice.call(arguments,1),
            fToBind = this,
            fNOP = function() {},
            fBound = function() {
                return fToBind.apply(this instanceof fBound?this:oThis,aArgs.concat(Array.prototype.slice(arguments)));
            }
        if(this.prototype){
            fNOP.prototype = this.prototype;
        }
        // 下行的代碼使fBound.prototype是fNOP的實例,所以
        // 返回的fBound若做爲new的構造函數,new生成的新對象做爲this傳入fBound,新對象的__proto__就是fNOP的實例
        fBound.prototype = new fNOP();
        
        //搞定!~
        return fBound;
    }
}
複製代碼
相關文章
相關標籤/搜索