js 自定義 (call,bind)總結

一直以來在看這些手寫自定義方法,其實目的不是看實現結果,而是看過程的思路,從中會學習到一些邏輯的思惟,雖然都是一些簡單的小方法,可是仍是值得咱們一看的。javascript

手寫call

第一個咱們就來看看這個call,可能你們都見慣不慣了,但仍是以call 爲例總結一下,apply 方法思路相同。首先咱們來看看自帶call方法的用途吧...java

var value = 'this is window';
var foo = {
    value : 'this is foo'
}
function bar(name,age){
    console.log(this.value);
}
bar.call(foo);  //this is foo
複製代碼

運行結果是'this is foo' , call函數在這裏修改了bar運行時this的指向,至關於執行了foo.value,因此輸出的是foo對象下的value。那咱們本身封裝的思路就是這樣了:數組

Function.prototype.call2 = function(obj){
    var obj = obj || window;   //若是obj爲null,那麼咱們讓它指向window
    obj.fn = this;
    obj.fn();
    delete obj.fn;  //執行完後接的刪除這個臨時方法
}
var value = 'this is window';
var foo = {
    value : 'this is foo'
}
function bar(name,age){
    console.log(this.value);
}
bar();  //this is window
bar.call1(foo);  //this is foo
複製代碼

在Function的原型上新建方法call2,傳遞第一個參數,也就是須要指向的那個對象,而後this指向當前調用call2 方法的對象,而後執行。 call方法是能夠接收參數的,因此咱們繼續來完善這個方法。app

Function.prototype.call2 = function(obj){
    var obj = obj || window;
    var arr = [];   //臨時建立一個空的數組,來存放傳進來的參數
    obj.fn = this;
    for(var i = 1; i < arguments.length; i++){   //參數第一個是要指向的對象,因此咱們從第二個參數開始循環添加,i=1
        arr.push('arguments['+i+']');
    }
    var result = eval('obj.fn('+arr.join()+')'); 
    delete obj.fn;
    return result;
}
複製代碼

arr 數組存後結果是 ["arguments[1]", "arguments[2]"...],arr.join()把它轉成字符串,因此咱們用到eval 方法,能夠把string字符串裏的內容運行,把結果賦值給result,返回出去。 完整的代碼是這樣的:函數

Function.prototype.call2 = function(obj){
    var obj = obj || window;
    var arr = [];
    obj.fn = this;
    for(var i = 1; i < arguments.length; i++){
        arr.push('arguments['+i+']');
    }
    var result = eval('obj.fn('+arr.join()+')');
        delete obj.fn;
        return result;
}
var value = 'this is window';
var foo = {
    value : 'this is foo'
}
function bar(name,age){
    console.log(this.value);
    console.log(name,age);
}
bar.call2(foo,'fly',30);   //this is foo fly 30
複製代碼

手寫bind方法

這個也和call,apply 方法相似,bind方法返回的是一個綁定this後的函數,而且該函數並無執行,須要手動去調用,而call,apply是當即執行。有了上面的自定義方法call2 ,這裏bing我就簡短來講了,直接上代碼。學習

Function.prototype.bind2 = function(obj){
    if(typeof this!== 'function'){
        return this;
    }
    var arg = Array.prototype.slice.call(arguments,1); //從第二個參數開始截取
    var that = this;  //這裏指向當前調用者,函數
    //建立返回的函數
    function bindFn(){
        var _this = this instanceof bindFn ? this : obj;  // 返回的函數可能涉及到new 操做符調用,因此這裏須要判斷一下,當前的對象 是不是 bindFn對象的實例,不然返回傳進來的對象obj
        return that.apply(_this,arg.concat(Array.prototype.slice.call(arguments)));
    }
    var fn = function(){};  // 建立空的函數,讓這個函數的原型接收當前函數的屬性和方法,而後吧實例賦值給bindFn的原型
    fn.prototype = this.prototype;
    bindFn.prototype = new fn();
    return bindFn;  //最後返回bindFn 函數
}
複製代碼
相關文章
相關標籤/搜索