笔记:《JavaScript学习指南》-第5章表达式和运算符

第5章 表达式和运算符
表达式是一种特殊的语句,它可以计算出一个值。非表达式语句不产生值。
非表达式语句通常会产生某种结果,但是只有表达式语句会对生成的结果做显式的转换。
因为表达式能解析成值,所以可以将它们与其他表达式组合在一起,进而将返回的结果再与其他表达式进行组合,以此类推。
表达式能解析成值,所以可以用它们来赋值。
let x,y;
x = 3 * 5;
y = x =  3 * 5;
第二行存在两个组合在一起的表达式。
第一个表达式是3 *5,结果为15
第二个表达式是15赋给变量x。赋值也是一个表达式。

JavaScript对表达式求值的顺序叫做运算符优先级。
大部分表达式,比如乘法和赋值,都是运算符表达式。
有两种非运算符表达式,它们是标识符表达式(变量名和常量名)和字面量表达式:变量和常量本身就是一个表达式,字面量也是。
表达式的本质:任何能够产生值的语句都是表达式。

5.1 运算符
可以认为运算符是表达式的“动作”。

5.2 算术运算符
JavaScript所有的数字都是双精度的,这意味着整数做算术运算的时候,有可能返回小数(如3/2,返回1.5)。
一元负号和一元正号的优先级高于加减法运算。
一元正号通常是强制将字符串转换成数字,或者调整那些否定的值。

自增和自减运算符实际上是将赋值和加(减)法运算结合在一起。
前置运算符修改了变量,表达式的值是修改后的值;后置运算符也修改了变量,但是表达式的值没有变。
var x = 2, y = 10;

//分别运行
x++ + x++;     //5
++x + ++x;    //7

x++ + ++x;    //6
++x + x++;    //6

y-- + y--;    //19
--y + --y;    //17

x++ + y--;    //12
x++ + y++;    //12

++x + y++;    //13

5.3 运算符优先级
括号具有最高优先级。同一优先级按从左到右的顺序执行。
赋值运算符则是从右到左。

5.4 比较运算符
有三种类型的比较运算符:严格相等、非严格相等、相关性。
建议始终选择严格相等运算符。

严格相等(===),其否定形式(!==);
非严格相等(==),其否定形式(!=);

关系运算符比较的是两个值的关系。仅仅适用于拥有自然排序特性的数据类型。
关系运算符有小于( < )、小于等于( <= )、大于( > )、大于等于( >= )。

5.5 比较数字
特殊的数值NaN与任何值都不相等,包括它自己。使用内置函数isNaN()测试:如果 x 是NaN,isNaN(x)会返回true。

let n = 0;
while(true){
    n += 0.1;
    if(n === 0.3) break;
}
console.log(`Stopped at ${n}`);
while循环跳过了0.3,无限地执行下去了。因为0.1并不能精确地表示一个双精度数值,它介于两个二进制小数之间。
使用Number.EPSILON重新设置上面的循环:
let n = 0;
while(true){
    n += 0.1;
    if(Math.abs(n - 0.3) < Number.EPSILON) break;
}
console.log(`Stopped at ${n}`);     //Stopped at 0.30000000000000004
Number.EPSILON是一个数值常量,这个值非常小。Math.abs取绝对值。
取绝对值来比较两个值是否足够接近,是测试两个双精度数值是否相等的通用方法。

5.6 字符串连接
+运算符可以做数字的加法,也可以用作字符串连接。

5.7 逻辑运算符
逻辑运算符只关心布尔值,且只有两种值:true 或 false。
真值和假值
代表false的有:
  • undefined
  • null
  • false
  • 0
  • NaN
  • ""(空字符串)

其他值都是真,包括:
  • 仅仅包含空格的字符串
  • 字符串“false”。
  • 所有数组,包括空数组
  • 所有对象

如果想让空数组arr的值为假,使用arr.length(空数组返回0, 0代表假)可以达成目的。

5.8 与、或、非
三种逻辑运算符:与 &&  , 或 ||  , 非 !
有时候,或运算符又叫做“同或”,因为如果两个值都为true,结果就为true。
存在“异或”XOR,当两个值为true时,它的值为false。JavaScript不支持XOR运算符,但它有一个位异或运算符( ^)。

如果要对变量 x 和 y 做异或运算,可以使用等价表达式。
(x || y) && x !== y
//x和y为真的情况下,会返回false

5.8.1 短路求值
对于x && y,如果 x 是 false,不管 y 的值是什么,结果都为 false。
对于x || y,如果 x 是 true,不管 y 的值是什么,结果都为true。

const skipIt = true;
let x = 0;
const result = skipIt || x++;
result;     //true
由于短路求值,x的自增表达式没有执行,所以 x 的值还是 0 。如果将skipIt改为false,两个表达式都会被执行。在这里,自增就是副作用。
自增执行后,result的变成了 0。result为什么是 0 而不是 false?看下一主题。

