我是目录
引言
上一篇this关键字的相关问题中,描述了很多this的原理和应用,这一篇查缺补漏,还包括了一些古老用法,大概七八年前常考吧。。。那时候笔试我还做不出来,现在会了,没人考这些了泪目。。。
bind函数实现
先明确一下bind
到底实现了什么:
bind
是用于绑定this指向的。bind
方法会创建一个新函数。当这个新函数被调用时,bind
的第一个参数将作为它运行时的this
,之后的一序列参数将会在传递的实参前传入作为它的参数。
fun.bind(thisArg[, arg1[, arg2[, ...]]])
bind
返回的绑定函数也能使用new
操作符创建对象:这种行为就像把原函数当成构造器。提供的this
值被忽略,同时调用时的参数被提供给模拟函数。
初级实现
了解了以上内容,我们来实现一个初级的bind
函数Polyfill:
Function.prototype.bind = Function.prototype.bind || function (context) {
var me = this;
var argsArray = Array.prototype.slice.call(arguments);
return function () {
return me.apply(context, argsArray.slice(1))
}
}
基本原理是使用apply
进行模拟。函数体内的this
,就是需要绑定this
的实例函数,或者说是原函数。最后我们使用apply
来进行参数(context)绑定,并返回。
同时,将第一个参数(context)以外的其他参数,作为提供给原函数的预设参数,这也是基本的“颗粒化(curring)”基础。
颗粒化(curring)实现
上述的实现方式中,我们返回的参数列表里包含:atgsArray.slice(1)
,他的问题在于存在预置参数功能丢失的现象。
想象我们返回的绑定函数中,如果想实现预设传参(就像bind
所实现的那样),就面临尴尬的局面。真正实现颗粒化的完美方式是:
Function.prototype.bind = Function.prototype.bind || function (context) {
var me = this;
var args = Array.prototype.slice.call(arguments, 1);
return function () {
var innerArgs = Array.prototype.slice.call(arguments);
var finalArgs = args.concat(innerArgs);
return me.apply(context, finalArgs);
}
}
我们注意在上边bind
方法介绍的第三条提到:bind
返回的函数如果作为构造函数,搭配new
关键字出现的话,我们的绑定this
就需要被忽略。
Function.prototype.bind = Function.prototype.bind || function (context) {
var me = this;
var args = Array.prototype.slice.call(arguments, 1);
var F = function () {
};
F.prototype = this<