ES5
实现 bind
函数如下
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; }复制代码
测试1
var bar = function() { console.log(this.x) }var foo = { x: 3}var func = bar.bind(foo);func(); // 3复制代码
bar
函数绑定foo
中的x
值,然后输出3
bind
函数中最主要的是bound
函数,bound
函数做了哪些事呢?
首先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
对象中。
所以此时直接执行self.call(context)
,返回执行的结果3
,就是我们测试1中的结果。
那什么时候this instanceof bound == true
呢,而且此时还需要使用空函数F
来获取主函数的prototype
,
答案是实例化,什么时候实例化呢?
测试2
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; // undefinednewFunc.name(); // name复制代码
对bar.bind(foo)
进行实例化,此时因为进行了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
赋给新函数,执行新函数,并返回新函数