变量-操作符
基础
注释
// single line comment
/* This is a multi-line comment */
Strict Mode
strict mode
- 特殊模式;
- 禁止不稳定行为;
开启方式
// 全局开启
"use strict";
// ..;
// 局部位置开启
function doSomething() {
"use strict";
// ..;
}
变量
声明变量
声明变量
- 未初始化赋值 undefined;
let message;
let message, found, age;
let message = "hi";
变量赋值的本质
- 储存的并不是变量值本身;
- 而是变量值在栈中的内存地址;
不同关键字混合声明
- 关键字并非定义不同变量, 而是指明变量作用域;
var name;
let name; // SyntaxError
let age;
var age; // SyntaxError
命名规则
变量
- 大小写敏感;
- 字母 + 下划线 + $ + 数字;
- 字母, 下划线和 $ 开头;
- 小驼峰;
常量
- 大写字母 + 下划线;
不声明
- 自动添加至 global context (window/globalThis);
- 推荐不要使用;
var 声明
作用域
- 函数作用域;
- 浏览器环境绑定至 windows 上;
- node 不会绑定在 globalThis 上;
变量提升
- var 声明会自动提升至所在作用域的顶端;
var name = "Jake";
// 等效于
name = "Jake";
var name;
声明前使用 var 变量
- var 变量赋值为 undefined;
console.log(name); // undefined
var name = "Jake";
重复声明
- var 允许重复声明;
var name;
var name;
let 声明
作用域
- 块作用域: 包裹的区域;
重复声明
- let 不允许重复声明;
let age;
let age; // SyntaxError; identifier 'age' has already been declared
变量提升
- let 不会发生变量提升;
console.log(age); // ReferenceError: age is not defined
let age = 26;
全局声明
- let 出现在全局上下文时, 具有全局作用域;
- 但不会绑定到 window 上;
let age = 26;
console.log(window.age); // undefined
const 声明
机制
- 与 let 基本一致;
初始化
- const 声明后必须初始化;
- const 声明变量不可修改;
更快的 const
- 使用 const 声明时;
- 编译器直接用其实际值进行替换;
- 节约查变量表的时间;
关键字和保留字
关键字一览
| break | do | in | typeof |
| case | else | instanceof | var |
| catch | export | new | void |
| class | extends | return | while |
| const | finally | super | with |
| continue | for | switch | yield |
| debugger | function | this | |
| default | if | throw | |
| delete | import | try |
保留关键字一览
| enum | ||
| implements | package | public |
| interface | protected | static |
| let | private | |
| await |
操作符
一元操作符
自增自减操作符
// ++x, 先自增再返回值
// --x, 先自减再返回值
// x++, 先返回值再自增
// x--, 先返回值再自减
let num1 = 29;
let num2 = --num1 + 2; // 30
let num3 = num1-- + 2; // 31
一元加减运算符
| 操作符 | 机制 |
|---|---|
| + (一元) | 正值, 无左操作数等效于 Number() 函数 |
| - (一元) | 负值, 无左操作数等效于 -Number() 函数 |
位操作符
| 操作符 | 机制 |
|---|---|
| ~ | 按位非 |
| & | 按位与 |
| | | 按位或 |
| ^ | 按位异或 |
| << | 左移, 保留符号位 |
| >> | 右移, 保留符号位 |
| >>> | 右移, 不保留符号位, 负数差距较大, 正数不影响 |
逻辑操作符
逻辑操作符
| 操作符 | 含义 | 机制 | 应用 |
|---|---|---|---|
| !expr | 非 | 转换为 boolean 并取反 | !! 等效于 Boolean() |
| expr1 && expr2 | 与 | 一假即假, 全真才真 | 若 expr1 为真, 返回 expr2, 反之返回 expr1 |
| expr1 || expr2 | 或 | 一真即真, 全假才假 | 若 expr1 为假, 返回 expr2, 反之返回 expr1 |
| expr1 ?? expr2 | 空值合并 | 返回第一个不为 null 或 undefined 的值 | 无 |
短路机制
- false && anything, 返回 false, anything 不被计算;
- true || anything 返回 true, anything 不被计算;
|| 与 ?? 的区别
- || 返回第一个真值, 即无法区分 false, 0 和 "";
- ? ? 返回第一个已定义的值;
let height = 0;
height || 100; // 100
height ?? 100; // 0
四则运算操作符
基本语法
let result = 34 * 56; // 乘
let result = 66 / 11; // 除
let result = 26 % 5; // 取余
let result = 3 ** 2; // 幂运算, 等效于 Math.pow(3, 2)
let result = 1 + 2; // 加
let result = 2 - 1; // 减
关系运算符
| 运算符 | 机制 |
|---|---|
| > | 若左操作数大于右操作数返回 true, 反之返回 false |
| >= | 若左操作数大于等于右操作数返回 true, 反之返回 false |
| <= | 若左操作数小于右操作数返回 true, 反之返回 false |
| <= | 若左操作数小于等于右操作数返回 true, 反之返回 false |
判等操作符
简单判等
| 运算符 | 机制 |
|---|---|
| == | 若转换后的操作数相等返回 true, 反之返回 false |
| != | 若转换后的操作数不相等返回 true, 反之返回 false |
严格判等
| 运算符 | 机制 |
|---|---|
| === | 若不经转换的操作数相等且类型相同返回 true, 反之返回 false |
| !== | 若不经转换的操作数不相等或类型不相同返回 true, 反之返回 false |
条件操作符
// boolean_expression 为真返回 true_value, 反之返回 false_value
variable = boolean_expression ? true_value : false_value;
赋值操作符
| Name | Shorthand operator | Meaning |
|---|---|---|
| 赋值 | x = f() | x = f() |
| 加赋值 | x += f() | x = x + f() |
| 减赋值 | x -= f() | x = x - f() |
| 乘赋值 | x *= f() | x = x * f() |
| 除赋值 | x /= f() | x = x / f() |
| 取余赋值 | x %= f() | x = x % f() |
| 乘方赋值 | x **= f() | x = x ** f() |
| 左移赋值 | x <<= f() | x = x << f() |
| 右移赋值 | x >>= f() | x = x >> f() |
| 无符号右移赋值 | x >>>= f() | x = x >>> f() |
逗号操作符
- 分割表达式;
- 返回最后一个操作符的值;
let num = (5, 1, 4, 8, 0); // num becomes 0
优先级和结合性
优先级
- 运算符的优先次序;
结合性
- 相同优先级运算符的执行顺序;
优先级和结合性列表
| Operator type | Individual operators | Associativity |
|---|---|---|
| member | . [] | left-to-right |
| call / create instance | () new | left-to-right |
| negation/increment | ! ~ - -- + ++ -- typeof void delete | right-to-left |
| exponentiate | ** | right-to-left |
| multiply/divide | * / % | left-to-right |
| addition/subtraction | + - | left-to-right |
| bitwise shift | << >> >>> | left-to-right |
| relational | < <= > >= in instanceof | left-to-right |
| equality | == != === !== | left-to-right |
| bitwise-and | & | left-to-right |
| bitwise-xor | ^ | left-to-right |
| bitwise-or | | | left-to-right |
| logical-and | && | left-to-right |
| logical-or | || | left-to-right |
| conditional | ?: | right-to-left |
| assignment | = += -= **= *= /= %= <<= >>= >>>= &= ^= |= &&= ||= ??= | right-to-left |
| comma | , | left-to-right |
提高优先级
- 使用 ();
隐式转换和比较机制
四则运算转换规则
- 任一操作数为非数字, 自动执行 Number() 函数;
- + 中任一操作数为字符串, 非字符串操作数自动执行 String() 函数;
四则运算计算规则
- 两个数字返回计算结果, 若超范围返回对应 Infinity;
- 任一操作数为 NaN, 返回 NaN;
- 若计算无效, 返回 NaN;
- 其中一个操作数为 (-)Infinity;
- 乘除 0: NaN;
- 无逻辑上的结果: NaN;
- 其余: Infinity;
关系运算符比较规则
- 若均为数字, 比较数字大小;
- 若均为 string, 比较对应字符中第一个不同的字符的字符编码;
- 若任一为数字, 另一转换为数字;
- 若任一为 object;
- 首先执行 valueOf() 返回 number;
- 其次执行 toString(), 返回 string;
- 任一为 NaN, 返回 false;
简单判定机制
- 若任一操作符为非数字, 利用 Number() 将其转换为数字;
- 若仅有一个为 object;
- 仅执行 valueOf() 返回 number;
- null 和 undefined 相等;
- 任一为 NaN;
- == 返回 false;
- != 返回 true;
- 均为 object, 判断两者是否指向同一个 object;
最佳实践
变量使用
使用原则
- 推荐不要使用 var;
- 推荐使用 let 和 const;
- 能用 const 就用 const;
循环中的变量声明
var 声明
for (var i = 0; i < 5; ++i) {
setTimeout(() => console.log(i), 0);
}
// It will actually console.log 5, 5, 5, 5, 5
let 声明
// 每一次循环声明一个新的变量;
// 每个 setTimeout() 引用五个不同的变量;
for (let i = 0; i < 5; ++i) {
setTimeout(() => console.log(i), 0);
}
// console.logs 0, 1, 2, 3, 4
const 变量
- const 无法声明循环迭代器;
同名变量和同名函数
同名变量
- 使用忽略原则, 后声明的被忽略;
同名函数
- 使用覆盖原则, 先声明的被忽略;
同名的函数和变量
- 使用忽略原则;
- 函数提升会提升到变量之前, 变量会被忽略;
- js function 和 var 分为声明和赋值两个操作;
var a = undefined;
function a() {
console.log(1);
}
a();
// 解析
function a() {
console.log(1);
}
var a;
a = undefined;
a(); // 此时a已经是个变量undefined, 报错;