javascript 原生bind方法實現

來源:互聯網
上載者:User

標籤:lan   apply   就是   error   script   簡單   def   bar   rgs   

bind方法可以用來給一個方法綁定上下文環境對象,以及重新給方法傳參數。
bind的另一個簡單使用是使一個函數擁有預設的初始參數。我們稱為偏函數

function list() {  return Array.prototype.slice.call(arguments);}var list1 = list(1, 2, 3); // [1, 2, 3]// Create a function with a preset leading argumentvar leadingThirtysevenList = list.bind(undefined, 37);var list2 = leadingThirtysevenList(); // [37]var list3 = leadingThirtysevenList(1, 2, 3); // [37, 1, 2, 3]

由於bind方法在並不是在所有的瀏覽器上都支援,因此我們考慮自己實現bind方法。
首先我們可以給目標函數指定範圍來簡單實現bind

Function.prototype.bind = function(context){    self = this;    return function(){        return self.apply(context, arguments);    }}

這樣實現的bind方法就只能接受一個上下文環境變數的參數,不能同時接受參數。因此我們修改一下。

Function.prototype.bind = function(context){    var slice = Array.prototype.slice,        _args = slice.call(arguments,1),        self = this;    return function(){        var _inargs = slice.call(arguments);        return self.apply(context, _args.concat(_inargs));    }}

現在bind可以綁定對象,同時也能在綁定對象時傳遞參數。
但是bind還有一個特點:

一個綁定函數也能使用new操作符建立對象:這種行為就像把原函數當成構造器。提供的 this 值被忽略,同時調用時的參數被提供給類比函數。
並看不懂什麼意思 = = 其實就是bind返回的函數還能用做建構函式。bind 時指定的 this 值會失效,但傳入的參數依然生效。

舉個例子:

var value = 2;var foo = {    value: 1};function bar(name, age) {    this.habit = ‘shopping‘;    console.log(this.value);    console.log(name);    console.log(age);}bar.prototype.friend = ‘kevin‘;var bindFoo = bar.bind(foo, ‘daisy‘);var obj = new bindFoo(‘18‘);// undefined// daisy// 18console.log(obj.habit);console.log(obj.friend);// shopping// kevin

我們可以通過修改函數的返回原型來實現,代碼如下:

Function.prototype.bind = function(context){    var slice = Array.prototype.slice,        _args = slice.call(arguments,1),        self = this,        fBound = function(){            var _inargs = slice.call(arguments);            // 當作為建構函式時,this 指向執行個體,此時結果為 true,將綁定函數的 this 指向該執行個體,可以讓執行個體獲得來自綁定函數的值            // 以上面的是 demo 為例,如果改成 `this instanceof fBound ? null : context`,執行個體只是一個Null 物件,將 null 改成 this ,執行個體會具有 habit 屬性            // 當作為普通函數時,this 指向 window,此時結果為 false,將綁定函數的 this 指向 context            return self.apply((this instanceof fBound ? this : context), _args.concat(_inargs));        };        // 修改返回函數的 prototype 為綁定函數的 prototype,執行個體就可以繼承綁定函數的原型中的值        fBound.prototype = self.prototype;        return fBound;}

bound.prototype = this.prototype這麼寫的話,修改返回函數原型對象(bound.prototype)的同時把綁定函數的原型對象(this.prototype也同時修改了。因此用匿名函數做中轉,this.protptype 就安全了。
還有幾個小問題的解決:

  • 調用bind不是函數
  • bind相容性的問題
    最終的完整代碼如下:
fakeBind = function (context) {    if (typeof this !== "function") {        throw new Error("Function.prototype.bind - what is trying to be bound is not callable");    }    var slice = Array.prototype.slice,        _args = slice.call(arguments, 1),        self = this,        F = function () {},        bound = function () {            var _inargs = slice.call(arguments);            return self.apply((this instanceof F ? this : context), _args.concat(_inargs));        };    F.prototype = self.prototype;    bound.prototype = new F();    return bound;}Function.prototype.bind = Function.prototype.bind || fakeBind;
ES6版實現
Function.prototype.fakeBindES6 = function(context, ...rest) {  if (typeof this !== "function") {    throw new Error("Bind must be called on a function");  }  var self = this;  return function inner(...args) {    if (this instanceof inner) {      // 當返回的內層函數作為建構函式使用,bind 時綁定的 this 失效。      // 即此處直接執行綁定函數,而不使用 apply 對 this 進行綁定       return new self(...rest, ...args);    }    // 當作為普通函數調用,this 指向傳入的對象    return self.apply(context, rest.concat(args));  };};

Github: https://github.com/Vxee/articles/issues/7

javascript 原生bind方法實現

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.