【JavaScript】6.语言基础 - 操作符、语句

本篇笔记示例代码仓库:https://github.com/zhangtuo1999/study-js 。

本篇笔记遵循中文技术文档的写作规范

主要内容来源于《JavaScript高级程序设计(第4版)》,部分内容来源于MDN Web Docs

操作符

1 一元操作符

只操作一个值的操作符叫一元操作符。

1.1 自增自减 ++--

++--用法照搬 C 语言。不仅可以用在数值类型上,用在其它类型上的规则如下:

  1. 对于字符串,如果是有效的数值形式,则转换为数值后再应用改变。如果不是有效的形式,则将变量的值设置为 NaN
  2. 对于布尔值,如果是 false,则转换成0后再应用改变。如果是 true,则转换成1后再应用改变。
  3. 如果是对象,则调用其 valueOf() 方法取得可以操作的值。接着应用上述的规则。如果是 NaN,则调用 toString() 并再次应用其它规则。

注意:使用自增或者自减操作符后,变量的类型会转变成数值

1.2 正负+-

在非数值类型的变量前使用加号,则会执行与使用 Number() 转型函数一样类型转换。

在非数值类型的变量前使用减号,则先会执行与使用Number() 转型函数一样类型转换,再转成负数。

2 位操作符

位操作符用来操作内存中表示数据的比特。ECMAScript 使用 IEEE 754 64 位存储,但是位操作不能直接操作 64 位。因此会先把数值转换成 32 位整数然后进行位操作,随后将结果转换为 64 位。对于开发者,就像只有 32 位一样。

2.1 正数和负数在内存中的表示形式

有符号整数使用 32 位的前 31 位表示整数值,第 32 位是符号位。比如 0 正 1 负。

负数使用二补数进行存储,通过三个步骤得到二补数:绝对值取反加一。比如:

18:
0000 0000 0000 0000 0000 0000 0001 0010

-18:
1. 绝对值
0000 0000 0000 0000 0000 0000 0001 0010
2. 取反
1111 1111 1111 1111 1111 1111 1110 1101
3. 加一
1111 1111 1111 1111 1111 1111 1110 1110

使用 toString() 方法来输出负数的二进制表示:

let a = -18
console.log(a.toString(2)); // -10010

对非数值类型进行位操作,会先使用 Number() 方法将该值转换为数值,之后再进行位操作。

2.2 按位非 ~

使用~对操作数的每个比特位进行取反。最终效果是对数值进行取反减一

let num = 15
console.log(~num);  // -16

2.3 按位与 &

使用&对两个操作数进行按位与。规则如下:两个比特位,如果都是1,则该位结果是1,否则是0。

2.4 按位或 |

使用|对两个操作数进行按位或。规则如下:两个比特位,只要有一位是1,则该位结果是1,否则是0。

2.5 按位异或 ^

使用^对两个操作数按位异或。规则如下:两个比特位,有且仅有一位是1时,该位结果是1,否则是0。

2.6 左移 <<

使用<<会对操作数的所有位向左移动。左移会保留符号

let num = 2
console.log(num<<5);  // 64

2.7 有符号右移 >>

使用>>会对操作数的所有位向右移动。有符号右移会保留符号

let num = 32;
console.log(num >> 3);  // 4

2.8 无符号右移>>>

使用>>>会对操作数的所有位向右移动。对于正数,无符号右移和有符号右移结果相同。对于负数,无符号右移会将负数的二补数当作正数来处理,所以无符号右移之后结果变得会非常大。

let num = -32;
console.log(num >>> 3); // 536870908

3 布尔操作符

3.1 逻辑非 !

使用!会对操作数进行取反。

如果应用到非布尔值,首先转换为布尔值,随后进行取反。使用!!,相当于对操作数使用Boolean()函数。

3.2 逻辑与 &&

&& 有两个操作数。两个操作数中,只有都为 true,才返回 true,否则返回 false。

如果应用到非布尔值,逻辑与不一定返回布尔值,规则如下:

  1. 如果第一个数是对象,则返回第二个操作数。
  2. 如果第二个操作数是对象,只有第一个操作数求值为 true 时,才会返回该对象。
  3. 如果有一个操作数是 null,则返回 null。
  4. 如果有一个操作数是 NaN,则返回 NaN。
  5. 如果有一个操作数是 undefined,则返回 undefined。
  6. 如果两个操作数是 null、NaN、undefined,则返回第一个操作数。

逻辑与有短路特性:如果第一个操作符决定了结果,那么永远不会对第二个操作符求值。对于逻辑与,如果第一个操作符是 false,那么永远不会对第二个操作符进行求值。

