Files
DefectingCat.github.io/source/_posts/JavaScript-语法.md
DefectingCat 2385c24169 挖坑&测试
update test

更新文章
1. 测试新主题

挖坑

挖坑

update config

更新文章
1. 简易FaaS平台

更新文章
1. 修复错误

更新文章:Promise信任问题

update theme
1. 合并js

post: update notedly

fix: update faas

feature: change theme

* fix: comment

* feature: pgp

* fix: delete local file

post: update darkmode

update: update dependencies

fix: navbar in post incorrect height
* pre code adapt to dark mode

update new post useCallback

update dependencies

new post tiny router
* add static files

update vue tiny router

添加备案
* 更新依赖

add post

Add ignore file
2021-11-16 20:26:44 +08:00

233 lines
7.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
title: JavaScript-语法
date: 2021-07-12 15:20:03
tags: JavaScript
categories: 笔记
url: javascript-syntax
---
在 JavaScript 中,有很多常见的语法仍然有很多地方容易产生困惑、造成误解。
## 语句与表达式
语句statement和表达式expression常常被混为一谈但他们二者之间有细微的差别。语句相当于一句话而表达式更类似于一条短语。
JavaScript 中表达式可以返回一个结果值:
```js
let a = 3 * 6;
const b = a;
b;
```
上述带有`let``const`的语句被称为“声明语句”declaration statement而不带声明关键词的`a = 3 * 6;`则是“赋值表达式”。
乍一看可能还是不能太过于区分他们之间的区别,但是有些地方会让我们强制区分他们。在现代 SPA 框架中,模板语法中通常只允许插入 JavaScript 表达式,而不允许插入语句。例如在常见的 Vue 和 React 中:
```vue
<template>
<span>{{ 3 * 6 }}</span>
<span>{{ a }}</span>
<span>{{ let a = 3 * 6 }}</span> // 错误
</template>
```
### 语句的结果值
基本上所有的语句都有一个结果值undefined 也算)。
如果经常和控制台打交道,应该会发现很多时候控制台都会给我们返回一个 undefined。其实这就是语句所返回的值只不过大部分情况下都是 undefined。
代码块中的返回值是最后一个语句/表达式的结果:
```js
let a ;
// undefined
if (true) {
a = 3 + 1;
}
// 4
```
目前代码块语句返回的值无法被拿到:
```js
b = if (true) {
a = 3 + 1;
}
// VM268:1 Uncaught SyntaxError: Unexpected token 'if'
```
当然也有变通的方法 evil
```js
b = eval("if (true) {a = 3 + 1;}");
b; // 4
```
除了万恶的 evilES7 还有一项“do 表达式”提案,目前环境还没实现:
```js
b = do {
if (true) {
a = 3 + 1;
}
};
b; // 4
```
### 表达式的副作用
副作用通常是指执行了语句之后,除了返回值或赋值,还有其他变量等被修改。
最常见的副作用的表达式是函数调用:
```js
const foo = () => {
a = a + 1;
};
let a = 1;
foo(); // 结果undefined副作用a 的值被修改
```
### 上下文规则
在 JavaScript 语法规则中,有时候同样的语法在不同的情况下会有不同的解释。这些语法规则孤立起来会很难理解。
#### 大括号
大括号的作用有很多,随着 JavaScript 的演进可能会出现更多类似的情况。
**对象常量**
大括号可以使用表达式的方式定义对象:
```js
const a = {
foo: bar()
}
```
大括号内的内容被赋值给变量 a因而它是一个对象常量。
**标签**
将上述声明语句去掉,这时的大括号可不是一个孤立的对象常量。因为这里的`{...}`被看作了一个普通的代码块。这里的`foo: bar()`被解释为标签语句。
```js
{
foo: bar()
}
```
标签语句配合 continue 和 break 语句可以实现类似于 goto 的方式进行跳转。但 goto 是一种极为糟糕的编码方式,所以 JavaScript 并不支持真正的 goto 语句。
#### 代码块
有一个强制类型转换的坑经常被提到:
```js
[] + {} // "[object Object]"
{} + [] // 0
```
看上去简直就是 JavaScript 在和我们开玩笑。其实不然,上述情况并不是非常难以理解。
第一行是普通的强制类型转换,二者都会被强制转换字符串,而`[]`被转换为了`''``{}`被转换为了`"[object Object]"`,所以他们相加的最后结果就是`"[object Object]"`
第二行看上去有点莫名其妙,换个位置结果就变了。这里其实`{}`并没有参与运算,而是被当作了一段独立的空代码块。真正参与运算的是`+[]`,最终被转换为数字 0。
#### 对象解构
从 ES6 开始`{...}`也可用于解构赋值。
```js
const foo = () => {
return {
name: 'xfy',
age: 18,
};
};
const { name, age } = foo();
console.log(name, age);
```
同理,函数形参也可以利用解构赋值。
#### else if 和可选代码块
其实`else if`并不存在于 JavaScript 语法中,只是多个`if else`只包含单条语句的时候可以省略代码块的`{...}`
实际上`else if`是这样的:
```js
if (a) {
console.log(a);
} else {
if (b) {
console.log(b);
} else {
console.log(c);
}
}
```
## 运算符优先级
多数情况下JavaScript 的数学运算符与真正的数学一样,按照真正的数学的顺序进行运算。但 JavaScript 的语句并不是数学公式,而且语句中通常会充斥着各种各样的运算符。他们也是有各自的运算优先级的。
### 短路
and 与 or 操作拥有“短路”short circuiting的特性别急我们还没走错片场。在 JavaScript 中,他们分别是`&&``||`运算符。
短路的意思是,当左边的操作数能够得出结果时,就可以忽略右边的操作数。
对于`&&`来说,左边的操作数为假值时,则就没有必要再判断右边的值。同理,对于`||`来说,左边的操作数为真值时,也没有必要再判断右边的操作数。
### 关联
JavaScript 的代码是从上往下执行的,而单条语句是从左往右执行的。但在特定的运算符下,某些语句需要先求得右边的值。
例如:
```js
true ? false : true ? true : true;
```
这段代码乍一看很令人头疼,但它确实说明运算符的关联最容易理解的例子。在这里,第二个三目运算符的结果会影响第一个三目运算符,所以这里要执行右关联,也就是需要先求得第二个三目运算符的结果。
> 虽然是右关联,但它的运算顺序还是从左到右。`a ? b : c;`还是会先执行 a 然后 b c。
## 自动分号
有时 JavaScript 会自动为代码补上分号即分号自动插入机制Automatic Semicolon InsertionASI
ASI只会在换行符处起作用而不会在代码中间插入分号。
常见的情况是在 return 后自动加上,这样 return 后换行的代码就会不生效。return 语句可以跨越多行,但是其后必须右换行符以外的代码。
```js
const foo = () => {
return (
1 + 2
);
};
```
### 纠错机制
是否应该完全依赖 ASI 来编码,这是 JavaScript 社区中最具争议性的话题之一。
支持的一方认为 ASI 大有裨益,能省略掉那些不必要的`;`,让代码更简洁。此外 ASI 让许多`;`变得可有可无,因此只要代码没问题,有没有`;`都一样。
反方则认为 ASI 机制问题太多,对于缺乏经验的初学者尤其如此,因为自动插入`;`会无意改变代码的逻辑。有些人还认为依赖 linter 这些工具找出错误,而不是依赖 JavaScript 引擎。
事实上,现在多数`;`可以通过 ESlint 这样的 linter 工具来在格式化代码是插入。这种方式相比较用引擎来找出错误好很多,而且它不会在运行时改变代码原有的意思。
## 小结
JavaScript 语法规则中的许多细节需要我们多花时间和精力来了解。从长远来看,这有助于更深入地掌握这门语言。