ECMAScript 5中如何用bind()模拟辅助构造函数?
Set辅助构造函数与bind()的问题解答
先回顾原书中的Set实现与辅助构造函数:
// Definition of Set, taken from chapter 9.6.1 function Set() { this.values = {}; this.n = 0; this.add.apply(this, arguments); } Set.prototype.add = function() { for(var i = 0; i < arguments.length; i++) { var val = arguments[i]; var str = Set._v2s(val); if (!this.values.hasOwnProperty(str)) { this.values[str] = val; this.n++; } } return this; }; Set._v2s = function(val) { switch(val) { case undefined: return 'u'; case null: return 'n'; case true: return 't'; case false: return 'f'; default: switch(typeof val) { case 'number': return '#' + val; case 'string': return '"' + val; default: return '@' + objectId(val); } } function objectId(o) { var prop = "|**objectid**|"; if (!o.hasOwnProperty(prop)) o[prop] = Set._v2s.next++; return o[prop]; } }; Set._v2s.next = 100; // Taken from 9.6.7: auxiliary constructor function SetFromArray(a) { Set.apply(this, a); } SetFromArray.prototype = Set.prototype; var s = new SetFromArray( [1,2,3] ); console.log(s instanceof Set); // => true
针对你提出的问题,解答如下:
一、bind()作为构造函数调用时的特殊行为
当用new操作符调用通过bind()创建的绑定函数时,会触发两个核心特殊逻辑:
- 绑定函数预设的
this值会被忽略,new创建的新实例会成为构造函数内部的this。 - 绑定函数生成的实例会自动继承原构造函数的原型链:实例的
__proto__指向原构造函数的prototype,因此instanceof原构造函数返回true,且能访问原原型上的所有方法。
二、用bind()创建Set的辅助构造函数
原SetFromArray的作用是接收数组,将数组元素作为参数传入Set构造函数,同时保证实例属于Set类型。用bind()实现的正确方式如下:
方式一:适配数组输入的辅助构造函数
function SetFromArray(arr) { // 用bind创建预设参数的绑定函数,new调用时忽略绑定的null,展开数组作为Set的参数 return new (Set.bind(null, ...arr))(); } // 验证效果 const s = new SetFromArray([1,2,3]); console.log(s instanceof Set); // => true console.log(s.n); // => 3(Set构造逻辑正常执行,添加了3个元素)
这里Set.bind(null, ...arr)生成了预设参数的绑定函数,new调用时,绑定的null被忽略,新实例作为this执行Set的构造逻辑,且实例自动继承Set.prototype,无需手动设置原型。
方式二:直接生成复用原参数逻辑的辅助构造函数
如果不需要数组转参数的逻辑,可直接用bind()生成辅助构造函数:
// 直接生成绑定函数,new调用时等价于new Set(...) const SetFromArgs = Set.bind(null); const s = new SetFromArgs(1,2,3); console.log(s instanceof Set); // => true
你之前的尝试写法Set.bind(null).apply(this, a)存在问题:这是直接调用绑定函数而非用new调用,此时绑定的null会生效(严格模式下this为null,非严格模式下为全局对象),导致Set的构造逻辑无法作用在new SetFromArray创建的实例上,反而可能污染全局对象或报错。
三、JavaScript是否能创建辅助构造函数?
完全可以。辅助构造函数本质是封装原构造函数调用逻辑、简化特定场景实例创建的函数,它可以:
- 转换输入参数(比如将数组转为原构造函数需要的多参数)
- 保证实例继承原构造函数的原型链,维持类型一致性
- 按需添加额外初始化逻辑
原书中的SetFromArray就是典型的辅助构造函数,用bind()实现的版本也是合法的辅助构造函数。
内容的提问来源于stack exchange,提问作者Taofeek
相关产品推荐
相关产品推荐

