【问题标题】:Javascript prototype constant declarationJavascript原型常量声明
【发布时间】:2013-07-25 13:24:06
【问题描述】:

我正在使用 RESTful API,我的 Javascript 代码通过 jQuery 的 $.ajax() 调用进行 REST 查询。

我已经实现了一个 javascript Rest 类,我将在下面展示(非常简化):

var Rest = function (baseUrlPath, errorMessageHandler) {
        ...
    };

// Declare HTTP response codes as constants
Rest.prototype.STATUS_OK = 200;
Rest.prototype.STATUS_BAD_REQUEST = 400;

... // other rest methods 

Rest.prototype.post = function (params) {
        $.ajax({
            type: 'POST',
            url: params.url,
            data: params.data,
            dataType: 'json',
            contentType: 'application/json; charset=utf-8',
            beforeSend: this._authorize,
            success: params.success,
            error: params.error || this._getAjaxErrorHandler(params.errorMessage)
        });
        };

... // more rest methods

Rest.prototype.executeScenario = function (scenarioRef) {
        var self = this;

        this.post({
            url: 'myurlgoeshere',
            data: 'mydatagoeshere',
            success: function (data, textStatus, xhr) {
                if (xhr.status == 200) {
                    console.log("everything went ok");
                }
            },
            error: function (xhr, textStatus, errorMsg) {
                // TODO: constants
                if (404 == xhr.status) {
                    self.errorMessageHandler("The scenario does not exist or is not currently queued");
                } else if (403 == xhr.status) {
                    self.errorMessageHandler("You are not allowed to execute scenario: " + scenarioRef.displayName);
                } else if(423 == xhr.status) {
                    self.errorMessageHandler("Scenario: " + scenarioRef.displayName +  " is already in the queue");
                }
            }
        });
    };

代码按预期工作,但是我决定添加一些常量来帮助美化代码并提高可读性。例如,我的代码中有几个地方正在检查 xhr.status == 200 或 xhr.status == 400 等等。

我可以将类变量声明为Rest.prototype.STATUS_OK = 200;

但是变量是可编辑的,我想不出如何使它们保持不变。例如,在我的代码中,我可以执行this.STATUS_OK = 123;,这将修改变量。我玩过 const 关键字,但没有运气。

我看到了这个:Where to declare class constants?,但这并没有多大帮助。

谁能指出我正确的方向,如何使这些字段成为常量而不是变量?

【问题讨论】:

  • 请注意“字段”是属性,而不是变量。对于变量,您只需在支持的情况下使用const keyword。但无论如何你都会在本地范围内:-)

标签: javascript oop


【解决方案1】:

使用 ECMAScript 5 的 Object.defineProperty 可以使值不可设置:

Object.defineProperty(Rest, "STATUS_OK", {
  enumerable: false,   // optional; if you care about your enumerated keys
  configurable: false,
  writable: false,
  value: 200
});

或者,由于这些是默认值,只需执行以下操作:

Object.defineProperty(Rest, "STATUS_OK", { value: 200 });

这使得Rest.STATUS_OK 在访问时产生200,但它不会响应重新定义它或delete 它的尝试。此外,configurable: false 将阻止任何尝试通过随后的 defineProperty 调用重新定义该属性。

但是,这在 older browsers that don't support ES5's defineProperty(尤其是 IE8 及更低版本)中不起作用。

【讨论】:

  • 这是一个很好的解决方法,但似乎必须编写几行代码(我知道它的一个语句,但为了可读性仍然有几行)来设置一个常量。当你有很多常量要声明时,肯定会做很多工作。随着 IE8 及以下版本的逐步淘汰,未来可能会有更好的支持。
  • @Husman:实际上你可以省略除value之外的所有行,因为false是这些行的默认值。
  • @Bergi 好电话;我根据您的建议编辑了我的答案。
  • @Bergi 看起来仍然像个 hack,考虑到您必须调用全局对象和 defineProperty,然后传入您的对象、变量和要设置的属性。大多数语言都有 'var x' 和 'const x' 或类似的东西,即 final (java) 或 #define (C/C++)
  • 我将选择这个作为接受的答案,因为作者和@Bergi 都有一些很好的建议,但是这对我来说目前无法使用,因为代码是企业客户和 IE 支持是必须的。感谢大家的帮助。
【解决方案2】:

这在 Javascript 中是不可能的。您可能会做的最好的事情是创建一些类似于闭包的东西:

var StatusCode = (function() {
    var STATUS_OK = 200,
        STATUS_BAD_REQUEST = 400;

    return {
        getOk: function() {
            return STATUS_OK;
        },
        getBadRequest: function() {
            return STATUS_BAD_REQUEST;
        }
    }

});

并像StatusCode.getOk() === 200 一样使用它。这将帮助您无法更改那些“常量”,但又会不利于您的可读性(这可能是基于意见的)。 我只会将这些常量全部大写以将它们标记为常量,尽管它们可以更改。

【讨论】:

  • +1;此外,没有理由不能简单地用function() { return "something else"; } 覆盖getOk
  • @apsillers 好点。作为底线,您无法安全地保护 javascript 中的任何内容。典型示例 - 甚至可以覆盖 undefined
【解决方案3】:

您可以将状态定义为 getter,但 AFAIK 这在 IE8 和更早版本中不起作用。

var Rest = function (baseUrlPath, errorMessageHandler) {
        this.STATUS_OK = 123; // trying to override.
    };

// Declare HTTP response codes as constants
Rest.prototype = {
    get STATUS_OK(){ return 200; },
    get STATUS_BAD_REQUEST(){ return 400; }
}

var client = new Rest();
console.log( client.STATUS_OK ); // 200!
client.STATUS_OK = 123;
console.log( client.STATUS_OK ); // still 200!

更多关于 getter 和 setter 的信息:http://ejohn.org/blog/javascript-getters-and-setters/

【讨论】:

  • Object.defineProperty(Rest.prototype, "STATUS_OK", {get:function(){return 123;}}); 你出局了 :-)
【解决方案4】:

Javascript 对创建不可变常量没有很好的支持。 甚至不推荐使用 const 关键字,因为它在某些浏览器中不起作用。

我认为最好的方法是使用Object.freeze

Rest.Status = {};
Rest.Status.Ok = "Ok";
Object.freeze(Rest.Status);

Object.freeze 将忽略状态对象中的更改。 举例:

Rest.Status.Ok = "foo";
Rest.Status.Ok; //=> "Ok"

但只能在 ECMAScript 5 或更高版本中工作。

上面我把状态放在了一个Status对象中,我觉得它比prototype更有趣,因为原型更接近实例方法、属性等。 并且 Status 对象看起来像一个枚举。

【讨论】:

  • 请注意,这仍然允许将 Rest.Status 属性重新分配给完全不同的对象。
  • 是的,我没有意识到这一点。一种替代方法是创建一个 RestStatus 对象,但这样会存在两个全局变量:(
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-12-16
  • 2011-06-28
  • 2011-08-07
  • 2011-09-18
  • 2011-03-11
  • 1970-01-01
  • 2016-09-26
相关资源
最近更新 更多