1
0
Fork 0
Browse Source

Merge remote-tracking branch 'origin/master'

master
YuJian920 3 years ago
parent
commit
5588fef915
  1. 44
      深入探索 JavaScript/JavaScript 执行.md
  2. 57
      深入探索 JavaScript/JavaScript 语法.md
  3. 14
      深入探索 JavaScript/碎片记录.md

44
深入探索 JavaScript/JavaScript 执行.md

@ -47,6 +47,48 @@ o.showThis(); // o
如果将例子中的 showThis 函数改写为类中的方法,那么直接调用 showThis 方法的 this 的结果也会不同,这是因为 JavaScript 的 Class 被设计成了默认在严格模式下(use strict)执行,而严格模式下 this 指向会发生一些改变。 如果将例子中的 showThis 函数改写为类中的方法,那么直接调用 showThis 方法的 this 的结果也会不同,这是因为 JavaScript 的 Class 被设计成了默认在严格模式下(use strict)执行,而严格模式下 this 指向会发生一些改变。
this 是一个复杂的机制,JavaScript 标准定义了 \[\[ thisMode \]\] 私有属性,这个属性有以下三种取值:
- lexical - 表示从上下文中找 this,对应箭头函数。
- global - 表示当 this 为 underfined 时,取全局对象,对应普通函数。
- strict - 当严格模式时使用,this 严格按照调用时传入的值,可能为 underfined 或 null
实际上 this 也可以看作是在调用时被确认的词法环境,普通函数被调用时会将 this 指向调用者压入执行上下文栈,但箭头函数不会创建新的词法环境,因此箭头函数中的 this 将从词法环境中查找并继承(复用)其定义时外部函数的 this。
JavaScript 提供了可以操作 this 的内置函数,如 Function.prototype.call 和 Function.prototype.apply,它们可以指定函数调用时传入的 this,除此之外还有 Function.prototype.bind,它可以返回一个更改了 this 的函数,它们甚至可以应用在箭头函数中,但是它并不会修改 this,仅仅实现了传参的能力。
Kyle Simpson 关于 this 的总结:
1. 如果由new调用 - 绑定到新创建的对象
2. 如果由 call、apply 或 bind调用 - 绑定到指定的对象
3. 如果由上下文对象调用 - 绑定到那个上下文对象
4. 其他调用情况 - 严格模式下会绑定到 undefined,非严格模式绑定到全局对象
5. 以上情况对于箭头函数都不适用,它会继承外层函数的 this 绑定
## 上下文栈
>JavaScript 引擎并非一行一行分析执行代码,而是一段一段的分析执行,当执行一段代码的时候会进行一些准备工作
函数能够引用定义时的变量,函数也能记住定义时的 this,因此,函数内部必然有一个机制来保存这些信息,这个用来保存定义时上下文的机制就是私有属性 \[\[Environment\]\]。 函数能够引用定义时的变量,函数也能记住定义时的 this,因此,函数内部必然有一个机制来保存这些信息,这个用来保存定义时上下文的机制就是私有属性 \[\[Environment\]\]。
在函数定义时,会保存定义时的上下文为函数的 \[\[Environment\]\],而在函数执行时,会创建一条新的执行环境记录,也就是函数执行时的上下文被设置为函数的 \[\[Environment\]\],这个动作就是切换上下文,着一层一层形成的上下文就是函数的 **“作用域链”**。 在函数执行时,会创建一条执行环境记录,也就是函数定义时的上下文设置为函数的 \[\[Environment\]\],这个动作就是切换上下文,无论函数以何种形式被调用,变量都会依照定义时的环境被查找出来。
JavaScript 用一个栈来管理执行上下文,当函数调用时,会入栈一个新的执行上下文,函数调用结束之后,执行上下文被出栈
this 的值存放在私有属性 \[\[ThisBindingStatus\]\] 中
函数创建新的执行上下文中的词法环境记录时,会根据 \[\[thisMode\]\] 来标记新纪录的 \[\[ThisBindingStatus\]\] 私有属性。代码执行遇到 this 时,会逐层检查当前词法环境记录中的 \[\[ThisBindingStatus\]\],当找到有 this 的环境记录时获取 this 的值。
## Completion Record / 完成标记
>Completion Record 是 JavaScript 中的一个规范类型,用于描述异常、跳出等语句执行过程
Completion Record 是语言实现者才需要关心的内容,但是我们可以从中看出一些 JavaScript 更加底层的实现逻辑,它有着三个字段分别是:
- \[\[type\]\] - 表示完成的类型,有 break continue return throw 和 normal 几种类型
- \[\[value\]\] - 表示语句的返回值,如果语句没有,则是 empty
- \[\[target\]\] - 表示语句的目标,通常是一个 JavaScript 标签
JavaScript 正是依靠语句的 Completion Record 类型,方才可以在语句的复杂嵌套结构中,实现各种控制,普通语句执行后,会得到 \[\[type\]\] 为 normal 的 Completion Record,JavaScript 引擎遇到这样的 Completion Record,会继续执行下一条语句。
这些语句中,只有表达式语句会产生 \[\[value\]\],当然,从引擎控制的角度,这个 value 并没有什么用处,Chrome 控制台显示的正是语句的 Completion Record 的 \[\[value\]\]
参考文章:
- http://www.ecma-international.org/ecma-262/#sec-ecmascript-specification-types

