Skip to content

Commit 3655cca

Browse files
committed
Merge branch 'main' of github.com:buynao/stackoverflow-js-top-qa
2 parents ee6fd7a + eceb8ed commit 3655cca

File tree

3 files changed

+36
-34
lines changed

3 files changed

+36
-34
lines changed

README.md

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,20 @@
22

33
## 背景
44

5-
国内已经有很多技术社区,其中包含了海量的学习资源,但是像 stackoverflow 这样的,以技术问答形式做分享的却比较少(我知道有一个,但是...)
5+
在学习过程中,如果能够针对一个问题着手,一直深入下去,可能会让你对这个知识点掌握的更深刻
66

7-
在学习过程中,如果能够针对一个问题着手,一直深入下去,会让你对这个知识点掌握的更加深刻
7+
经过了一番筛选后,整理的很多问题,现在可能看起来比较过时,内容也没有一些现成的前端面试答案看起来更爽更舒服
88

9-
虽然经过了一番筛选后,整理的很多问题,现在可能看起来比较过时,内容也没有一些现成的前端面试答案看起来更爽更舒服。但是在整理翻译的过程中,还是会有一些让人觉得 “原来还能这样” 的深刻体会。
9+
但是在整理翻译的过程中,还是会有一些让人觉得 “原来还能这样” 的深刻体会。
1010

1111
这些问题之所以之所以票数比较高,除了问题比较经典,时间久远积累的原因之外,更多的是因为很多答疑者们,在提供解决方案的同时,还能集思广益,引发更多角度的思考:
1212

1313
- 比如通过ECMA标准规范,对问题刨根剖底:[this 的运行原理?](./contents/basic/this.md)
1414
- 比如针对 "老生常谈" 的问题,进行深度思考: [在 JavaScript 中如使字符串的第一个字母大写(含国际化方案讨论)?](./contents/advanced/firstStrToUppercase.md)
15-
- 还有一些可能目前热度不高,但是却令人茅塞顿开:有些知识,传了百遍,千遍,就是正确的么?[Javascript 在哪里为函数调用的结果分配内存?堆栈还是堆?](./contents/advanced/heapAndStack.md)
1615
- 比如会将解决方案的优缺点,进行一一对比:[在 JavaScript 中循环遍历数组](./contents/basic/loopArray.md)
16+
- 还有一些可能目前热度不高,但是却令人茅塞顿开... [JavaScript 在函数调用过程中是如何分配内存的?如何区分堆栈和堆?](./contents/advanced/heapAndStack.md)
1717

18-
总之言而,就是在解决问题的同时,还能够引导大家对问题的背后原因多一些思考~
18+
总而言之,就是在解决问题的同时,还能够引导大家对问题多一些其他角度的思考~
1919

2020
所以,我想对 stackoverflow 上 前端 相关(主要是JS,浏览器,框架,性能等)投票数较多且比较有意义的问题进行整理翻译!
2121

@@ -24,18 +24,16 @@
2424

2525
由于筛选机制原因,票数最多的问题,一般提问时间也比较久远,对于一些已经明显过时的问题,不在进行翻译
2626

27-
只针对一些有意义的问题,进行翻译
27+
只针对一些有意义的问题,进行整理翻译
2828

29-
有意义的标准,可能包括以下之一
29+
有意义的标准,可能是以下原因之一
3030
1. 票数多
3131
2. 经典问题
3232
3. 常见问题,但是解答内容仍然令人醍醐灌顶
3333
4. 可能知道个大概,但是一下不知道如何具体表达的问题
3434
5. 一些被人误解的问题
3535
6. ...
3636

37-
欢迎 star 激励~
38-
3937
## 在线阅读
4038

