使用裸词手动声明一个 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;
}
注意到这种行为,我尝试在我的 class 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)
任何人都可以向菜鸟解释这种行为吗?当可以手动完成时,不能在方法中使用裸词作为键是非常令人沮丧的。
hello
应该是一个表达式,例如引用。
不是,因此失败。
它是语法糖,允许 { foo: 'bar'}
形式。解释器知道您在对象声明中并假装它是一个字符串。
(JS没有symbols,直到ES6,我忘了说。)
上下文在语言解析中很重要。
在 JavaScript 中,属性 名称总是字符串或 Symbol
s(最后一个在 ES6 中是新的)。在 object initializer, you can specify a property name without quotes (using a literal name, which must be an 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
是一个 标识符 ,因为语法表明函数中的各个参数值(括号的内容) call 是表达式,表达式中的单个词本身表示标识符。由于它是您尚未声明的标识符,因此您会得到 ReferenceError
.
Strangely enough, the quotes are dropped on the key of x. I'm willing to overlook this, though it is confusing
当 属性 名称是有效的 IdentifierName.
时,这是显示对象属性的标准表示法
回复您的评论:
I'm a beginner to JavaScript and am trying to refactor an API
很公平。看起来没有比强制用户传递字符串更好的方法了。
正确,传递 属性 名称的正确方法是作为字符串,有时是数字(如数组索引)或 Symbol
s,然后您可以使用它们来访问属性 "brackets" 表示法:
var a = {foo: "bar"};
var name = "foo";
console.log(foo[name]); // "bar"
(当你使用数字时,它会被强制转换为字符串。是的,JavaScript 的标准数组使用数组索引时 [理论上] 会发生这种情况,因为 they aren't really arrays at all.)
但这并不意味着您的 API 的用户需要输入字符串 literals。如果有一组允许的 属性 名称,您可以将它们作为对象的属性提供。
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";
我是 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;
}
注意到这种行为,我尝试在我的 class 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)
任何人都可以向菜鸟解释这种行为吗?当可以手动完成时,不能在方法中使用裸词作为键是非常令人沮丧的。
hello
应该是一个表达式,例如引用。
不是,因此失败。
它是语法糖,允许 { foo: 'bar'}
形式。解释器知道您在对象声明中并假装它是一个字符串。
(JS没有symbols,直到ES6,我忘了说。)
上下文在语言解析中很重要。
在 JavaScript 中,属性 名称总是字符串或 Symbol
s(最后一个在 ES6 中是新的)。在 object initializer, you can specify a property name without quotes (using a literal name, which must be an 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
是一个 标识符 ,因为语法表明函数中的各个参数值(括号的内容) call 是表达式,表达式中的单个词本身表示标识符。由于它是您尚未声明的标识符,因此您会得到 ReferenceError
.
Strangely enough, the quotes are dropped on the key of x. I'm willing to overlook this, though it is confusing
当 属性 名称是有效的 IdentifierName.
时,这是显示对象属性的标准表示法回复您的评论:
I'm a beginner to JavaScript and am trying to refactor an API
很公平。看起来没有比强制用户传递字符串更好的方法了。
正确,传递 属性 名称的正确方法是作为字符串,有时是数字(如数组索引)或 Symbol
s,然后您可以使用它们来访问属性 "brackets" 表示法:
var a = {foo: "bar"};
var name = "foo";
console.log(foo[name]); // "bar"
(当你使用数字时,它会被强制转换为字符串。是的,JavaScript 的标准数组使用数组索引时 [理论上] 会发生这种情况,因为 they aren't really arrays at all.)
但这并不意味着您的 API 的用户需要输入字符串 literals。如果有一组允许的 属性 名称,您可以将它们作为对象的属性提供。
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";