Javascript 从“原型”和“新”转向封闭和曝光模式

Javascript 从“原型”和“新”转向封闭和曝光模式,javascript,design-patterns,closures,prototypal-inheritance,Javascript,Design Patterns,Closures,Prototypal Inheritance,我一直在重新分解其他人的JavaScript代码 之前: function SomeObj(flag) { var _private = true; this.flag = (flag) ? true : false; this.version="1.1 (prototype)"; if (!this._someProperty) this._init(); // leading underscore hints at what shoul

我一直在重新分解其他人的JavaScript代码

之前:

function SomeObj(flag) {
    var _private = true;
    this.flag = (flag) ? true : false;
    this.version="1.1 (prototype)";
    if (!this._someProperty) this._init();
            // leading underscore hints at what should be a 'private' to me
    this.reset(); // assumes reset has been added...
}

SomeObj.prototype.reset = function() {
    /* perform some actions */
}

/* UPDATE */
SomeObj.prototype.getPrivate = function() {
    return _private; // will return undefined
}

/* ...several other functions appended via `prototype`...*/
var SomeObj = function (flag) {
    var _private = true;
    this.flag = (flag) ? true : false;
    this.version = "2.0 (constructor)";

    this.reset = function () {
       /* perform some actions */
    };

    /* UPDATE */
    this.getPrivate = function() {
        return _private; // will return true
    }

    /* other functions and function calls here */
}
之后:

function SomeObj(flag) {
    var _private = true;
    this.flag = (flag) ? true : false;
    this.version="1.1 (prototype)";
    if (!this._someProperty) this._init();
            // leading underscore hints at what should be a 'private' to me
    this.reset(); // assumes reset has been added...
}

SomeObj.prototype.reset = function() {
    /* perform some actions */
}

/* UPDATE */
SomeObj.prototype.getPrivate = function() {
    return _private; // will return undefined
}

/* ...several other functions appended via `prototype`...*/
var SomeObj = function (flag) {
    var _private = true;
    this.flag = (flag) ? true : false;
    this.version = "2.0 (constructor)";

    this.reset = function () {
       /* perform some actions */
    };

    /* UPDATE */
    this.getPrivate = function() {
        return _private; // will return true
    }

    /* other functions and function calls here */
}
对我来说,第一个例子看起来很难阅读,尤其是在更大的背景下。使用
prototype
属性,像这样添加
reset
之类的方法,似乎不太受控制,因为它可能发生在脚本中的任何地方。我的重构代码(上面的第二个示例)看起来更整洁,因此更易于阅读,因为它是自包含的。我通过变量声明获得了一些隐私,但我失去了原型链的可能性

问题:

function SomeObj(flag) {
    var _private = true;
    this.flag = (flag) ? true : false;
    this.version="1.1 (prototype)";
    if (!this._someProperty) this._init();
            // leading underscore hints at what should be a 'private' to me
    this.reset(); // assumes reset has been added...
}

SomeObj.prototype.reset = function() {
    /* perform some actions */
}

/* UPDATE */
SomeObj.prototype.getPrivate = function() {
    return _private; // will return undefined
}

/* ...several other functions appended via `prototype`...*/
var SomeObj = function (flag) {
    var _private = true;
    this.flag = (flag) ? true : false;
    this.version = "2.0 (constructor)";

    this.reset = function () {
       /* perform some actions */
    };

    /* UPDATE */
    this.getPrivate = function() {
        return _private; // will return true
    }

    /* other functions and function calls here */
}
  • 首先,我想知道前面提到的
    prototype
    ,我还损失了什么,或者原型链的损失是否有更大的影响。6岁,但声称使用
    原型
    属性在大规模上比闭包模式更有效

  • 上述两个示例仍将由
    new
    操作符实例化;他们都是“经典”式的构造器。最后,我甚至想从这个模型中转移到一个模型中,在这个模型中,所有的属性和函数都声明为
    var
    s,我有一个方法,我公开了这个方法,它能够返回一个对象,打开我需要的所有属性和方法,这些属性和方法对那些私有的属性和方法具有特权(通过闭包)。大概是这样的:

    var SomeObj = (function () {
    
        /* all the stuff mentioned above, declared as 'private' `var`s */
    
        /* UPDATE */
        var getPrivate = function () {
            return private;
        }
    
        var expose = function (flag) {
             // just returns `flag` for now
             // but could expose other properties
             return {
                 flag: flag || false, // flag from argument, or default value
                 getPrivate: getPrivate
             } 
        };
    
        return {
            expose: expose
        }
    })(); // IIFE
    
    // instead of having to write `var whatever = new SomeObj(true);` use...
    var whatever = SomeObj.expose();
    
    关于StackOverflow,有一些答案可以回答“原型vs.闭包”的问题(例如)。但是,与
    prototype
    属性一样,我感兴趣的是朝着这个方向移动并远离
    new
    操作符对于我的代码效率和任何可能性损失(例如
    instanceof
    丢失)意味着什么。如果我不打算使用原型继承,那么在前面的
    new
    操作符中我真的丢失了什么吗

  • 如果允许的话,我会问一个更宽松的问题,因为我要求的是上面的细节:如果
    原型
    新的
    真的是最有效的方式,比闭包有更多的优势(无论你认为它们可能是什么),那么是否有任何指导方针或设计模式可以更简洁地编写它们

  • 更新: 请注意,
    expose
    每次都返回一个新对象,因此这就是实例化发生的地方。正如我所理解的,当该对象引用在
    SomeObj
    闭包中声明的方法时,它们在所有对象中都是相同的方法(除非被覆盖)。对于
    标志
    变量(我现在已经更正了该变量),可以从
    expose
    的参数继承,使用默认值,或者再次引用封装的预先存在的方法或属性。因此,有一些对象的实例正在生成,这里有一些继承(加上多态性?)

    所以重复问题2:如果我不打算使用原型继承,那么在前面的
    new
    操作符中我真的丢失了什么吗


    非常感谢您迄今为止的回答,这些回答帮助我澄清了问题。

    根据我的经验,不使用
    。prototype
    会丢失的唯一东西是内存-每个对象最终都拥有其中定义的函数对象的自己的副本

    如果您只打算实例化“少量”的对象,那么这不太可能是一个大问题

    关于你的具体问题:

  • 对这篇相关文章的第二点评论非常相关。作者的基准测试是错误的——它测试的是运行一个同时声明四个内部函数的构造函数的开销。它不是测试这些函数的后续性能

  • 您的“闭包和公开”代码示例不是OO,它只是一个带有一些封闭的私有变量的名称空间。因为它不使用
    new
    ,如果您希望从中实例化对象,那么它就没有用了

  • 我不能回答这个问题——“这要看情况”是一个很好的答案

  • 逐项提问:

  • 基本上,在
    prototype
    中使用
    reset
    方法意味着您的构造函数的所有实例都将共享该方法的完全相同的副本。通过在构造函数中创建本地方法,每个实例将有一个方法副本,这将消耗更多内存(如果有很多实例,这可能会成为一个问题)。除此之外,两个版本是相同的;将
    function SomeObj
    更改为
    var SomeObj=function
    仅在父作用域上提升
    SomeObj
    的方式不同。你说你“通过变量声明获得了一些隐私”,但我没有看到任何私有变量

  • 使用您提到的IIFE方法,您将无法检查SomeObj的实例实例是否

  • 不确定这是否回答了您的问题,但也有一个问题,您仍然可以设置原型,但不要使用
    new
    关键字。但是,您将失去拥有构造函数的能力

  • 前面提到的
    原型
    ,我还损失了什么

    我相信有人能提供答案,但我至少要试一试。使用
    原型至少有两个原因:

  • prototype
    方法可以静态使用
  • 它们只创建一次
  • 将方法创建为对象成员意味着为对象的每个实例创建该方法。这意味着每个对象有更多的内存,并且会减慢对象的创建速度(从而提高效率)。人们倾向于说
    prototype
    方法类似于类方法,而成员方法类似于对象方法,但这是非常误导的,因为prototype链中的方法仍然可以使用对象实例