【问题标题】:dynamic keys for object literals in Javascript [duplicate]Javascript中对象文字的动态键[重复]
【发布时间】:2011-09-23 22:35:30
【问题描述】:

好的,所以我正在处理 Nodes 中的一个项目,我遇到了对象文字中的键的一个小问题,我有以下设置:

var required = {
    directories : {
        this.applicationPath                    : "Application " + this.application + " does not exists",
        this.applicationPath + "/configs"       : "Application config folder does not exists",
        this.applicationPath + "/controllers"   : "Application controllers folder does not exists",
        this.applicationPath + "/public"        : "Application public folder does not exists",
        this.applicationPath + "/views"         : "Application views folder does not exists"
    },
    files : {
        this.applicationPath + "/init.js"               : "Application init.js file does not exists",
        this.applicationPath + "/controllers/index.js"  : "Application index.js controller file does not exists",
        this.applicationPath + "/configs/application.js": "Application configs/application.js file does not exists",
        this.applicationPath + "/configs/server.js"     : "Application configs/server.js file does not exists"
    }
}

好吧,你们中的很多人会看到这个并认为它看起来不错,但编译器一直告诉我我缺少一个 :(冒号),我没有,看起来像 +. 都在影响编译器。

现在我相信(不确定),对象字面量是在编译时创建的,而不是在运行时创建的,这意味着动态变量(例如 this.applicationPath 和串联)将不可用 :( :(

在不必重写大量代码的情况下克服此类障碍的最佳方法是什么。

【问题讨论】:

标签: javascript object-literal


【解决方案1】:

ECMAScript2015 支持计算属性名称:

var name = 'key';
var value = 'value';
var o = {
  [name]: value
};
alert("o as json : " + JSON.stringify(o));

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer

【讨论】:

  • 随着时间的推移,这已成为最正确的答案!
  • 确实! @RobertPitt 你能改变这个接受的答案吗?
  • 哇。这对我来说是新事物。完美的。 "Computed property names" ,感谢这个概念。
  • 这是一个更正确的答案,因为它比接受的答案更好地回答了所提出的问题:接受的答案处理绑定对象,而不是对象文字/“内联对象”。
  • 我记得几年前看到这个并认为这是不必要的。它实际上对 Typescript 非常有用,因为它在创建对象时隐式推断类型,并节省了大量丑陋、显式的样板代码。
【解决方案2】:

在 ECMAScript 2015(ed 6)之前,对象文字(ECMAScript 将其称为“对象初始化器”)键必须是以下之一:

  1. 标识符名称
  2. 字符串字面量
  3. 数字文字

所以你不能在初始化程序中使用表达式作为键。自 ECMAScript 2015 起,这已更改(见下文)。您可以使用带有方括号表示法的表达式来访问属性,因此要使用您必须执行的表达式来设置属性:

var required = { directories : {}};
required.directories[this.applicationPath] = "Application " + this.application + " does not exists";
required.directories[this.applicationPath + "/configs"] = "Application config folder does not exists";
...

等等。由于this.applicationPath 被大量重用,最好存储一个引用以帮助提高性能并减少代码量:

var a = this.applicationPath;
var required = { directories : {}};
var rd = required.directories;
rd[a] = "Application " + this.application + " does not exists";
rd[a + "/configs"] = "Application config folder does not exists";
...

编辑

从 ECMAScript 2015(第 6 版)开始,对象初始化器可以使用以下计算键:

[expression]: value

还有属性和方法名称的简写语法。

请参阅MDN: Object InitializerECMAScript Object Initializer

【讨论】:

  • 赞成,因为您引用了标准,以及可以用作关键的确切内容。
  • ECMA 成为 USCMA....?
  • "initializer" 不是以美国为中心的;见quora.com/…
  • @AntonisChristofides——这是美国英语变体所采用的拼写。
  • @RobG 它被美国采用的,但它不是以美国为中心的。它也在英国使用;取决于你是去牛津还是剑桥。 -izer 拼写早于美国。您可以在我之前评论中发布的链接中找到更多信息。
【解决方案3】:

您可以使用括号表示法设置动态键:

required.directories[this.applicationPath + "/configs"] = "Application config folder does not exists";

(当然无论你在哪里定义,this.applicationPath 都必须存在)

但是你需要this.applicationPath 吗?您如何访问这些值?也许您可以从用于访问属性的任何值中删除 this.applicationPath


但如果你需要它:

如果您想避免重复大量代码,可以使用数组来初始化键:

var dirs = ['configs', 'controllers', ...];
var files = ['init.js', 'controllers/index.js', ...];

var required = { directories: {}, files: {} };
required.directories[this.applicationPath] = "Application " + this.application + " does not exists";

for(var i = dirs.length; i--;) {
    required.directories[this.applicationPath + '/' + dirs[i]] = "Application " + dirs[i] + " folder does not exists";
}

for(var i = files.length; i--;) {
    // same here
}

【讨论】:

  • 不需要在密钥中使用它们,但这只是一种偏好,我想改变它,你的方法似乎最合理。
  • 感谢 Felix,我选择了“/config”方法作为键,并在 for 循环中连接,我没有理由在索引中使用变量,但现在已经很晚了,再次感谢芽。
  • 我认为这个答案需要更新以提及computed property names
  • 虽然很冗长,但您可以使用:{ ...Object.defineProperty({}, key, { value, enumerable: true }) },其中键和值是变量,通过定义具有该键和值的对象,以文字对象表示法传播。虽然{ [key]: value } 在支持的情况下会很简洁。
【解决方案4】:

babel 如何将新的 ES6 语法 ({[expression]: value}) 转换为旧的 Javascript 的启发,我了解到您可以使用一个衬里来做到这一点:

var obj = (_obj = {}, _obj[expression] = value, _obj);

例子:

var dynamic_key = "hello";
var value = "world";
var obj = (_obj = {}, _obj[dynamic_key] = value, _obj);

console.log(obj);
// Object {hello: "world"}

(在最新的 Chrome 上测试)

【讨论】:

    【解决方案5】:

    如果您有深层对象结构(例如 Grunt 配置),有时能够使用 Felix 概述的括号表示法返回动态生成的对象键很方便,但内联在对象结构中。这可以通过使用函数在深层对象的上下文中动态返回对象来实现;对于这个问题中的代码,是这样的:

    var required = {
        directories : function() {
            var o = {};
            o[this.applicationPath] = "Application " + this.application + " does not exists";
            o[this.applicationPath + "/configs"] = "Application config folder does not exists";
            o[this.applicationPath + "/controllers"] = "Application controllers folder does not exists";
            o[this.applicationPath + "/public"] = "Application public folder does not exists";
            o[this.applicationPath + "/views"] = "Application views folder does not exists";
            return o;
        }(),
        files : function() {
            var o = {};
            o[this.applicationPath + "/init.js"] = "Application init.js file does not exists";
            o[this.applicationPath + "/controllers/index.js"]  = "Application index.js controller file does not exists";
            o[this.applicationPath + "/configs/application.js"] ="Application configs/application.js file does not exists";
            o[this.applicationPath + "/configs/server.js"]     ="Application configs/server.js file does not exists";
            return o;
        }()
    }
    

    This fiddle 验证了这种方法。

    【讨论】:

      【解决方案6】:

      一个老问题,当时答案是正确的,但时代变了。如果有人在谷歌搜索中找到它,新的 javascript 版本 (ES6) 允许使用表达式作为对象文字的键,如果它们被方括号括起来: var obj={["a"+Math.PI]:42}

      【讨论】:

        【解决方案7】:

        对于对象文字,Javascript/ECMAScript 脚本将键指定为有效的 IdentifierName、字符串文字或数字 credit RobG(甚至是十六进制)。不是表达式,required.applicationPath + "/configs" 就是这样。

        【讨论】:

        • this.applicationPath 不算作有效标识符吗?
        • 也是一个表达式,因为 this 的值要到运行时才能知道。
        • RobertPitt - 不,它是一种表达方式。
        • 请注意,key 可以是 IdentifierName,这与作为标识符不同。如果使用与标识符同名的键(比如变量名),它会创建一个具有该名称的属性,它不会解析标识符并创建一个具有标识符值的属性(否则它将被处理作为一个表达式,它不能)。
        【解决方案8】:

        问题在于使用“this”,因为它不指代任何智能*。 在其中创建带有 applicationPath 的静态文字。

        需要变量={ "applicationPath":"someWhereOverTheRainboW" };

        然后使用

        required.directories={}; required.directories[required.applicationPath + "/configs"]="应用配置文件夹不存在"; ……

        动态填充

        编辑; 我急于提出我的第一个想法,它没有奏效。以上工作现在 - 抱歉!

        * 'this' 关键字非常聪明:) 但它通常指的是窗口对象或元素、已触发的事件或调用的“活动”对象。因此,造成了很多混乱;)

        【讨论】:

        • 你能提供一个你所说的构造类型的例子吗,我刚刚尝试的方式仍然会抛出错误?
        • 添加了你想要的缺失行
        • 感谢您的更新,这就是我假设您的意思,但是当涉及到键时,我仍然遇到错误,抛出的错误是 SyntaxError: Unexpected token 。
        猜你喜欢
        • 2018-12-05
        • 1970-01-01
        • 2018-05-20
        • 2022-01-06
        • 2021-11-02
        • 2023-03-13
        • 2014-07-25
        相关资源
        最近更新 更多