文章原地址:https://github.com/catchonme/...javascript
ES5
实现 bind
函数以下java
Function.prototype.bind = function(that){ var self = this, args = arguments.length > 1 ? Array.slice(arguments, 1) : null, F = function(){}; var bound = function(){ var context = that, length = arguments.length; if (this instanceof bound){ F.prototype = self.prototype; context = new F; } var result = (!args && !length) ? self.call(context) : self.apply(context, args && length ? args.concat(Array.slice(arguments)) : args || arguments); return context == that ? result : context; }; return bound; }
测试1git
var bar = function() { console.log(this.x) } var foo = { x: 3 } var func = bar.bind(foo); func(); // 3
bar
函数绑定foo
中的x
值,而后输出3github
bind
函数中最主要的是bound
函数,bound
函数作了哪些事呢?segmentfault
首先context
存储传入的that
到context
中,判断this instanceof bound
,那何时this instanceof bound == true
呢?在测试1中的案例中,this instanceof bound
为 false
,打印此时的this
输出Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
,发现是window
对象,由于foo
自己就是在window
对象中。app
因此此时直接执行self.call(context)
,返回执行的结果3
,就是咱们测试1中的结果。函数
那何时this instanceof bound == true
呢,并且此时还须要使用空函数F
来获取主函数的prototype
,post
答案是实例化,何时实例化呢?测试
测试2this
var bar = function() { console.log(this.x) } bar.prototype.name = function(){ this.name = 'name'; } var foo = { x: 3 } var func = bar.bind(foo); var newFunc = new func; // undefined newFunc.name(); // name
对bar.bind(foo)
进行实例化,此时由于进行了new
操做,new
操做作了什么呢,参考new操做符里面到底发生了什么?因此此时的this
为新生成的bound {}
对象,constructor
为bound
函数,因此此时this instanceof bound == true
那为何bar.bind(foo)
把foo
对象传递的时候,没有输出3
而是undefined
呢?也是由于new
操做,当前的上下文已是新生成的newFunc
函数了。并且当this instanceof bound == true
时,会把bar
的prototype
赋给F
函数,而bound
函数返回的是new F
,因此这时bar
的prototype
也赋给newFunc
了。
咱们看看ES6
的操做,结果和上述例子是同样的。
var bar = function() { console.log(this.x) } bar.prototype.name = function(){ console.log('name') } var foo = { x: 3 } var func = bar.bind(foo); func(); // 3 // 实例化 var newFunc = new func; // undefined newFunc.name(); // name
总结:
因此bind
函数总共作了哪几件事呢?
new
操做生成新函数,原函数的prototype
赋给新函数,执行新函数,并返回新函数