使用裸词手动声明JavaScript对象

使用裸词手动声明JavaScript对象,javascript,json,bareword,Javascript,Json,Bareword,我是JavaScript的初学者,正在尝试重构API,但我遇到了一个奇怪的问题 我使用节点解释器来测试我想在重新设计中包含的一些代码,但是我遇到了一些意想不到的行为 考虑输入节点解释器的以下内容: [In0] b 我预期会出现引用错误,如下所示 [Out0] ReferenceError: b is not defined at repl:1:1 at REPLServer.defaultEval (repl.js:132:27) at bound (domain.js:254:14) at

我是JavaScript的初学者,正在尝试重构API,但我遇到了一个奇怪的问题

我使用
节点
解释器来测试我想在重新设计中包含的一些代码,但是我遇到了一些意想不到的行为

考虑输入节点解释器的以下内容:

[In0] b
我预期会出现引用错误,如下所示

[Out0] 
ReferenceError: b is not defined
at repl:1:1
at REPLServer.defaultEval (repl.js:132:27)
at bound (domain.js:254:14)
at REPLServer.runBound [as eval] (domain.js:267:12)
at REPLServer.<anonymous> (repl.js:279:12)
at REPLServer.emit (events.js:107:17)
at REPLServer.Interface._onLine (readline.js:214:10)
at REPLServer.Interface._line (readline.js:553:8)
at REPLServer.Interface._ttyWrite (readline.js:830:14)
at ReadStream.onkeypress (readline.js:109:10)

现在考虑一个JSON样式对象:

 [In2] var x = { 'b' : 'c' };
 [Out2] { b : 'c' }
奇怪的是,引号被放在
x
的键上。我愿意忽略这一点,尽管它令人困惑

最后,

 [In3] var y = { b : 'c' };
 [Out3] { b : 'c' }
没有引号,解释器不会抱怨,并产生与引号相同的结果

我还注意到这个模式,
key
总是作为字符串返回:

for(var key in obj) {
    key;
 }
注意到这种行为,我尝试在类
Foo
中编写一个方法,
Bar
,定义如下:

function Foo(a) {
    this.a = a;
    this.Bar = function(attr, val) {
        // attr doesn't need to be a string to be a key in object x
        var x = { attr : val };
        for(var key in x) {
            //key DOES need to be a string to be used like this
            this[key] = val;
        }
    }
}
本质上,
Bar
只是将
attr:val
的键值对添加到类型为
Foo
的对象中

我尝试使用以下内容测试此代码:

[In4] var foo = new Foo('c');
[Out4] { a : 'c', Bar : [Function] } // this is OK. I expect this.

[In5] foo.Bar(hello, "World");
[Out5]
ReferenceError: hello is not defined
at repl:1:9
at REPLServer.defaultEval (repl.js:132:27)
at bound (domain.js:254:14)
at REPLServer.runBound [as eval] (domain.js:267:12)
at REPLServer.<anonymous> (repl.js:279:12)
at REPLServer.emit (events.js:107:17)
at REPLServer.Interface._onLine (readline.js:214:10)
at REPLServer.Interface._line (readline.js:553:8)
at REPLServer.Interface._ttyWrite (readline.js:830:14)
at ReadStream.onkeypress (readline.js:109:10)
[In4]var foo=new foo('c');
[Out4]{a:'c',Bar:[函数]}//这没问题。我希望这样。
[In5]foo.Bar(你好,“世界”);
[Out5]
ReferenceError:未定义hello
回复:1:9
在REPLServer.defaultEval(repl.js:132:27)
绑定时(domain.js:254:14)
在REPLServer.runBound[as eval](domain.js:267:12)
在服务器上。(回复js:279:12)
在REPLServer.emit上(events.js:107:17)
在REPLServer.Interface.\u在线(readline.js:214:10)
在REPLServer.Interface._行(readline.js:553:8)
在REPLServer.Interface.\u ttyWrite(readline.js:830:14)
在ReadStream.onkeypress(readline.js:109:10)

