waahah 发表于 2023-6-15 23:26

请教大佬一个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:08

本帖最后由 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了~~

metaxman 发表于 2023-6-16 00:04

在javascript中,对象取值基本的有两种方式,一种是使用"."的方式,这种你应该清楚,这种方式语言执行时,一般是已知属性名取值,当取不到就会返回undefined。另一种是通过 obj['paramName'],中括号中可以是string或者变量的方式去取值,字符串则和之前点取值的方式一样,使用变量即可以做到动态取值设置值。你这段代码用在循环中,肯定是变量属性名,所以要使用[]的方式来取值遍历读取。

metaxman 发表于 2023-6-16 00:09

metaxman 发表于 2023-6-16 00:04
在javascript中,对象取值基本的有两种方式,一种是使用"."的方式,这种你应该清楚,这种方式语言执行时, ...

大白话就是你想去找循环遍历的 node 变量属性名,但用错了方式,它觉得你找对象中的“node”属性,一看对象里没有呀,哦,抱歉同志,只能say undefined了。

waahah 发表于 2023-6-16 00:21

metaxman 发表于 2023-6-16 00:04
在javascript中,对象取值基本的有两种方式,一种是使用"."的方式,这种你应该清楚,这种方式语言执行时, ...

感谢回复,那怎么分辨什么时候用 . 又什么时候用[],交叉用呢。还有在我看来 . 和 [] 不是一样的吗

metaxman 发表于 2023-6-16 00:29

waahah 发表于 2023-6-16 00:21
感谢回复,那怎么分辨什么时候用 . 又什么时候用[],交叉用呢。还有在我看来 . 和 [] 不是一样的吗

当属性名是一个变量时必须得用[],就像4楼说的,dict.node相当于dict['node']。你理解这个,就可以了。不想区分就全用[],但使用点属性名的方式编写更便捷。

metaxman 发表于 2023-6-16 00:32

waahah 发表于 2023-6-16 00:21
感谢回复,那怎么分辨什么时候用 . 又什么时候用[],交叉用呢。还有在我看来 . 和 [] 不是一样的吗

dict 和 dict['node'] 写法上很明显不一样吧,dict.node相当于 dict['node'],所以 dict.node 怎么能和 dict 一样呢。

69之皇 发表于 2023-6-16 00:45

dict 这个node可以是任何key,而dict["node"]表示这个key只能是node

waahah 发表于 2023-6-16 00:48

69之皇 发表于 2023-6-16 00:45
dict 这个node可以是任何key,而dict["node"]表示这个key只能是node

这个我知道,在这个循环里 dict就相当于不循环直接调用的dict["node"]

waahah 发表于 2023-6-16 00:58

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 (它俩用哪个都行相等),就是在循环块里我也是潜意识里也还认为它俩相等,就是不知道为啥到了循环块里就不一样了
页: [1] 2 3
查看完整版本: 请教大佬一个JS问题