let a = false && b;		// 即使 b 没有被定义也不会出错,因为不会执行 && 后面

3.3 逻辑或 ||

|| 有两个操作数。两个操作数中,只要有一个为 true,就返回 true,否则返回 false。

如果应用到非布尔值,逻辑或不一定返回布尔值,规则如下:

  1. 如果第一个数是对象,则返回第一个操作数。
  2. 如果第一个操作数求值是 false,则返回第二个操作数。
  3. 如果两个操作数都是 null,则返回 null。
  4. 如果两个操作数都是 NaN,则返回 NaN。
  5. 如果两个操作数都是 undefined,则返回 undefined。

逻辑或也有短路特性。对于逻辑或,如果第一个操作符是 true,那么永远不会对第二个操作符进行求值。

let a = true || b;
console.log(a);

特别的,利用这个特性,可以避免给变量赋值 null 或者 undefined:

let a = obj1 || obj2

如果 obj1 不是 null 或者 undefined,则 a 被赋值为 obj1,否则赋值为 obj2。

4 乘法 *,除法 /,取模 %,指数 **

4.1 乘法

如果两个操作数中有非数值,则会先调用 Number() 转型函数转换为数值。特别的:

  1. Infinity 乘以0,则返回 NaN。
  2. Infinity 乘以非0有限数值,根据第二个操作数的符号返回 Infinity 或 -Infinity。
  3. Infinity 乘以 Infinity,则返回 Infinity。

4.2 除法

如果两个操作数中有非数值,则会先调用 Number() 转型函数转换为数值。特别的:

  1. Infinity 除以 Infinity,则返回 NaN。
  2. 0 除以 0,返回 NaN。
  3. 非0有限数值除以0,根据第一个操作数的符号返回 Infinity 或 -Infinity。
  4. Infinity 除以任何数值,根据第二个操作数的符号返回 Infinity 或 -Infinity。

4.3 取模

如果两个操作数中有非数值,则会先调用 Number() 转型函数转换为数值。特别的:

  1. 被除数是无限值,除数是有限值,则返回NaN。
  2. 被除数是有限值,除数是无限值,则返回被除数。
  3. 被除数是有限值,除数是0,则返回NaN。
  4. Infinity 除以 Infinity,则返回 NaN。
  5. 被除数是0,除数不是0,则返回0。

结果的符号和被除数相同

console.log(10 % 6);	// 4
console.log(10 % -6);	// 4
console.log(-10 % 6);	// -4
console.log(-10 % -6);	// -4

4.4 指数操作符**

console.log(Math.pow(3,2));		// 9
console.log(3**2);				// 9

5 加法+、减法-

5.1 加法

如果两个操作数都是数值,运算规则如下:

  1. 任一操作数是 NaN,返回 NaN。

  2. Infinity + Infinity = Infinity
    -Infinity + -Infinity = -Infinity
    -Infinity + Infinity = NaN
    
  3. +0 + +0 = +0
    -0 + +0 = +0
    -0 + -0 = -0
    

如果有一个操作数是字符串,运算规则如下:

  1. 如果都是字符串,则将第二个字符串拼接到第一个字符串后面
  2. 如果只有一个操作符是字符串,则将另一个操作符转为字符串,再将两个字符串拼接到一起。

如果有任一操作数是对象数值布尔值,则调用toString()方法获取字符串,随后应用上述规则。

如果是undefinednull则调用String()函数,分别获取为"undefined"和"null"。

5.2 减法

如果两个数字是数值,则执行运算并返回结果。其余规则:

  1. 任一操作数是 NaN,返回 NaN。

  2. Infinity - Infinity = NaN
    -Infinity - -Infinity = NaN
    Infinity - -Infinity = Infinity
    -Infinity - Infinity = -Infinity
    
  3. +0 - +0 = +0
    +0 - -0 = -0
    -0 - -0 = +0
    

如果有任一操作数是字符串布尔值nullundefined,先在后台使用 Number() 转为数值,随后执行以上规则。

如果任意操作数是对象,则调用 valueoOf() 方法取得数值。如果对象没有 valueOf() 方法,则调用 toString() 方法,然后将得到的字符串转换为数值。

6 关系操作符

规则如下:

  1. 如果两个操作数都是数值,执行数值比较。
  2. 如果两个操作数都是字符串,则逐个比较字符串中对应的编码。(大写字符编码小于小写字符)
  3. 如果有任一操作数是数值,则将另一个操作数转换为数值,再执行比较。
  4. 任何涉及 NaN 的比较都返回 false。
  5. 如果有任一操作数是对象,则调用其 valueOf() 方法,将取得的结果按上述规则比较。如果没有 valueOf() 方法,则调用 toString() 方法,将取得的结果按上述规则比较。
  6. 如果有任一操作数是布尔值,则将其转为数值再比较。

