【问题标题】:Using ECMAScript 5 get/set properties with revealing module pattern使用带有显示模块模式的 ECMAScript 5 获取/设置属性
【发布时间】:2015-05-07 22:34:09
【问题描述】:

在revealing module pattern 的基础上考虑以下contrived bit of JavaScript:

var RevealingModuleSample = function () {
    var moduleName = "DefaultModuleName",

    init = function (name) {
        moduleName = name
    },

    issueAlert = function () {
        alert(moduleName + " module is running");
    }

    return {
        init: init,
        issueAlert: issueAlert
    };
} ();

RevealingModuleSample.init("SampleModule");

RevealingModuleSample.issueAlert();

有没有办法将 moduleName 转换为具有 getter 和 setter 方法的属性并让这些 getter/setter 方法通过对 moduleName 的内部引用来调用?举一个具体的例子,请考虑以下 @ 987654323@:

public class ContrivedCsharpExample
{
    private string _moduleName;

    protected string moduleName
    {
        get {
            // Perhaps some logging code here that records the moduleName was retrieved.
            return this._moduleName;
        }
        set {
            // Some code here that ensure that a valid moduleName was passed.
            this._moduleName = value;
        }
    }

    public void init(string moduleName) {
        this.moduleName = moduleName;
    }

    public void issueAlert() {
        Console.WriteLine(this.moduleName);
    }


    public static void Main()
    {
        var module = new ContrivedCsharpExample();

        module.init("SampleC#Module");
        module.issueAlert();
    }
}

请注意,在类内部,方法正在调用具有 getter/setter 的属性。这允许我们在这些 getter/setter 方法中添加额外的代码,而如果我们只使用类外部可用的属性,“init”和“issueAlert”方法将不得不直接检查字段,以及我们添加的任何逻辑getter/setter 将被绕过。

我看到的问题是,在揭示模块模式中,“moduleName”变量不是对象的属性——它只是当前范围内的变量。因此,您不能只是将其拉出并用 get/set 对替换它。对吧?

There is a related question on StackOverflow,但在这种情况下,提问者正在寻找一种方法来返回一个具有 getter/setter 代码的属性的对象,以便模块的外部用户可以路由他们的属性访问通过 get/set 方法。问题中列出了解决方案,但提供的解决方案不允许模块内部的代码在不直接操作变量的情况下访问该属性,绕过 get/set 函数。

我认为这对于显示模块模式是不可能的,对吗?有没有办法让模块内部的调用通过 get/set 函数路由?

【问题讨论】:

  • 必须使用显示模型模式吗?如果需要,JavaScript 使用关键字this。这对我来说真的不重要。我可以使用它。这只是一个问题。
  • 由于所有这些模块函数都是在本地声明的,getter/setter 无论如何都不能从外部获得,无论如何你都必须抽出变量引用,我建议用简单的函数替换它们调用(不是人为对象上的访问器属性)。

标签: javascript properties


【解决方案1】:

您是正确的,因为您不能在变量上定义 setter/getter。它必须是对象的属性。然后解决方案是将模块的内部转换为对象,同时仍然公开相同的公共 API:

var RevealingModuleSample = function () {

    var self = {

        _moduleName: "DefaultModuleName",

        set moduleName(name) {
            console.log("setting module name: " + name);
            self._moduleName = name;
        },

        get moduleName() {
            return self._moduleName;
        },

        init: function (name) {
            self.moduleName = name;
        },

        issueAlert: function () {
            alert(self.moduleName + " module is running");
        }

    };

    return {
        init: self.init,
        issueAlert: self.issueAlert
    };
}();

RevealingModuleSample.init("SampleModule");
RevealingModuleSample.issueAlert();

暴露对象方法的一个后果是,当调用方法时,this 的上下文或值会丢失。因此在对象内部使用了self,这是对this的简单引用。

我想另一种方法是将所有私有变量存储在一个单独的对象中,但这对我来说似乎不太优雅。

【讨论】:

    【解决方案2】:

    有一种方法可以使用 IIFE 来接近你想要的,尽管我认为这有点矫枉过正。但是,您必须做出妥协——而不是使用属性,您总是必须使用函数:

    var Example = function () {
        var moduleName = (function(moduleName){
        return function(value){
            if (val === undefined) return moduleName;
            moduleName= val;
        };
        })("DefaultModuleName");
    
        init = function (name) {
            moduleName(name);
        },
    
        issueAlert = function () {
            alert(moduleName() + " module is running");
        }
    
        return {
            init: init,
            issueAlert: issueAlert
        };
    } ();
    
    Example.init("SampleModule");
    
    Example.issueAlert();
    

    诀窍是使用 IIFE 返回访问器函数。如果不带参数调用该函数是 getter,如果带参数调用它是 setter。访问器函数改变了 IIFE 闭包中隐藏变量的值,除了访问器函数之外,IIFE 之外的任何东西都无法访问它。

    在这种情况下,揭示模块模式是一个红鲱鱼 - 它与问题没有任何关系,它是 anti-pattern,因为它是 implementations of the module pattern 中最糟糕的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-08-18
      • 2018-07-21
      • 1970-01-01
      • 2021-10-15
      • 2014-05-19
      • 1970-01-01
      • 2019-08-10
      相关资源
      最近更新 更多