Javascript 如何使用object.create()而不是new创建具有私有成员的对象

Javascript 如何使用object.create()而不是new创建具有私有成员的对象,javascript,design-patterns,prototype-programming,private-members,Javascript,Design Patterns,Prototype Programming,Private Members,编辑:我最终从Bergi的答案中找到了答案 谢谢你,伯吉 pubPrivExample = (function () { return { init : function () { var private; this.setPrivate = function (p) { private = p; }; this.getPrivate = fu

编辑:我最终从Bergi的答案中找到了答案

谢谢你,伯吉

pubPrivExample = (function () {
    return {
        init : function () {
            var private;

            this.setPrivate = function (p) {
                private = p;
            };
            this.getPrivate = function () {
                return private;
            };
        },

        public : "This is public\n"
    };
}());

var a;

a = Object.create(pubPrivExample);
a.init();
a.setPrivate("This is private");

document.write(a.getPrivate());
编辑:我的问题的答案似乎偏离了正轨。我真的对工厂不感兴趣,实际上我宁愿不使用if。我的问题是关于私人国家的。从Bergi的回答和评论中,我想我可以总结出一些东西

待续

编辑:Bergi已经开始回答下面的问题,但遗漏了最重要的部分——私人国家

我花了时间仔细考虑这个想法,但仍然无法在没有工厂的情况下使用Object.create()实现私有状态。但我想说的是错的,Bergi提到了一个解决方案。。。请随意将Bergi的答案作为起点

原创:我试图避免在javascript中出现新的
,这将我带到了一个特殊的地方。我想要私有对象成员,但我不想放弃
object.create()

这是密码

var trackQueue = {};

trackQueue.factory = function () {
    var that, queue;
    that = this;
    queue = [];

    that.push = function (item) {
        queue.push(item);
    };

    that.work = function () {
        document.write(queue + "<br />");
    };

    return {
        work : that.work,
        push : that.push
    };        
};

var a = Object.create( trackQueue.factory() );
a.push("a");
a.push("b");
a.push("c");

var b = Object.create( trackQueue.factory() );
b.push("d");
b.push("e");
b.push("f");

a.work();
b.work();
var trackQueue={};
trackQueue.factory=函数(){
var表示,队列;
那=这个;
队列=[];
that.push=功能(项){
队列。推送(项目);
};
工作=功能(){
document.write(队列+“
”); }; 返回{ 工作:那,工作, 推:推,推 }; }; var a=Object.create(trackQueue.factory()); a、 推动(“a”); a、 推动(“b”); a、 推送(“c”); var b=Object.create(trackQueue.factory()); b、 推送(“d”); b、 推送(“e”); b、 推动(“f”); a、 工作(); b、 工作();
还有一把叉子

init
是否是
factory
方法更惯用/合适的名称

这是不是疯了


仁慈点-javascript不是我的第一语言。

是的,原型上的init方法可能是更合适的名称:

var proto = {
    init: function(args) {
        // setting up private-scoped vars,
        var example = args;
        // privileged methods
        this.accessPrivate = function(){ return example; };
        // and other stuff
        this.public = 5;
    },
    prop: "defaultvalue",
    ...
}

var instance = Object.create(proto);
instance.init();
但是,绝对没有理由不使用带有new关键字的经典构造函数,它将
Object.create
init
调用巧妙地结合在一起

请注意,您正在使用
对象。创建
时绝对没有任何用处。您的工厂模式(完全有效的应用)返回良好的对象。无需为每个继承自它们的对象创建新对象。只要做:

var instance = trackQueue.factory();
如果您喜欢方法名“create”的发音,您可以为工厂使用更惯用的名称:

trackQueueFactory.create = function(args) {...};

编辑:您将工厂模式与原型继承相结合的想法并没有那么错误。然而,所有装配对象从中继承的原型对象需要是静态的,而不是在每次调用时创建一个新的原型对象。您的代码可能如下所示:

var factory = {
    proto: {
        ...
    },
    create: function(args) {
        var product = Object.create(this.proto);
        // set up private vars scoped to the create function
        // privileged methods
        product.doSomethingSpecial = function(){ ... };
        // and other stuff
    }
};

var a = factory.create(...);

我认为这是实现您的要求的明确方式:

var personFactory = function(id, name, age){
    var _id = id;
    var _name = name;
    var _age = age;

    var personPrototype = {
        getId: function(){
            return _id;
        },
        setId: function(id){
            _id = id;
        },
        getName: function(){
            return _name;
        },
        setName: function(name){
            _name = name;
        },
        getAge: function(){
            return _age; 
        },
        setAge: function(age){
            _age = age;
        },
        work: function(){
            document.write(this.toString());
        },
        toString: function(){
            return "Id: " + _id + " - Name: " + _name + " - Age: " + _age;
        }
    };

    return Object.create(personPrototype);
};
用法:

var renato = personFactory(1, "Renato Gama", 25);
console.log(renato.getName()); //logs "Renato Gama"
renato.setName("Renato Mendonça da Gama");
console.log(renato.getName()); //logs "Renato Mendonça da Gama"

如果我没有错的话,这就是模块模式的用法之一。有关更好的解释,请参阅。这也是一篇关于这个主题的好文章。

为什么不想使用
new
?在您的示例中,我如何在init函数中设置私有作用域变量?就像正常情况一样:使用var关键字或函数声明,它们的作用域将被限定到init函数。不,您错了。您犯了与OP相同的错误:完全没有必要使用Object.create on private scope factored objects。我无法理解您的观点,您能澄清一点吗?我不明白为什么它被认为是一个错误。我甚至认为你的第二个代码块和我写的一样,不同于你的原型是工厂的公共成员。我同意你的方法,如果你的工厂对象除了create()之外还有更多的公共函数,为什么不直接返回object literal(“personPrototype”)呢?Object.create在代码中有什么用途?其目的是返回一个实例化的对象,其属性已在工厂中设置(其工作方式类似于构造函数方法)。换句话说,封装初始化逻辑。是的,它在返回“personPrototype”对象时正是这样做的。你知道这是什么吗?