JavaScript中用于自定义构造函数的模块模式

JavaScript中用于自定义构造函数的模块模式,javascript,module-pattern,Javascript,Module Pattern,当我有自己的自定义构造函数时,我尝试在JavaScript中应用模块模式。让我们举一个例子: // Assume I need `name` as private function Dog(name){ this.name = name; } 我可以将上述内容改写为: function Dog(name) { let dogName = name; return { getName : function () { retur

当我有自己的自定义构造函数时,我尝试在JavaScript中应用模块模式。让我们举一个例子:

// Assume I need `name` as private
function Dog(name){
    this.name = name;
}
我可以将上述内容改写为:

function Dog(name) {

    let dogName = name;

    return {

        getName : function () {
            return dogName;
        },

        setName : function (name) {
            dogName = name;
        }
    }
}
上面的代码没有正确的
构造函数
属性和
Dog.prototype
,返回的对象的
prototype不匹配

为了解决这个问题,我做了两个修复:

function Dog(name) {

    let dogName = name;

    return {

        // Fix 1
        constructor : Dog,

        getName : function () {
            return dogName;
        },

        setName : function (name) {
            dogName = name;
        }
    }
}


let d2 = new Dog("Tony");
// Fix 2 : This is painful as every time I need to set this up
Object.setPrototypeOf(d2 , Dog.prototype);
正如您所看到的,修复2是痛苦的。每次我必须创建一个对象时,我都需要这样做。 还有更好的办法吗


让我们不要偏离我们的讨论,即getter和setter应该转移到prototype。上面是我正在使用的一个简单示例。

这里的问题是您在“构造函数”中返回一个对象文本,一个对象文本具有
对象
原型。您不应该在构造函数中返回,您应该像在第一个代码段中那样将内容分配给
this

function Dog(name) {

    let dogName = name;

    this.getName = function () {
        return dogName;
    };

    this.setName = function (name) {
        dogName = name;
    };
}
虽然这不是实现类的常见模式,但您甚至没有使用
原型
,因此不清楚为什么
原型对您很重要。显然,这种方法允许您关闭一个变量,使其成为“私有”变量,而使用
原型
是不可能的。但是,这种方法有更多的开销,因为
Dog
的每个实例都有自己的函数用于
getName
setName
,而“私有”变量和方法的标准约定是在它们前面加下划线,以便您可以按预期使用
原型

function Dog(name) {
    this._name = name;
}

Dog.prototype.getName = function () {
    return this._name;
};

Dog.prototype.setName = function (name) {
    this._name = name;
};

免责声明:我不提倡用javascript进行封装。但这里有一些丑陋的方法

如果您想要的只是减少代码重复,那么您可以轻松地在“构造函数”中设置所有内容,使其成为自己的工厂:

function Dog(name) {

    let dogName = name;

    let dog = Object.create(Dog.prototype);

    dog.getName = function () {
        return dogName;
    };

    dog.setName = function (name) {
        dogName = name;
    };

    return dog;
}


let d2 = new Dog("Tony");
如果您还想实际使用原型,可以使用符号来隐藏name属性:

Dog = function() {

    const nameSymbol = Symbol("name");

    function Dog(name) {
        Object.defineProperty(this, nameSymbol, {
            configurable: true,
            enumerable: false,
            writable: true,
            value: name
        });
    }

    Object.assign(Dog.prototype, {
        getName : function () {
            return this[nameSymbol];
        },

        setName : function (name) {
            this[nameSymbol] = name;
        }
    });

    return Dog;
}();

let d2 = new Dog("Tony");
但是符号仍然可以通过
Object.getOwnPropertySymbols
检索。因此,如果您正在寻找一种方法,使不使用getter/setter就无法访问名称,我认为您必须使用
WeakMap

Dog = function() {

    const dogNames = new WeakMap()

    function Dog(name) {
        dogNames.set(this, name);
    }

    Object.assign(Dog.prototype, {
        getName : function () {
            return dogNames.get(this);
        },

        setName : function (name) {
            dogNames.set(this, name);
        }
    });

    return Dog;
}();

let d2 = new Dog("Tony");

您是否愿意使用类而不是函数?您应该使用类,每隔一段时间创建一次类的实例,然后在函数中直接向
这个.prototype
添加属性如何?您甚至没有使用
prototype。
Object.setPrototypeOf(d2,Dog.prototype)
?您已经实现了返回对象的构造函数,对象文本具有
对象
原型,您不应该在构造函数中返回。如果您需要将
名称
设为“私有”,为什么要为其提供
getName
setName
访问器方法?