You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 08:59:50