5.8.2 非布尔值的逻辑运算符
如果使用布尔值做逻辑运算,结果只能为布尔值。如果使用非布尔值,能够确定结果的那个值就是逻辑运算的结果。

对于 x && y 。x 和 y 都为 true时, 返回 y;x 或 y 有 false 时,优先返回 x 为 false 的 x 。
对于 x || y 。x 和 y 都为 false时, 返回 y; x 或 y 有 true 时,优先返回 x 为 true 的 x 。
const options = suppliedOptions || {name: "Default"};
如果suppliedOptions是一个对象,options 将引用 suppliedOptions。如果suppliedOptions 的值是null 或undefined,options也会有一个默认值。
使用 !非运算符 ,永远返回布尔值。

5.8.3 条件运算符
也称三元运算符,它有三个操作数(其他运算符都是一个或两个)。
const doIt = false;
const result = doIt ? "Did it!" : "Don't do it.";
如果第一个操作数为真,执行第二个操作数;否则执行第三个操作数。

5.8.4 逗号运算符
逗号运算符可以简单的将表达式组合起来:他会按顺序执行两个表达式,并返回第二个表达式的结果。
let x = 0, y = 10, z;
z = (x++, y++);
x 和 y 都自增了,z 最后的值为10。逗号的优先级是最低的,所以用了括号,否则会先赋值。

5.9 分组运算符
分组运算符除了修改或澄清运算符的优先级外,没有任何影响。

5.9.1 位运算符
位运算符允许在每个二进制位上执行操作。
位运算符将其操作数当成二进制补码格式的 32 位有符号整型数字。
因为JavaScript中,所有数字都是双精度的,JavaScript在执行位运算前会先将数字转换成 32 位的整型,并在返回结果之前转换回来。
位运算符是在整型的每一个二进制位上进行逻辑操作(与、或、非、异或)。还包含二进制位进行位移的位移运算符。

左移位实际上是乘以 2,右移位则是除以 2 然后舍去位数。
存在两种补码,最左边的二进制位为 1 时表示负数,0 表示整数。

5.9.2 类型判断运算符
类型判断运算符返回一个字符串形式的类型名称。
typeof的类型判断:

typeof 不能正确判断数组,typeof [],返回“object”。

5.9.3 void运算符
void的用途:计算它的操作数并返回undefined。
它可以强制表达式返回undefined。
常被用作HTML 标签<a>的URI:
<a href="javascript:void 0">Do nothing.</a>

5.9.4 赋值运算符
赋值运算符:将一个值指派给某个变量。
等号左边必须是变量、属性或者数组元素。
链式赋值:
let v, v0;
v = v0 = 1;    //链式赋值,首先给v0 赋值1,然后给 v 赋值 1.
 
运算中赋值:


5.10 解构赋值
ES6新特性。
解构赋值,允许将一个对象或者数组“分解”成多个单独的值。
const obj = { b: 2, c: 3, d: 4 };

//对象解构赋值
const {a,b,c} = obj;

a;    //undefined
b;    //2
c;    //3
d;    //引用error:"d" 未定义
解构对象时,变量名必须与对象中的属性名保持一致(数组解构只能指派那些作为标识符的属性名)。
上面例子中,如果没有const进行声明,JavaScript会认为左边是一个代码块,会报错。可以添加括号运算符。
const obj = {b: 2, c: 3, d: 4};
let a, b, c;

//会报错
{a, b, c} = obj;

//正常运行
({a, b, c} = obj);

数组解构时,可以给数组的元素任意指定变量名(按顺序)。
const arr = [1, 2, 3];

//数组解构赋值
let [x, y] = arr;
x;    //1
y;    //2
z;    //错误:z 未定义
这个例子中,x 接受了数组的第一个元素,y 接受了第二个元素,所有没被接受的元素都被丢弃了。
也可以把剩下的元素放入一个新的数组中,用  展开运算符( ... )。第六章学习这个运算符。
const arr = [1, 2, 3, 4, 5];
let [x, y, ...rest] = arr;
x;    //1
y;    //2
rest;    //[3, 4, 5]

数组解构可以很方便的交换变量的值。
let a = 5, b = 10;
[a, b] = [b, a];
a;    //10
b;    //5

数组解构不仅适用于数组,还适用于任何可迭代的对象。

5.11 对象和数组运算符


5.12 模板字符串中的表达式
第 3 章中介绍。

5.13表达式和控制流模式
5.13.1 将 if ... else 语句转化成条件表达式
if(isPrime(n)){
    label = "prime";
}else{
    label = "non-prime";
}

//可以写成

label = isPrime(n) ? "prime" : "non-prime";

5.13.2 将 if 语句转化成短路求值的逻辑或( || )表达式
if(!option) option = {};

//可以写成

options = options || {};
 

猜你喜欢

转载自blog.csdn.net/kjhz_liang/article/details/80525468