使用简单的文字手动声明JavaScript对象
Using bare words to declare a JavaScript object manually
我是一个JavaScript初学者,正在尝试重构一个API,但是我遇到了一个奇怪的问题。
我使用node
解释器来测试我想在重新设计中合并的一些代码,但是我遇到了一些意想不到的行为。
考虑在节点解释器中输入以下内容:
[In0] b
我期望得到如下所示的ReferenceError。
[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)
接下来 [In1] 'b'
[Out1] 'b' // this is OK because it's a string
现在考虑一个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)
有谁能向一个新手解释这种行为吗?当可以手动完成时,不能在方法中使用裸字作为键,这是非常令人沮丧的。
上下文在语言分析中很重要。
在JavaScript中,属性名总是字符串或Symbol
s(最后一个在ES6中是新的)。在对象初始化器中,您可以指定不带引号的属性名称(使用文字名称,必须是IdentifierName),作为数字文字(转换为字符串)或作为字符串文字(例如,带引号):
var a = { b: 'c' };
// is the same as
var a = { 'b': 'c' };
// is the same as
var a = { "b": 'c' };
(在ES6中,您也可以在方括号中使用计算的属性名称,但这在这里不相关,在任何情况下,它们最终都是Symbol
s或计算后的字符串。)
因此,在对象初始化器中,上下文告诉解析器它正在等待一个属性名,该属性名可以是文字或字符串表示法。但这里:
foo.Bar(hello, "World");
…上下文告诉它hello
是标识符,因为语法规定函数调用中的单个参数值(括号的内容)是表达式,表达式中的单个单词表示标识符。因为它是一个你没有声明的标识符,你得到一个ReferenceError
.
奇怪的是,x的键上省略了引号。我愿意忽略这一点,尽管它令人困惑
当属性名是有效的IdentifierName时,这是显示对象属性的标准符号。
你的评论:
我是一个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中,它们也可以是常量:
const Foo = "Foo";
const Bar = "Bar";
hello
在这里应该是一个表达式,例如引用。
它不是,因此失败。
它的语法糖允许形式{ foo: 'bar'}
。解释器知道你在对象声明中,并假装它是一个字符串。
(JS没有符号。直到ES6,我忘了提。)
- 声明JavaScript选项对象的正确方法
- 声明Javascript名称空间的两种方法之间的区别
- 声明 JavaScript 变量
- 解析函数声明 Javascript
- 在 Rails 3 中声明 Javascript 变量时出错
- 我应该在对象原型中声明javascript对象方法吗
- 淘汰高级声明javascript"用“-喜欢
- 动态编辑html声明javascript
- 在构造函数和原型中声明javascript对象方法
- 声明javascript对象时在其变量中引用该对象
- 在typescript中声明javascript命名空间
- 声明javascript对象属性问题
- 在HTML链接中声明JavaScript变量
- 声明Javascript变量的所有可能方法
- 声明JavaScript成员函数的最佳实践
- 如何在ios中声明javascript
- 有效地声明JavaScript变量
- 以更简洁的方式声明javascript静态方法
- 使用function-prototype声明Javascript命名空间
- 如何在对象中正确声明Javascript对象数组