从规范来看,Function.prototype.bind
是如何工做,以及如何来模拟bind操做。react
以下简单示例,普通对象 testObj
内部有一个b函数,接受一个普通参数,若参数为空则输出 this.a
。git
const testObj = { a: 3, b: function(args) { console.log(args || this.a); }, }; testObj.b() testObj.b(23) const c = testObj.b c() c(23) const c1 = testObj.b.bind(testObj, 50) c1(70)
查看结果:github
testObj.b
被从新赋值给 c
后,函数的的执行上下文已经改变,致使输出为 undefined
。经过上面例子,若是采用 bind
后,则能够改变 testObj
的执行上下文,并能够把默认值传递到参数函数列表.app
假若在 testObj.b
内,加入 console.log(arguments)
, 则能够看到以下输出:函数
50 70
bind函数是,Function
原型链上的函数,主要是改变函数执行上下文的同时,能够传入函数参数值,并返回新的函数this
如图是mdn上的定义,es5
bind产生的函数就一个偏函数,就是说使用bind能够参数一个函数,而后接受新的参数。spa
In computer science, partial application (or partial function application) refers to the process of fixing a number of arguments to a function, producing another function of smaller arity.
详细可看: https://github.com/mqyqingfeng/Blog/issues/43
在EcmaScript的规范 15.3.4.5 中以下截图:prototype
bind 方法须要一个或更多参数,thisArg 和(可选的)arg1, arg2, 等等,执行以下步骤返回一个新函数对象: 1. 令 Target 为 this 值 . 2. 若是 IsCallable(Target) 是 false, 抛出一个 TypeError 异常 . 3. 令 A 为一个(可能为空的)新内部列表,它包含按顺序的 thisArg 后面的全部参数(arg1, arg2 等等)。 4. 令 F 为一个新原生 ECMAScript 对象。 5. 依照 8.12 指定,设定 F 的除了 [[Get]] 以外的全部内部方法。 6. 依照 15.3.5.4 指定,设定 F 的 [[Get]] 内部属性。 7. 设定 F 的 [[TargetFunction]] 内部属性为 Target。 8. 设定 F 的 [[BoundThis]] 内部属性为 thisArg 的值。 9. 设定 F 的 [[BoundArgs]] 内部属性为 A。 10. 设定 F 的 [[Class]] 内部属性为 "Function"。 11. 设定 F 的 [[Prototype]] 内部属性为 15.3.3.1 指定的标准内置 Function 的 prototype 对象。 12. 依照 15.3.4.5.1 描述,设定 F 的 [[Call]] 内置属性。 13. 依照 15.3.4.5.2 描述,设定 F 的 [[Construct]] 内置属性。 14. 依照 15.3.4.5.3 描述,设定 F 的 [[HasInstance]] 内置属性。 15. 若是 Target 的 [[Class]] 内部属性是 "Function", 则 a. 令 L 为 Target 的 length 属性减 A 的长度。 b. 设定 F 的 length 自身属性为 0 和 L 中更大的值。 16. 不然设定 F 的 length 自身属性为 0. 17. 设定 F 的 length 自身属性的特性为 15.3.5.1 指定的值。 18. 设定 F 的 [[Extensible]] 内部属性为 true。 19. 令 thrower 为 [[ThrowTypeError]] 函数对象 (13.2.3)。 20. 以 "caller", 属性描述符 {[[Get]]: thrower, [[Set]]: thrower,[[Enumerable]]: false, [[Configurable]]: false}, 和 false 做为参数调用 F 的 [[DefineOwnProperty]] 内部方法。 21. 以 "arguments", 属性描述符 {[[Get]]: thrower, [[Set]]: thrower, [[Enumerable]]: false, [[Configurable]]: false}, 和 false 做为参数调用 F 的 [[DefineOwnProperty]] 内部方法。 22. 返回 F. bind 方法的 length 属性是 1。 Function.prototype.bind 建立的函数对象不包含 prototype 属性或 [[Code]], [[FormalParameters]], [[Scope]] 内部属
规范表达过程简述以下:code
thisArg
以外的其余函数thisArg
新的函数的 this.[[Call]]
, [[Construct]]
, [[HasInstance]]
, 让对象能够被调用[[Function]]
, 并设置新的函数 length
, 新的length值 范围是 0 ~ Target.length
caller
属性,arguments
在bind过程当中,会从新设置
[[Call]]
相关函数内部方法,详细能够看规范。
知道了过程,假若不支持,该如何呢?来,搞一个手工的:
Function.prototype.bind2 = function bind2(thisArgs) { const aArgs = Array.prototype.slice.call(arguments, 1); const fThis = this; const fNOP = function() {}; const fBound = function() { // 这段判断是否是使用bind返回函数继续bind return fThis.apply(this instanceof fBound ? this : fThis, aArgs.concat(Array.prototype.slice.call(arguments))); }; // this === Function.prototype, 保证建立函数的原型链也为undefined if (this.prototype) fNOP.prototype = this.prototype; fBound.prototype = new fNOP(); return fBound; };
咱们实现方法依赖一些属性方法:
并且咱们实现方法有一个问题在于:
prototype
, 不符合规范查看更规范的实现,点击这里
欢迎交流