7 相等操作符

有两组操作符,第一组是等于和不等于,它们在比较前执行转换。第二组是全等和不全等,它们在比较前不会发生转换。

7.1 等于和不等于

==!=会先对操作数进行强制类型转换,再判断操作数是否相等。规则如下:

  • 如果两个操作数都是对象,则仅当两个操作数都引用同一个对象时才返回true
  • 如果一个操作数是null,另一个操作数是undefined,则返回true
  • 如果两个操作数是不同类型的,就会尝试在比较之前将它们转换为相同类型:
    • 当数字与字符串进行比较时,会尝试将字符串转换为数字值。
    • 如果操作数之一是Boolean,则将布尔操作数转换为1或0。
      • 如果是true,则转换为1
      • 如果是 false,则转换为0
    • 如果操作数之一是对象,另一个是数字或字符串,会尝试使用对象的valueOf()toString()方法将对象转换为原始值。
  • 如果操作数具有相同的类型,则将它们进行如下比较:
    • Stringtrue仅当两个操作数具有相同顺序的相同字符时才返回。
    • Numbertrue仅当两个操作数具有相同的值时才返回。+0并被-0视为相同的值。如果任一操作数为NaN,则返回false
    • Booleantrue仅当操作数为两个true或两个false时才返回true

7.2 全等和不全等

===!==不会对操作数进行强制类型转换。与相等运算符不同,全等运算符总是认为不同类型的操作数是不同的。规则如下:

  • 如果操作数的类型不同,则返回 false
  • 如果两个操作数都是对象,只有当它们指向同一个对象时才返回 true
  • 如果两个操作数都为 null,或者两个操作数都为 undefined,返回 true
  • 如果两个操作数有任意一个为 NaN,返回 false
  • 否则,比较两个操作数的值:
    • 数字类型必须拥有相同的数值。+0-0 会被认为是相同的值。
    • 字符串类型必须拥有相同顺序的相同字符。
    • 布尔运算符必须同时为 true 或同时为 false

8 三元操作符

let num1 = 10
let num2 = 5
let max = num1 > num2 ? num1 : num2

9 赋值操作符 =

复合赋值操作符:+=-=等等

10 逗号操作符 ,

  1. 一条语句中执行多个操作

    let a = 1,b = 2,c = 3
    
  2. 赋值时,使用逗号分隔值,最终会返回最后一个值

    let num = (1,2,3,4,5) 	// num = 5
    

语句

1 if、do-while、while、for

2 for-in

for-in 语句用来枚举对象中非符号属性,例如:

const obj = {
    a: 1,
    b: 2,
    [Symbol("foo")]: 'foo',
};
for (let prop in obj) {
    console.log(prop, obj[prop]);	// a 1   b 2 
}

注意:

  1. ECMAScript 中对象的属性是无序的,因此 for-in 无法保证对象属性的顺序。
  2. 如果要迭代的变量是 null 或 undefined,则不会执行循环体。

3 for-of

for-of 用来遍历可迭代对象的元素,例如:

const nums = [1, 2, 3];
for (const item of nums) {
    console.log(item);		// 1 2 3
}

注意:如果尝试迭代的对象不支持迭代,for-of 会抛出错误。

4 标签语句 配合 break 和 continue

4.1 标签语句

格式:标签:语句,例如:

flag:let a = 1

4.2 配合 break 和 continue

flag: for (let i = 1; i < 10; i++) {
    for (let j = 1; j < 10; j++) {
        if (j % 5 === 0) continue flag;
        console.log(i, j);
    }
}

执行到 break 和 continue 时,会跳转到指定的位置继续执行。

5 with 语句

with 语句的用途是将代码的作用域设置为特定的对象,比如:

const obj ={
    a:1,
    b:2,
    c:3,
    d:4
}
with(obj){
    console.log(a);		// 1
    console.log(b);		// 2
    console.log(c);		// 3
    let d = 400;
    console.log(d);		// 400
    console.log(e); 	//报错
}

注意:

  1. 在语句内部,每个变量会先被认为是局部变量。如果没有找到局部变量,就去 with 后面的对象身上去找。如果还找不到就报错。
  2. with 影响性能并且难以调试,因此不建议使用 with 语句。

6 switch 语句

注意:switch 语句在比较每个条件的值时,使用的是全等操作符

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值