57
深入探索 JavaScript/JavaScript 语法.md

@ -0,0 +1,57 @@
## import 声明
import 声明有两种用法,一个是直接 import 一个模块,另一个是带 from 的 import,它能引入模块里的一些信息。
```javascript
import "mod"; //引入一个模块
import v from "mod"; //把模块默认的导出值放入变量v
```
直接 import 一个模块,只是保证了这个模块代码被执行,引用它的模块是无法获得它的任何信息的,而带 from 的 import 意思是引入模块中的一部分信息,可以把它们变成本地的变量。
独立的 `export` 导入相当于是一个引用,导出的变量仍然指向同一个地址(无关引用类型和值类型)。
`export default` 导出的则是一个值,但是对于引用类型而言,也是会被修改的
## var 声明的预处理
>var 在预处理阶段,不关心赋值的部分,只管在当前作用域声明这个变量
```javascript
var a = 1;
function foo() {
console.log(a); // undefined
// var 会穿透一切语言结构
if(false) {
var a = 2;
}
}
foo();
```
## function 声明
>function 声明表现跟 var 相似,不同之处在于,function 声明不但在作用域中加入变量,还会给它赋值。
看一个与之不同的例子:
```javascript
// foo 会被提升,但不会被赋值
console.log(foo); // undefined
if(true) {
function foo(){ }
}
```
## class 声明
class 声明也是存在预处理的,但是它的行为会更加的符合直觉,更倾向于抛出错误
## 指令序言机制
"use strict"是 JavaScript 标准中规定的唯一一种指令序言,但是设计指令序言的目的是,留给 JavaScript 的引擎和实现者一些统一的表达方式,在静态扫描时指定 JavaScript 代码的一些特性。
JavaScript 的指令序言是只有一个字符串直接量的表达式语句,它只能出现在脚本、模块和函数体的最前面。

14
深入探索 JavaScript/碎片记录.md

@ -0,0 +1,14 @@
- `12.toString()` 会报错,这是因为 JavaScript 允许10进制 Number 省略小数点前或者后,`12.toString()` 中的 `12.` 会被当作省略了小数点后的数字,如果想要这一句正常工作,需要在中间加个空格:`12 .toString()` 或是 `12..toString()`
- 模板支持添加处理函数的写法,这时模板的各段会被拆开,传递给函数当参数:
```javascript
function f(){
console.log(arguments);
}
var a = "world"
f`Hello ${a}!`; // [["Hello", "!"], world]
```
- JavaScript switch 语句继承自 Java,Java 中的 switch 语句继承自 C 和 C++,原本 switch 语句是跳转的变形,所以我们如果要用它来实现分支,必须要加上 break。
- 在 C 时代,switch 生成的汇编代码性能是略优于 if else 的,但是对 JavaScript 来说,则无本质区别。
Loading…
Cancel
Save