You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
// 最终版 删除注释 详细注释版请看上文
Function.prototype.bind = Function.prototype.bind || function bind(thisArg){
if(typeof this !== 'function'){
throw new TypeError(this + ' must be a function');
}
var self = this;
var args = [].slice.call(arguments, 1);
var bound = function(){
var boundArgs = [].slice.call(arguments);
var finalArgs = args.concat(boundArgs);
if(this instanceof bound){
if(self.prototype){
function Empty(){}
Empty.prototype = self.prototype;
bound.prototype = new Empty();
}
var result = self.apply(this, finalArgs);
var isObject = typeof result === 'object' && result !== null;
var isFunction = typeof result === 'function';
if(isObject || isFunction){
return result;
}
return this;
}
else{
return self.apply(thisArg, finalArgs);
}
};
return bound;
}
前言
用过
React
的同学都知道,经常会使用bind
来绑定this
。那么面试官可能会问是否想过
bind
到底做了什么,怎么模拟实现呢。先看一下
bind
是什么。从上面的React
代码中,可以看出bind
执行后是函数,并且每个函数都可以执行调用它。眼见为实,耳听为虚。读者可以在控制台一步步点开例子1中的
obj
:因此可以得出结论1:
1、
bind
是Functoin
原型链中Function.prototype
的一个属性,每个函数都可以调用它。2、
bind
本身是一个函数名为bind
的函数,返回值也是函数,函数名是bound
。(打出来就是bound加上一个空格
)。知道了
bind
是函数,就可以传参,而且返回值'bound '
也是函数,也可以传参,就很容易写出例子2:后文统一
bound
指原函数original
bind
之后返回的函数,便于说明。由此可以得出结论2:
1、调用
bind
的函数中的this
指向bind()
函数的第一个参数。2、传给
bind()
的其他参数接收处理了,bind()
之后返回的函数的参数也接收处理了,也就是说合并处理了。3、并且
bind()
后的name
为bound + 空格 + 调用bind的函数名
。如果是匿名函数则是bound + 空格
。4、
bind
后的返回值函数,执行后返回值是原函数(original
)的返回值。5、
bind
函数形参(即函数的length
)是1
。bind
后返回的bound
函数形参不定,根据绑定的函数原函数(original
)形参个数确定。根据结论2:我们就可以简单模拟实现一个简版
bindFn
如果面试官看到你答到这里,估计对你的印象60、70分应该是会有的。
但我们知道函数是可以用
new
来实例化的。那么bind()
返回值函数会是什么表现呢。接下来看例子3:
从例子3种可以看出
this
指向了new bound()
生成的新对象。可以分析得出结论3:
1、
bind
原先指向obj
的失效了,其他参数有效。2、
new bound
的返回值是以original
原函数构造器生成的新对象。original
原函数的this
指向的就是这个新对象。另外前不久写过一篇文章:面试官问:能否模拟实现JS的new操作符。简单摘要:
new做了什么:
所以相当于
new
调用时,bind
的返回值函数bound
内部要模拟实现new
实现的操作。话不多说,直接上代码。
面试官看到这样的实现代码,基本就是满分了,心里独白:这小伙子/小姑娘不错啊。不过可能还会问
this instanceof bound
不准确问题。上文注释中提到
this instanceof bound
也不是很准确,ES6 new.target
很好的解决这一问题,我们举个例子4:instanceof
不准确,ES6 new.target
很好的解决这一问题细心的同学可能会发现了这版本的代码没有实现
bind
后的bound
函数的name
MDN Function.name和length
MDN Function.length。面试官可能也发现了这一点继续追问,如何实现,或者问是否看过es5-shim
的源码实现L201-L335
。如果不限ES
版本。其实可以用ES5
的Object.defineProperties
来实现。es5-shim
的源码实现bind
直接附上源码(有删减注释和部分修改等)
你说出
es5-shim
源码bind
实现,感慨这代码真是高效、严谨。面试官心里独白可能是:你就是我要找的人,薪酬福利你可以和HR
去谈下。最后总结一下
1、
bind
是Function
原型链中的Function.prototype
的一个属性,它是一个函数,修改this
指向,合并参数传递给原函数,返回值是一个新的函数。2、
bind
返回的函数可以通过new
调用,这时提供的this
的参数被忽略,指向了new
生成的全新对象。内部模拟实现了new
操作符。3、
es5-shim
源码模拟实现bind
时用Function
实现了length
。事实上,平时其实很少需要使用自己实现的投入到生成环境中。但面试官通过这个面试题能考察很多知识。比如
this
指向,原型链,闭包,函数等知识,可以扩展很多。读者发现有不妥或可改善之处,欢迎指出。另外觉得写得不错,可以点个赞,也是对笔者的一种支持。
文章中的例子和测试代码放在
github
中bind模拟实现 github。bind模拟实现 预览地址F12
看控制台输出,结合source
面板查看效果更佳。参考
OshotOkill翻译的 深入理解
ES6
简体中文版 - 第三章 函数(虽然笔者是看的纸质书籍,但推荐下这本在线的书)MDN Function.prototype.bind
冴羽: JavaScript深入之bind的模拟实现
《react状态管理与同构实战》侯策:从一道面试题,到“我可能看了假源码”
关于
作者:常以若川为名混迹于江湖。前端路上 | PPT爱好者 | 所知甚少,唯善学。
个人博客
segmentfault
前端视野专栏,开通了前端视野专栏,欢迎关注~掘金专栏,欢迎关注~
知乎前端视野专栏,开通了前端视野专栏,欢迎关注~
github blog,求个
star
^_^~The text was updated successfully, but these errors were encountered: