You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

275 lines
9.2 KiB
Markdown

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# JavaScript语法什么是表达式语句
你好我是winter。
不知道你有没有注意到,我们在语句部分,讲到了很多种语句类型,但是,其实最终产生执行效果的语句不多。
事实上,真正能干活的就只有表达式语句,其它语句的作用都是产生各种结构,来控制表达式语句执行,或者改变表达式语句的意义。
今天的课程,我们就深入到表达式语句中来学习一下。
## 什么是表达式语句
表达式语句实际上就是一个表达式,它是由运算符连接变量或者直接量构成的(关于直接量我们在下一节详细讲解)。
一般来说,我们的表达式语句要么是函数调用,要么是赋值,要么是自增、自减,否则表达式计算的结果没有任何意义。
但是从语法上,并没有这样的限制,任何合法的表达式都可以当做表达式语句使用。比如我们看下面的例子。
```JavaScript
a + b;
```
这句代码计算了a和b相加的值但是不会显示出来也不会产生任何执行效果除非a和b是getter但是不妨碍它符合语法也能够被执行。
下面我们就一起来了解下都有哪些表达式,我们从粒度最小到粒度最大了解一下。
## PrimaryExpression 主要表达式
首先我们来给你讲解一下表达式的原子项Primary Expression。它是表达式的最小单位它所涉及的语法结构也是优先级最高的。
Primary Expression包含了各种“直接量”直接量就是直接用某种语法写出来的具有特定类型的值。我们已经知道在运行时有各种值比如数字123字符串Hello world所以通俗地讲直接量就是在代码中把它们写出来的语法。
我们在类型部分已经介绍过一些基本类型的直接量。比如我们当时用null关键字获取null值这个用法就是null直接量这里我们仅仅把它们简单回顾一下
```JavaScript
"abc";
123;
null;
true;
false;
```
除这些之外JavaScript还能够直接量的形式定义对象针对函数、类、数组、正则表达式等特殊对象类型JavaScript提供了语法层面的支持。
```JavaScript
({});
(function(){});
(class{ });
[];
/abc/g;
```
需要注意在语法层面function、{ 和class开头的表达式语句与声明语句有语法冲突所以我们要想使用这样的表达式必须加上括号来回避语法冲突。
在JavaScript标准中这些结构有的被称作直接量Literal有的被称作表达式\*\*Expression在我看来把它们都理解成直接量比较合适。
Primary Expression还可以是this或者变量在语法上把变量称作“标识符引用”。
```JavaScript
this;
myVar;
```
任何表达式加上圆括号都被认为是Primary Expression这个机制使得圆括号成为改变运算优先顺序的手段。
```JavaScript
(a + b);
```
这就是Primary Expression的几种形式了接下来我们讲讲由Primary Expression构成的更复杂的表达式Member Expression。
## MemberExpression 成员表达式
Member Expression通常是用于访问对象成员的。它有几种形式
```JavaScript
a.b;
a["b"];
new.target;
super.b;
```
前面两种用法都很好理解就是用标识符的属性访问和用字符串的属性访问。而new.target是个新加入的语法用于判断函数是否是被new调用super则是构造函数中用于访问父类的属性的语法。
从名字就可以看出Member Expression最初设计是为了属性访问的不过从语法结构需要以下两种在JavaScript标准中当做Member Expression
```JavaScript
f`a${b}c`;
```
这是一个是带函数的模板,这个带函数名的模板表示把模板的各个部分算好后传递给一个函数。
```JavaScript
new Cls();
```
另一个是带参数列表的new运算注意不带参数列表的new运算优先级更低不属于Member Expression。
实际上这两种被放入Member Expression仅仅意味着它们跟属性运算属于同一优先级没有任何语义上的关联。接下来我们看看Member Expression能组成什么。
## NewExpression NEW表达式
这种非常简单Member Expression加上new就是New Expression当然不加new也可以构成New ExpressionJavaScript中默认独立的高优先级表达式都可以构成低优先级表达式
注意这里的New Expression特指没有参数列表的表达式。我们看个稍微复杂的例子
```JavaScript
new new Cls(1);
```
直观看上去,它可能有两种意思:
```JavaScript
new (new Cls(1));
```
```JavaScript
new (new Cls)(1);
```
实际上,它等价于第一种。我们可以用以下代码来验证:
```JavaScript
class Cls{
constructor(n){
console.log("cls", n);
return class {
constructor(n) {
console.log("returned", n);
}
}
}
}
new (new Cls(1));
```
这段代码最后得到了下面这样的结果。
```
cls 1
returned undefined
```
这里就说明了1被当做调用Cls时的参数传入了。
## CallExpression 函数调用表达式
除了New ExpressionMember Expression还能构成Call Expression。它的基本形式是Member Expression后加一个括号里的参数列表或者我们可以用上super关键字代替Member Expression。
```JavaScript
a.b(c);
super();
```
这看起来很简单,但是它有一些变体。比如:
```JavaScript
a.b(c)(d)(e);
a.b(c)[3];
a.b(c).d;
a.b(c)`xyz`;
```
这些变体的形态跟Member Expression几乎是一一对应的。实际上我们可以理解为Member Expression中的某一子结构具有函数调用那么整个表达式就成为了一个Call Expression。
而Call Expression就失去了比New Expression优先级高的特性这是一个主要的区分。
## LeftHandSideExpression 左值表达式
接下来我们需要理解一个概念New Expression 和 Call Expression 统称LeftHandSideExpression左值表达式。
我们直观地讲左值表达式就是可以放到等号左边的表达式。JavaScript语法则是下面这样。
```JavaScript
a() = b;
```
这样的用法其实是符合语法的只是原生的JavaScript函数返回的值都不能被赋值。因此多数时候我们看到的赋值将会是Call Expression的其它形式
```JavaScript
a().c = b;
```
另外根据JavaScript运行时的设计不排除某些宿主会提供返回引用类型的函数这时候赋值就是有效的了。
左值表达式最经典的用法是用于构成赋值表达式但是其实如果你翻一翻JavaScript标准你会发现它出现在各种场合凡是需要“可以被修改的变量”的位置都能见到它的身影。
那么接下来我们就讲讲 AssignmentExpression 赋值表达式。
## AssignmentExpression 赋值表达式
AssignmentExpression 赋值表达式也有多种形态,最基本的当然是使用等号赋值:
```JavaScript
a = b
```
这里需要理解的一个稍微复杂的概念是,这个等号是可以嵌套的:
```JavaScript
a = b = c = d
```
这样的连续赋值,是右结合的,它等价于下面这种:
```JavaScript
a = (b = (c = d))
```
也就是说先把d的结果赋值给c再把整个表达式的结果赋值给b再赋值给a。
**当然,这并非一个很好的代码风格,我们讲解语法是为了让你理解这样的用法,而不是推荐你这样写代码。**
赋值表达式的使用,还可以结合一些运算符,例如:
```JavaScript
a += b;
```
相当于
```JavaScript
a = a + b;
```
能有这样用的运算符有下面这几种:
`*=`、`/=`、`%=`、`+=`、`-=`、`<<=`、`>>=`、`>>>=`、`&=`、`^=`、`|=`、`**=`
我想你已经注意到了,赋值表达式的等号左边和右边能用的表达式类型不一样,在这一课,我们已经关注完了表达式的左边部分(左值表达式)的语法结构,下一节课,我们将会给你重点讲解表达式的右边部分。
## Expression 表达式
赋值表达式可以构成Expression表达式的一部分。在JavaScript中表达式就是用逗号运算符连接的赋值表达式。
在JavaScript中比赋值运算优先级更低的就是逗号运算符了。我们可以把逗号可以理解为一种小型的分号。
```JavaScript
a = b, b = 1, null;
```
逗号分隔的表达式会顺次执行,就像不同的表达式语句一样。“整个表达式的结果”就是“最后一个逗号后的表达式结果”。比如我们文中的例子,整个`“a = b, b = 1, null;”`表达式的结果就是`“,”`后面的`null`。
在很多场合都不允许使用带逗号的表达式比如我们在前面课程中提到export后只能跟赋值表达式意思就是表达式中不能含有逗号。
## 结语
这节课我们开始讲解了运算符和表达式的一些相关知识,这节课上,我们已经学习了赋值表达式和赋值表达式的左边部分。下节课,我们将会讲一讲赋值表达式的右边部分。
最后给你留一个作业,把今天讲到的所有运算符按优先级排列成一个表格,下节课我们会补完剩下的部分。