JavaScript之bind模擬實現javascript
var obj = { value : 1 } function foo(name,age){ console.log(name) console.log(age) console.log(this.value) } var foo1 = foo.bind(obj,'hy') foo1(18)// hy 18 1
模擬實現第一步java
Function.prototype.bind2 = function(context){ var that = this return function(){ return that.apply(context) } }
之因此 returnthat.apply(context) ,是考慮到綁定函數可能有返回值。app
var obj = { value : 1 } function foo(){ return this.value } var foo1 = foo.bind(obj) console.log(foo1()). // 1
傳參的模擬實現函數
var obj = { value : 1 } function foo(name,age){ console.log(this.value) console.log(name) console.log(age) } var Foobind = foo.bind(obj,'hy') Foobind(18)
函數須要傳name和age兩個參數,居然還能夠在bind的時候,只傳一個name,在執行返回的函數的時候,在傳另外一個參數age優化
Function.prototype.bind2 = function(context){ var that = this // 獲取bind2函數從第二個參數到最後一個參數 var args = Array.prototype.slice.call(arguments,1) return function(){ // 這個時候的 arguments 是指bind返回的函數傳入的參數 var bindArgs = Array.prototype.slice.call(arguments) return that.apply(context,args.concat(bindArgs)) } }
構造函數效果的模擬實現this
var value = 2 var obj = { value : 1 } function foo(name,age){ this.name = 'ycl' console.log(this.value)// undefined console.log(name)// hy console.log(age)// 18 } foo.prototype.flag = '1-' var bindFoo = foo.bind(obj,'hy') var bindFoo1 = new bindFoo(18) console.log(bindFoo1.name)// ycl console.log(bindFoo1.flag)// 1-
注意 :儘管在全局和obj 都聲明瞭value值,但最後返回了undefined,說明綁定this失效了。spa
Function.prototype.bind2=function(context){ var that = this var args = Array.prototype.slice.call(arguments,1) var fBound = function(){ var bindArgs = Array.prototype.slice.call(arguments) // 看成爲構造函數時,this 指向實例,此時結果爲true,將綁定函數的this指向該實例,能夠讓實例得到來自綁定函數的值 // 看成爲普通函數時,this 指向window,此時結果爲false,將綁定函數的this指向context return that.apply(this instanceof fBound ? this : context , args.concat(bindArgs)) } // 修改返回函數的 prototype 爲綁定函數的prototype,實例就能夠繼承綁定函數的原型的值 (此例子的綁定函數爲foo) fBound.prototype = this.prototype return fBound }
構造函數效果的優化實現prototype
Function.prototype.bind2 = function(context){ var that = this var args = Array.prototype.slice.call(arguments , 1) var fBound = function(){ var bindArgs = Array.prototype.slice.call(arguments) var fNOP = function(){} // 看成爲構造函數時,this 指向實例,此時結果爲true,將綁定函數的this指向該實例,能夠讓實例得到來自綁定函數的值 // 看成爲普通函數時,this 指向window,此時結果爲false,將綁定函數的this指向context return that.apply(this instanceof fNOP ? this : context , args.concat(bindArgs)) } // 修改返回函數的 prototype 爲綁定函數的prototype,實例就能夠繼承綁定函數的原型的值 (此例子的綁定函數爲foo) fNOP.prototype = this.prototype fBound.prototype = new fNOP() return fBound }
若是調用bind的不是函數咋辦?code
if(typeof this !== 'function'){ throw new Error("Function.prototype.bind - what is trying to be bound is not callable"); }
最後完成版本對象
Function.prototype.bind2 = function(context){ if(typeof this !== 'function'){ throw new Error("Function.prototype.bind - what is trying to be bound is not callable"); } var that = this var args = Array.prototype.slice.call(arguments , 1) var fBound = function(){ var bindArgs = Array.prototype.slice.call(arguments) var fNOP = function(){} // 看成爲構造函數時,this 指向實例,此時結果爲true,將綁定函數的this指向該實例,能夠讓實例得到來自綁定函數的值 // 看成爲普通函數時,this 指向window,此時結果爲false,將綁定函數的this指向context return that.apply(this instanceof fNOP ? this : context , args.concat(bindArgs)) } // 修改返回函數的 prototype 爲綁定函數的prototype,實例就能夠繼承綁定函數的原型的值 (此例子的綁定函數爲foo) fNOP.prototype = this.prototype fBound.prototype = new fNOP() return fBound }