请教大佬一个JS问题
请教大佬一个问题,可以从**底层**的层面解释一下为什么 `console.info(dict.node)` 输出的是 `undefined` 的原因吗***
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script>
window.onload = () => {
const dict = {
conform : document.querySelector("#admin"),
dimmer : document.querySelector('#pwd')
}
for(const node of Object.keys(dict)){
console.info(dict.node);
}
}
</script>
</head>
<body>
<form id="form1" name="form1" method="post" action="">
<table width="200" border="0" align="center">
<tr>
<td colspan="2"></td>
</tr>
<tr>
<td width="62">帐号:</td>
<td width="122">
<input name="admin" type="text" id="admin" size="15" />
</td>
</tr>
<tr>
<td>密码:</td>
<td><input name="pwd" type="password" id="pwd" size="15" /></td>
</tr>
</table>
</form>
</body>
</html>
``` 本帖最后由 hans7 于 2023-6-16 00:55 编辑
想实现这个例子的目标只需要把dict.node改成dict,dict.node相当于dict['node']。
打开 https://astexplorer.net/ 查看 这条语句 dict.node === dict 的Babel AST
两者区别只有一个:computed是true和false。但含义是不一样的。
接下来看下computed是true和false时v8生成的字节码的区别。准备一段代码 computed_demo.js
```js
let dict = {
node: 'node'
};
let node = '_node';
console.log(dict.node === dict);
```
命令:./d8 computed_demo.js --print-bytecode
获取字节码。如果没有d8.exe也可以用nodejs代替,node --print-bytecode computed_demo.js。简单分析如下。结论很简单:dict.node用了LdaNamedProperty指令,dict用了LdaKeyedProperty指令。这就是两者的不同。Lda类指令是将结果放到累加寄存器的。
```assembly
Parameter count 1
Register count 5
Frame size 40
000000650824FADA @ 0 : 7d 00 00 29 CreateObjectLiteral , , #41 ; 定义 dict
000000650824FADE @ 4 : 1d 02 StaCurrentContextSlot ; 简单理解为放到 globalThis 地址2处
000000650824FAE0 @ 6 : 12 01 LdaConstant ; 常量池处为字符串 '_node'
000000650824FAE2 @ 8 : 1d 03 StaCurrentContextSlot
000000650824FAE4 @ 10 : 13 02 01 LdaGlobal , ; 取常量池2处的值,即'console',放到累加寄存器。后面的 是反馈向量,本例不用管。
000000650824FAE7 @ 13 : 26 f9 Star r2 ; 累加寄存器当前值存入r2寄存器,即r2 = 'console'
000000650824FAE9 @ 15 : 28 f9 03 03 LdaNamedProperty r2, , ; console取log属性
000000650824FAED @ 19 : 26 fa Star r1 ; console.log对象的地址放到r1寄存器
000000650824FAEF @ 21 : 1a 02 LdaCurrentContextSlot ; globalThis 对应dict,加载到累加寄存器
000000650824FAF1 @ 23 : 26 f8 Star r3 ; r3现在指向dict对象
000000650824FAF3 @ 25 : 28 f8 04 05 LdaNamedProperty r3, , ; 常量池对应'node',dict取'node'属性
000000650824FAF7 @ 29 : 26 f8 Star r3 ; dict['node']结果放到r3寄存器
000000650824FAF9 @ 31 : 1a 02 LdaCurrentContextSlot
000000650824FAFB @ 33 : 26 f7 Star r4 ; r4指向dict对象
000000650824FAFD @ 35 : 1a 03 LdaCurrentContextSlot ; globalThis 对应'_node',至累加寄存器
000000650824FAFF @ 37 : 2a f7 07 LdaKeyedProperty r4, ; 取dict,即dict['_node'],结果放在累加寄存器
000000650824FB02 @ 40 : 68 f8 09 TestEqualStrict r3, ; 累加寄存器当前值与r3的值比较,结果放到累加寄存器
000000650824FB05 @ 43 : 26 f8 Star r3 ; dict.node === dict结果放到r3
000000650824FB07 @ 45 : 59 fa f9 f8 0a CallProperty1 r1, r2, r3, ; 调用console.log
000000650824FB0C @ 50 : 26 fb Star r0
000000650824FB0E @ 52 : aa Return
Constant pool (size = 5)
000000650824FA9D: in OldSpace
- map: 0x0065080404b1 <Map>
- length: 5
0: 0x00650824fa81 <ObjectBoilerplateDescription>
1: 0x00650824fa11 <String[#5]: _node>
2: 0x0065081c6971 <String[#7]: console>
3: 0x0065081c69e5 <String[#3]: log>
4: 0x00650824fa01 <String[#4]: node>
Handler Table (size = 0)
Source Position Table (size = 0)
false
```
~~感觉这些内容足够水一篇blog了~~ 在javascript中,对象取值基本的有两种方式,一种是使用"."的方式,这种你应该清楚,这种方式语言执行时,一般是已知属性名取值,当取不到就会返回undefined。另一种是通过 obj['paramName'],中括号中可以是string或者变量的方式去取值,字符串则和之前点取值的方式一样,使用变量即可以做到动态取值设置值。你这段代码用在循环中,肯定是变量属性名,所以要使用[]的方式来取值遍历读取。 metaxman 发表于 2023-6-16 00:04
在javascript中,对象取值基本的有两种方式,一种是使用"."的方式,这种你应该清楚,这种方式语言执行时, ...
大白话就是你想去找循环遍历的 node 变量属性名,但用错了方式,它觉得你找对象中的“node”属性,一看对象里没有呀,哦,抱歉同志,只能say undefined了。 metaxman 发表于 2023-6-16 00:04
在javascript中,对象取值基本的有两种方式,一种是使用"."的方式,这种你应该清楚,这种方式语言执行时, ...
感谢回复,那怎么分辨什么时候用 . 又什么时候用[],交叉用呢。还有在我看来 . 和 [] 不是一样的吗 waahah 发表于 2023-6-16 00:21
感谢回复,那怎么分辨什么时候用 . 又什么时候用[],交叉用呢。还有在我看来 . 和 [] 不是一样的吗
当属性名是一个变量时必须得用[],就像4楼说的,dict.node相当于dict['node']。你理解这个,就可以了。不想区分就全用[],但使用点属性名的方式编写更便捷。 waahah 发表于 2023-6-16 00:21
感谢回复,那怎么分辨什么时候用 . 又什么时候用[],交叉用呢。还有在我看来 . 和 [] 不是一样的吗
dict 和 dict['node'] 写法上很明显不一样吧,dict.node相当于 dict['node'],所以 dict.node 怎么能和 dict 一样呢。 dict 这个node可以是任何key,而dict["node"]表示这个key只能是node 69之皇 发表于 2023-6-16 00:45
dict 这个node可以是任何key,而dict["node"]表示这个key只能是node
这个我知道,在这个循环里 dict就相当于不循环直接调用的dict["node"] metaxman 发表于 2023-6-16 00:29
当属性名是一个变量时必须得用[],就像4楼说的,dict.node相当于dict['node']。你理解这个,就可以了。不 ...
```js
const dict = {
conform : document.querySelector("#admin"),
dimmer : document.querySelector('#pwd')
}
dict["conform"]
//正确
dict.conform == dict["conform"]
//结果为true
```
#### 我知道dict.node相当于dict["node"],所以在循环块我才写成dict.node,因为平常不在循环块里时都是直接用dict.node (它俩用哪个都行相等),就是在循环块里我也是潜意识里也还认为它俩相等,就是不知道为啥到了循环块里就不一样了