【问题标题】:Is this a JavaScript constructor pattern?这是 JavaScript 构造函数模式吗?
【发布时间】:2015-11-12 17:08:06
【问题描述】:

我一直在我的 JS 代码中使用这种模式:

function Thing() {
    var otherData = {
        // Private variables?
        name : "something"
    }

    var myThing = {
        data: "somedata",
        someFunction: function () {
        console.log(otherData.name);
        }
    }

    return myThing;
}

那么当使用它时:

var thing = Thing();
thing.someFunction();

我在 JS 中看到过构造函数和单例的示例,但我之前没有遇到过这种模式。这种模式有名字吗?这种模式有什么潜在的问题吗?以前我只是使用对象字面量模式,但想通过将其放入闭包中来获取私有变量。

【问题讨论】:

    标签: javascript oop design-patterns


    【解决方案1】:

    这种模式有名字吗?

    它有不同的名字。我听说过的常见的有:

    • 工厂函数
    • maker 函数(Douglas Crockford 是这个词,推广它们并使用)
    • 构建器函数

    为避免混淆,我们不称它们为“构造函数”或“构造函数”,因为该术语专门用于与 new 一起使用的函数,而您的不是。

    (注意:这里的“builder function”与builder pattern [e.g., GoF patterns]无关。那是完全不同的东西。同样,这里的“factory function”与工厂模式并没有真正的关系,但在这种情况下存在重叠,因为工厂模式使用工厂功能。“制造商”的优点是没有潜在的混淆;我确信某处有一些“制造商模式”,但至少在最初的 GoF 书中没有。)

    这种模式有什么潜在的问题吗?

    好吧,所有模式都存在潜在问题。 :-) 不过,这个没有什么特别的问题。

    只是指出它没有的一个问题:有人可能会提到您没有利用具有该模式的原型,但也许您只是不需要具有特定构建器的原型,如果你这样做了,你可以很容易地使用一个:

    var thingProto = {
        method: function() {
            // I'm a shared method
        }
    };
    function buildThing() {
        var otherData = {
            // Private variables?
            name : "something"
        }
    
        var myThing = Object.create(thingProto);
        myThing.data = "somedata";
        myThing.someFunction = function () {
            console.log(otherData.name);
        };
    
        return myThing;
    }
    

    不改变模式。


    作为一种风格说明,通常你不会大写它,因为 JavaScript 中压倒性的约定是大写的函数是 构造函数。所以Thing 可能被称为createThingbuildThing 或只是thing

    【讨论】:

      【解决方案2】:

      构造函数调用模式是在函数调用前加上new 关键字后跟空格。这允许函数充当构造函数,将其原型属性 (ConstructorFunction.prototype) 分配为返回对象的原型属性 (instanceObj.__proto__),并通过 this 关键字修改对象的属性。因此,您使用该函数的方式不是“构造函数模式”。

      使用函数闭包来封装数据通常被称为Module Pattern

      这是 Addy Osmani 书中的相关部分:Learning JavaScript Design Patterns

      模块模式最初被定义为一种同时提供 传统软件中类的私有和公共封装 工程。

      在 JavaScript 中,模块模式用于进一步模拟 类的概念,我们能够同时包含两者 单个对象内的公共/私有方法和变量,因此 将特定部分从全局范围中屏蔽。这会导致什么 减少了我们的函数名称冲突的可能性 与页面上其他脚本中定义的其他功能。

      隐私

      模块模式封装了“隐私”、状态和组织 使用闭包。它提供了一种包装公共和 私有方法和变量,防止碎片泄漏到 全局范围并意外与其他开发人员的冲突 界面。使用这种模式,只返回一个公共 API,保持 闭包中的所有其他内容都是私有的。

      这为我们提供了一个干净的解决方案来屏蔽执行繁重的逻辑 提升,同时只暴露一个界面,我们希望我们的其他部分 应用程序使用。该模式与一个非常相似 立即调用的函数表达式(IIFE - 参见关于 命名空间模式以了解更多信息),除了一个对象是 返回而不是函数。

      应该注意的是,实际上并没有明确的真实意义 JavaScript 中的“隐私”,因为与某些传统语言不同, 它没有访问修饰符。变量在技术上不能 声明为公共或私有,因此我们使用函数范围 模拟这个概念。在模块模式中,变量或方法 声明仅在模块本身内部可用,这要归功于 关闭。返回对象中定义的变量或方法 但是每个人都可以使用。

      【讨论】:

      • 这不是真正的模块模式。是的,它使用相同的底层技术(闭包),但模块模式比 OP 的构建器要大。准确地说,是模块。 :-)
      • @T.J.Crowder 我不明白为什么他的函数的大小应该决定它是否是模块模式。他说:“以前我只是使用对象字面量模式,但想通过将其放入闭包中来获取私有变量。”对我来说,这听起来像是模块模式。
      • 这不是函数的大小,而是它的意图和使用。当您谈论“模块模式”时,您是在暗示您在谈论模块,而不是实例。这就是我们使用术语构建器或工厂函数的原因,因为当我们谈论具有不同用例的事物时。
      • @T.J.Crowder 构建器模式指的是在我读过的每个来源中完全不同的东西。它用于降低构造具有多个动态选项和属性的对象的复杂性。虽然我可以看到工厂模式在这里是如何应用的,但工厂模式是将用户代码与通过工厂接口使用的实际构造函数解耦,允许多态方法分派和通过定义的接口使用创建的对象。注意它与闭包的隐私/封装无关,这是模块模式。
      • 我没有说 builder pattern。我说的是builder function。是的,这两件事之间有很大的不同。同样,我也没有说工厂模式,虽然是的,工厂功能是实现它的一部分。我会说我不是在谈论我的答案中的模式,以防其他人对此感到困惑。
      猜你喜欢
      • 2017-03-17
      • 1970-01-01
      • 2015-03-29
      • 2022-01-09
      • 1970-01-01
      • 2011-03-14
      • 2014-08-25
      • 2011-04-16
      • 1970-01-01
      相关资源
      最近更新 更多