4139
[https://stackoverflow-js-top-qa.vercel.app](https://stackoverflow-js-top-qa.vercel.app)

contents/advanced/heapAndStack.md

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
## Javascript 在哪里为函数调用的结果分配内存?栈还是堆
1+
## 问题:JavaScript 在函数调用过程中是如何分配内存的?如何区分堆栈和堆
22

3-
我浏览了整个互联网,似乎找不到这个问题的答案。
3+
我查遍了整个互联网,似乎找不到这个问题的答案。
44

5-
- 我读到过 `栈(Stack)` 用于存储原始数据类型(number, string...),`堆(Heap)` 用于存储引用数据类型(object, array...)。
6-
- 我还读到过 `栈(Stack)` 的大小是固定的,一旦分配它就不会改变,那么它为什么还能用于原始数据类型的存储?因为 `JS` 在运行前并不一定知道每个变量的大小
7-
- 基础数据类型是不可变的,所以如果我们尝试重新分配一个变量,它不会改变其内存地址的值,而是会在内存中分配新空间,存储新值并将其地址分配给变量。
5+
- 我读到过 `栈(Stack)` 用于存储原始数据类型(number, string...),`堆(Heap)` 用于存储引用数据类型(object, array...)。
6+
- 我还读到过 `栈(Stack)` 的内存大小是固定的,一旦分配它就不会改变,那么它为什么还能用于原始数据类型的存储?因为 `JS` 在运行前并不一定知道每个变量的所占内存大小
7+
- 原始数据类型是不可变的,所以如果我们尝试重新分配一个变量,它不会改变其内存地址的值,而是会在内存中分配新空间,存储新值并将其地址分配给变量。
88

99
如果以上是正确的,那么当我这样做时会发生什么?
1010

@@ -15,11 +15,13 @@ string = string.ToUpperCase(); // New memory allocated for "HELLO WORLD"
1515

1616
```
1717

18-
`HELLO WORLD` 的新内存分配在哪里?如果是在 `栈(Stack)` 中,是因为它是基础数据类型吗?还是在 `堆(Heap)` 中,因为 `JS` 在运行代码之前还不知道它的值。
18+
`HELLO WORLD` 在内存中会如何分配?
19+
- 如果是在 `栈(Stack)` 中,是因为它是原始数据类型吗?
20+
- 还是在 `堆(Heap)` 中,因为 `JS` 在运行代码之前还不知道它的值。
1921

2022
如果它确实是在 `栈(Stack)` 中,那么旧的 `Hello World` 会发生什么变化?
2123

22-
只有 `堆(Heap)` 里的数据会被垃圾回收收集释放,这是否意味着旧的、未使用的字符串将一直保留着,直到程序运行结束?
24+
只有 `堆(Heap)` 里的数据会被垃圾回收收集释放,这是否意味着旧的、未使用的字符串将一直保留着,直到程序运行结束?
2325

2426
如果我这样做会发生什么?
2527

@@ -33,9 +35,9 @@ string = string.repeat(10000000000)
3335

3436
## 答案
3537

36-
先说结论,答案因 `JS引擎` 而异,`EScript 标准规范` 中并没有对 `JS内存` 分配做出具体要求
38+
先说结论,答案因 `JS引擎` 而异,`EScript 标准规范` 中并没有对 `JS内存` 如何分配做出具体要求
3739

38-
你没必要担心 `栈(Stack)` 用完的情况,这对你的代码来说真的不重要。
40+
而且你没必要担心 `栈(Stack)` 用完的情况,这对你的代码来说真的不重要。
3941

4042
`EScript 标准规范` 并不要求实现的每一步都很具体。它描述的是行为,而不是该行为的实现。
4143

contents/basic/this.md

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@
66

77
## 答案
88

9-
`this` 是 JavaScript 中 `执行环境` 里的一个属性。主要用途通常是在函数和构造函数中。使用规则很简单(如果你坚持最佳实践的话)。
9+
`this` 是 JavaScript 中 `执行环境` 里的一个属性。主要用途通常是在函数和构造函数中。
1010

1111
### ECMA规范中对 this 的技术描述
1212

13-
[ECMAScript标准](https://tc39.es/ecma262/) 通过 [ResolveThisBinding](https://tc39.es/ecma262/#sec-resolvethisbinding) AO(一种抽象操作,缩写为AO) 来定义 [this](https://tc39.es/ecma262/#sec-this-keyword)
13+
[ECMAScript标准](https://tc39.es/ecma262/) 通过 [ResolveThisBinding](https://tc39.es/ecma262/#sec-resolvethisbinding) AO(可以理解成是一种抽象方法,缩写为AO) 来定义 [this](https://tc39.es/ecma262/#sec-this-keyword)
1414

1515
```text
1616
ResolveThisBinding 不需要任何参数。它使用运行中的执行环境的 [词法环境 LexicalEnvironment] 来完成 this 的绑定。在被调用时执行以下步骤。
@@ -21,17 +21,17 @@ ResolveThisBinding 不需要任何参数。它使用运行中的执行环境的
2121

2222
[全局环境记录 Global Environment Records](https://tc39.es/ecma262/#sec-global-environment-records)[模块环境记录 Module Environment Records](https://tc39.es/ecma262/#sec-module-environment-records)[函数环境记录 Function Environment Records](https://tc39.es/ecma262/#sec-function-environment-records) 都有自己的 `GetThisBinding` 方法。
2323

24-
通过 `GetThisEnvironment` AO 找到当前执行环境中的 `词法环境 LexicalEnvironment`,并找到最接近的具有此绑定(即 `HasThisBinding` 返回 true )的环境记录(通过迭代访问其 `[[OuterEnv]]` 属性)。这个过程最后会产生上述 `三种环境记录类型` 中的一种
24+
通过 `GetThisEnvironment` AO 找到当前执行环境中的 `词法环境 LexicalEnvironment`,并找到最接近的具有此绑定(即 `HasThisBinding` 返回 true )的环境记录(通过迭代访问其 `[[OuterEnv]]` 属性)。然后会产生上述 `三种环境类型` 中的一种环境记录
2525

26-
`this` 往往取决于代码环境是否处于 `严格模式(strict mode)` 中。
26+
`this` 往往也取决于代码环境是否处于 `严格模式(strict mode)` 中。
2727

2828
`GetThisBinding` 的返回值就是当前执行上下文的 `this`,所以每当建立一个新的执行上下文时,`this` 就会解析为一个不同的值。当当前执行上下文被修改时也会发生这种情况。
2929

3030
下面的例子列出了可能发生这种情况的五种场景:
3131

32-
### 1.脚本中的全局执行上下文
32+
### 1. script 中的执行上下文
3333

34-
例如,这是在最顶层执行的代码,直接在`<script>`内。
34+
例如,这是在最顶层执行的代码,直接在 `<script>` 内。
3535

3636
```html
3737
<script>
@@ -44,23 +44,25 @@ setTimeout(function(){
4444
</script>
4545
```
4646

47-
当脚本代码在全局环境中执行代码时`GetThisBinding` 将有以下步骤。
47+
当脚本代码在全局环境中执行时`GetThisBinding` 的步骤如下:
4848

4949
```text
5050
The GetThisBinding concrete method of a global Environment Record envRec […] [does this]:
5151
5252
Return envRec.[[GlobalThisValue]].
5353
```
5454

55-
`全局环境记录``[[GlobalThisValue]]` 属性总是被设置为当前环境的全局对象,它可以通过 `globalThis`(Web 上的 `window`,Node.js 上的 `global`[MDN上的文档](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/globalThis) )访问。你也可以按照 [InitializeHostDefinedRealm](https://tc39.es/ecma262/#sec-initializehostdefinedrealm) 的步骤来学习 `[[GlobalThisValue]]` 的属性是如何形成的。
55+
`全局环境记录``[[GlobalThisValue]]` 属性始终被设置为当前环境的全局对象,可以直接通过 `globalThis`(Web 上的 `window`,Node.js 上的 `global`[MDN上的文档](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/globalThis) )进行访问,也就是指向全局变量。
56+
57+
你可以访问 [InitializeHostDefinedRealm](https://tc39.es/ecma262/#sec-initializehostdefinedrealm) 进一步了解 `[[GlobalThisValue]]` 的属性是如何形成的。
5658

5759
### 2. module 中的执行上下文
5860

59-
module 在 `ECMAScript 2015` 中被引入。
61+
`module``ECMAScript 2015` 中被引入。
6062

6163
例子:直接在 `<script type="module">` 里面执行的代码。
6264

63-
当 module 在全局环境中执行代码时,`GetThisBinding` 将有以下步骤。
65+
`module` 在全局环境中执行代码时,`GetThisBinding` 的步骤如下:
6466

6567
```text
6668
The GetThisBinding concrete method of a module Environment Record […] [does this]:
@@ -70,18 +72,18 @@ Return undefined.
7072

7173
因此在 `module` 中,`this` 在全局范围内始终是 `undefined``module` 默认是开启严格模式的。
7274

73-
### 3. 进入 eval 上下文
75+
### 3. eval 中的执行上下文
7476

75-
`eval` 有两种调用方式[直接调用](https://tc39.es/ecma262/#sec-function-calls-runtime-semantics-evaluation)[间接调用](https://tc39.es/ecma262/#sec-eval-x)。这种区别从 `ECMAScript第五版` 就开始存在
77+
`ECMAScript 第五版` 的时候,`eval` 就有两种调用方式[直接调用](https://tc39.es/ecma262/#sec-function-calls-runtime-semantics-evaluation)[间接调用](https://tc39.es/ecma262/#sec-eval-x)
7678

7779
- 直接调用的 `eval` 通常看起来像 `eval(...);` 或者 `(eval)(...);`,只有在调用表达符合狭义模式的情况下才是 `直接` 的。
7880
- 间接调用的 `eval` 通常是以调用函数引用 `eval` 来完成的,比如:`eval?.(…)` , `(…, eval)(…)` , `window.eval(…)` , `eval.call(…,…)` 等...
7981

80-
通过 [performeval](https://tc39.es/ecma262/#sec-performeval) 执行 `eval` 代码时,会创建一个新的 [声明性环境记录](https://tc39.es/ecma262/#sec-declarative-environment-records) 作为其 `词法环境 LexicalEnvironment`这也是 `GetThisEnvironment` 获取 `this` 值的地方。
82+
通过 [performeval](https://tc39.es/ecma262/#sec-performeval) AO 执行 `eval` 代码时,会创建一个新的 [声明性环境记录](https://tc39.es/ecma262/#sec-declarative-environment-records) 作为其 `词法环境 LexicalEnvironment`前边说过,这是通过 `GetThisEnvironment` AO 获取 `this` 值的地方。
8183

82-
如果 `this` 出现在 `eval` 代码中,将由 `GetThisEnvironment` 找到的环境记录的 `GetThisBinding` 方法,直接调用并返回其值
84+
如果 `this` 出现在 `eval` 代码中,先通过 `GetThisEnvironment` AO 找到其环境记录,在直接调用 `GetThisBinding` AO 并返回其值
8385

84-
而刚刚所介绍的 `声明性环境记录` 来源哪里,是取决于 `eval` 的调用方式是 `直接` 还是 `间接`
86+
刚刚所说的 `声明性环境记录` 来源哪里,是取决于 `eval` 的调用方式是 `直接` 还是 `间接`
8587

8688
-`直接` 调用中,它将基于当前运行的执行环境中的 `词法环境 LexicalEnvironment`
8789
-`间接` 调用中,它将基于执行当前环境记录中的 `[[GlobalEnv]]` 属性(一个全局环境记录)。
@@ -93,7 +95,7 @@ Return undefined.
9395

9496
那么 `new Function` 呢?- `new Function``eval` 类似,但它并不立即调用代码,而是创建一个构造函数。在构造函数中的任何地方都不适用 `this` 的绑定,但是当这个函数被调用时,`this` 才能够发挥作用,下一小节会继续进行相关解释
9597

96-
### 4. 进入 function 执行上下文
98+
### 4. function 中的执行上下文
9799

98100
在调用一个函数时,我们将进入 function 执行上下文,目前有四种语法可以调用一个函数。
99101

0 commit comments

Comments
 (0)