gpt4 book ai didi

javascript - 使用裸字手动声​​明 JavaScript 对象

转载 作者:行者123 更新时间:2023-11-28 19:06:08 25 4
gpt4 key购买 nike

我是 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 中的新增内容)。在 object initializer ,您可以指定不带引号的属性名称(使用文字名称,必须是 IdentifierName )、数字文字(转换为字符串)或字符串文字(例如,带引号):

var a = { b: 'c' };
// is the same as
var a = { 'b': 'c' };
// is the same as
var a = { "b": 'c' };

(在 ES6 中,您还可以在方括号中使用计算属性名称,但这与这里无关,无论如何它们在计算后最终会成为 Symbol 或字符串。)

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

foo.Bar(hello, "World");

...上下文告诉它 hello是一个标识符,因为语法规定函数调用中的各个参数值​​(括号的内容)是表达式,并且表达式中的单个单词本身表示标识符。由于它是您尚未声明的标识符,因此您会得到 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,然后您可以使用“括号”表示法来访问属性:

var a = {foo: "bar"};
var name = "foo";
console.log(foo[name]); // "bar"

(当您使用数字执行此操作时,它会被强制转换为字符串。是的,当您将数组索引与 JavaScript 的标准数组一起使用时,[理论上]会发生这种情况,因为 they aren't really arrays at all 。)

但这并不意味着您的 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";

关于javascript - 使用裸字手动声​​明 JavaScript 对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31641986/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com