我们今天讨论下js的语法规则,尽管我们都能熟练使用js进行编程,但我想深入理解的话,其实还是会有我们所不知道的知识点,下面让我们一起探索js语法。这章节关联的知识点关联性比较强,需要重头到位仔细咀嚼~
语句和表达式
在JS中,“语句” 就跟现实生活中的 “句子” 一样,表示一句话的说完,同时具有完整的意义。而 “表达式” 就相当于 “句子” 中的短语、名词,“运算符”相当于标点符号和连接词。
JS中表达式可以返回一个结果值,我们来看个例子:
var a = 4 * 5;
var b = a;
b;
这里,第一行的4 * 5是一个表达式(结果是20),第二行的 a 也是表达式,第三行的 b 也是。a 和 b 的结果值都是 20。
上面的例子中,三行都是一个包含表达式的 “语句”。var a = 4 * 5 和 var b = a 是 声明表达式 。声明了变量,同时可以对其进行赋值。a = 4 * 5 和 b = a 是 赋值表达式 (没有包含 var)。第三行的b只有一个表达式,同时它也是一个 “语句”,我们称为 “表达式语句”。
语句的都有一个结果值
平时在日常开发中,都会用到浏览器的控制台。不知道你有没有发现,我们在控制台调试的时候,总会发现一段语句执行后,语句或者表达式的下方都会出现 undefined 或者其他值。
其实,语句都有一个结果值。而上面的截图中,显示的就是语句的结果值。那么如果是 if else 这样的代码块,是否有返回值呢?他的返回值是什么?
看截图我们发现,代码块也是有返回结果值的,并且总是最后一个语句的结果值。
但是语句的结果值我们是不能获取的,原因当然是JS的语法规定我们不能这样做。
// 会报错
var a, b;
a = if (true) {
b = 1 + 1;
}
表达式的副作用
副作用:在主要作用以外附带产生的作用。
通常的表达式中都不会有什么副作用。例如下面的例子:
var a = 5;
var b = a + 3;
表达式 a + 3 本身没有什么副作用,它的结果值为 8 ,然后通过赋值表达式赋值给了 b 。
常见的产生副作用的表达式是函数调用:
var a = 1;
function foo() {
a = a + 3;
}
foo(); // 结果值是 undefined;副作用是改变了 a 的值。
为什么说副作用的,因为你是单纯的调用函数,但实际函数内部对外部的 a 做了新的赋值,所以在调用函数的同时,顺带产生了对 a 进行赋值的副作用。当然,如果你的函数没有引用外部的值,也不会产生副作用。
我们再看看其他表达式的副作用
递增/递减运算符
var a = 42;
var b = a++; // 42;
a // 43;
b // 42;
上面的例子中,语句var b = a++;中,递增表达式a++,产生了副作用,先返回了结果值,结果值被赋给变量b,然后将a的值加1.
但是前置/后置的递增/递减,为什么导致值的不同呢?这是因为 ++ 运算符产生的副作用的时间不同。
++在前面时,如 ++a,它的副作用(将a递增)产生在表达式返回结果值之前,而 a++ 的副作用则产生在之后。所以就要有了语句var b = a++;中,a的结果值42赋值给了b之后,a进行了递增。
再如delete运算符,它通常以表达式语句出现(作用,删除对象中的属性和数组中的单元)。
var obj = {
a: 1
}
obj.a // 1
delete obj.a // true
obj.a // undefined
如果删除成功,delete返回true,否则返回false。其副作用是属性被从对象中删除(或者单元从对象中删除)。
上下文规则
上下文在JavaScript中是一个比较抽象的概念,就拿我们高中时的阅读理解为例子,一整篇文章比作一个全局上下文,里面包含了文章的各种信息(人物,背景,语境等)。一个段落也是一个局部上下文,里面也包含着它持有的信息。
JavaScript中,有时相同的语法在不同的情况下也会有不同的意思。下面我们来了解一下我们最常见的花括号。
1.花括号{}
- 对象常量:我们知道定义一个对象常量,可以这样写
var obj = {};其中{}被作为一个对象赋值给了obj。 - 标签语句:这个语法特性由于平时开发过程中基本没见过,同时它的代码十分晦涩难懂,也不建议使用。有兴趣的话可以自己研究。
2.代码块
{}可以作为一个代码块。就好比函数后面的花括号一样,只不过不携带函数名。
{
var a = 1;
console.log(a); // 1
}
我们看下这个例子:
[] + {}; // "[object Object]"
{} + []; // 0
第一行之所以是"[object Object]"是因为中间发生了类型转换,[]被转化成了空字符串""。然后空字符串+ {}就有了后面的结果。
第二行:前面的{}其实是个空代码块,并且里面没有执行任何操作。代码结尾不需要分号,所以不存在语法错误。随后的 + [],是一个显示数字类型转换,把 [] 转成了数字0。
3.解构赋值
ES6开始支持的对象解构。
function getData() {
return {
a: 42,
b: "foo"
}
}
var { a, b } = getData();
console.log(a, b); // 42 "foo"
4.else if 和可选代码块
很多人误以为JS中有 else if,其实在JS中是不存在这个短语的。它其实是有由可选代码块这一特性演变过来的。
我们知道,如果 if 和 else 后面只跟一条语句的话,是可以把{}忽略的。
var a = 'foo';
if(a === 'foo') return 11;
if(a){
} else if(b) {
} else {
}
// 实际上等于
if(a){
} else {
if(b) {
} else {
}
}
由于if(b){} else {}这个判断,其实本身就是一条判断语句,因为前面我们说过,if 和 else 后面只跟一条语句的话,是可以把{}忽略的。所以我们选择性的忽略了 else 后面的 {}。这样就有了 else if。