有人能向noob解释这种行为吗?当可以手动操作时,无法在方法中使用裸字作为键是非常令人沮丧的。

hello
在这里应该是一个表达式,例如,一个引用

事实并非如此,因此失败了

它是一种语法糖,允许使用
{foo:'bar'}
形式。解释器知道您在一个对象声明中,并假装它是一个字符串


(JS没有符号。直到ES6,我忽略了提到。)

hello
在这里应该是一个表达式,例如,一个引用

事实并非如此,因此失败了

它是一种语法糖,允许使用
{foo:'bar'}
形式。解释器知道您在一个对象声明中,并假装它是一个字符串


(JS没有符号。直到ES6,我忽略了提到。)

上下文在语言解析中非常重要

在JavaScript中,属性名总是字符串或
Symbol
s(最后一个在ES6中是新的)。在中,可以指定不带引号的属性名称(使用文字名称,必须为)、数字文字(转换为字符串)或字符串文字(例如,带引号):

(在ES6中,您也可以使用方括号中的计算属性名称,但这与此处无关,并且在任何情况下,它们在计算后都会变成
Symbol
s或字符串。)

因此,在对象初始值设定项中,上下文告诉解析器它需要一个属性名,允许使用文本或字符串表示法。但在这里:

foo.Bar(hello, "World");
…上下文告诉它,
hello
是一个标识符,因为语法说函数调用中的单个参数值(括号内容)是表达式,表达式中的单个单词本身表示标识符。由于它是您尚未声明的标识符,因此会出现
ReferenceError

奇怪的是,引号掉在了x的键上。我愿意忽略这一点,尽管它令人困惑

当属性名是有效的标识名时,这是显示对象属性的标准符号


您的评论如下:

我是JavaScript的初学者,正在尝试重构API


很公平。看起来没有比强制用户传递字符串更好的方法了

对,传递属性名称的正确方法是字符串,有时是数字(与数组索引一样),或
Symbol
s,然后使用“括号”符号访问属性:

var a = {foo: "bar"};
var name = "foo";
console.log(foo[name]); // "bar"
(当你用一个数字来做这件事时,它被强制为一个字符串。是的,当你用JavaScript的标准数组来使用数组索引时,(理论上)会发生这种情况,因为。)

但这并不意味着API的用户需要输入字符串文本。如果存在一组允许的属性名称,则可以将其作为对象上的属性使用

var API = {
    Things: {
        Foo: "Foo",
        Bar: "Bar"
    }
};
…然后使用API:

someApiMethod(API.Things.Foo);
您甚至可以定义这些只读,以防止意外覆盖:

var API = {Things: {}};
["Foo", "Bar"].forEach(function(name) {
    Object.defineProperty(API.Things, name, {
        enumerable: true, // Or not, whichever
        value: name
    });
});
默认情况下,使用
defineProperty
定义的属性是只读的

在ES6中,它们也可以是常量:


上下文在语言分析中非常重要

在JavaScript中,属性名总是字符串或
Symbol
s(最后一个在ES6中是新的)。在中,可以指定不带引号的属性名称(使用文字名称,必须为)、数字文字(转换为字符串)或字符串文字(例如,带引号):

(在ES6中,您也可以使用方括号中的计算属性名称,但这与此处无关,并且在任何情况下,它们在计算后都会变成
Symbol
s或字符串。)

因此,在对象初始值设定项中,上下文告诉解析器它需要一个属性名,允许使用文本或字符串表示法。但在这里:

foo.Bar(hello, "World");
…上下文告诉它,
hello
是一个标识符,因为语法说函数调用中的单个参数值(括号内容)是表达式,表达式中的单个单词本身表示标识符。硅
var API = {Things: {}};
["Foo", "Bar"].forEach(function(name) {
    Object.defineProperty(API.Things, name, {
        enumerable: true, // Or not, whichever
        value: name
    });
});
const Foo = "Foo";
const Bar = "Bar";