使用ECMAScript 5获取/设置属性并显示模块模式

时间:2015-05-07 22:34:09

标签: javascript properties

根据contrived bit of JavaScript

考虑以下revealing module pattern
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();

有没有办法使用getter和setter方法将moduleName转换为属性,并通过对moduleName的内部引用调用那些getter / setter方法?为了给出一个具体的例子,请考虑以下{ {3}}:

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对替换它。正确?

similarly contrived C# example,但在这种情况下,提问者正在寻找一种方法返回具有getter / setter代码的属性的对象,以便该模块的外部用户拥有其属性通过get / set方法路由的访问。问题中列出了一个解决方案,但所提供的解决方案并不允许模块内部的代码访问该属性而无需直接对变量进行操作,从而绕过了get / set函数。

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

2 个答案:

答案 0 :(得分:3)

你是对的,因为你无法在变量上定义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的简单引用。

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

答案 1 :(得分:0)

一种使用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最糟糕的{{3}}。