# 表达式与操作符
# 1、主表达式
包括常量或字面量值、某些语言关键字和变量引用
字面量是可以直接嵌入在程序中的常量值
1.23 // 数字字面量
"hello" // 字符串字面量
/pattern/ // 正则表达式字面量
2
3
程序中出现任何独立的标识符时,JavaScript 假设它是一个变量或常量或全局对象的属性,并查询它的值。如果不存在该名字的变量,则求值不存在的变量会导致抛出 ReferenceError。
# 2、条件式属性访问
ES2020 增加了两个新的属性访问表达式:
expression?.identifier;
expression?.[expression];
2
- expression 若为 null 或 undefined 则直接返回 undefined,不会对
.
号后面的条件进行判断 - expression 若不为 null 或 undefined 则根据
.
号后面条件进行判断 - 若 identifier 为 null 或 undefined 则 返回 undefined;若 identifier 后面还存在条件则返回抛出错误
const a = { b: null };
console.log(a.b?.c.d); // undefined
const a = { b: {} };
console.log(a.b?.c.d); // TypeError, 这是因为 .c为 undefined,null 和 undefined 没有任何属性所以会报错
2
3
4
5
# 3、条件式调用
在 ES2020 中,可以使用?.()而非()来调用函数。
?.()只会检查左侧的值是不是 null 或 undefined,不会验证该值是不是函数。
log?.(x); // 若 log 值不是 null 或 undefined,则执行函数调用,若 log 不是函数则抛出错误。
o.m(); // 常规属性访问,常规调用
o?.m(); // 条件式属性访问,常规调用
o.m?.(); // 常规属性访问,条件式调用
2
3
4
5
# 4、对象创建表达式
new Object();
new Point(2, 3);
new Object(); // 可以省略圆括号
new Date();
2
3
4
5
# 5、操作符副效应
对类似 2 * 3 这样的简单表达式求值不会影响程序状态,程序后续的任何计算也不会被这个求值所影响。
但有些表达式是有副效应的,即对它们求值可能影响将来求值的结果。比如赋值、delete 操作符
# 6、in 操作符
in 操作符期待左侧操作数是字符串、符号或可以转换为字符串的值,期待右侧操作数是对象。如果左侧的值是右侧的对象的属性名,则 in 返回 true。
let point = { x: 1, y: 1 }; // 定义对象
'x' in point; // true
'z' in point; // false
'toString' in point; // true
let data = [7, 8, 9];
'0' in data; // true
1 in data; // true
3 in data; // false
2
3
4
5
6
7
8
9
# 7、eval
eval()期待一个参数。如果给它传入任何非字符串值,它会简单地返回这个值。
- 如果传入字符串,它会尝试把这个字符串当成 JavaScript 代码来解析,解析失败会抛出 SyntaxError。
- 如果解析字符串成功,它会求值代码并返回该字符串中最后一个表达式或语句的值;
- 如果最后一个表达式或语句没有值则返回 undefined。
- 如果求值字符串抛出异常,该异常会从调用 eval()的地方传播出来。
对于 eval()(在像这样调用时),关键在于它会使用调用它的代码的变量环境。
- 在函数中调用 eval(),操作的是函数内的变量和函数
- 在全局中调用 eval(),操作的是全局变量和全局函数
const geval = eval; // 设置 eval 别名
let x = 'global',
y = 'global'; // 定义两个全局变量
function f() {
// f() 函数直接调用 eval
let x = 'local';
eval("x += 'changed';");
return x;
}
function g() {
// g() 函数间接调用 eval
let y = 'local';
geval("y += 'changed';");
return y;
}
console.log(f(), x); // 改变了局部变量: "localchanged global"
console.log(g(), y); // 改变了全局变量: "local globalchanged"
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 8、条件操作符(?😃
条件操作符是 JavaScript 唯一一个三元操作符(有三个操作数),因此有时候也被叫作三元操作符。
x > 0 ? x : -x; // x 的绝对值
# 9、先定义操作符(??)
如果其左操作数不是 null 或 undefined,就返回该值。否则,它会返回右操作数的值。
??是短路的:它只在第一个操作数求值为 null 或 undefined 时才会求值第二个操作数。
??
是对 ||
的一个有用的替代,适合选择先定义的操作数,而不是第一个为真值的操作数。
// 如果 maxWidth 为 0 则会被忽略
let max = maxWidth || pre.maxWidth || 500;
// maxWidth 为 0 则不会被忽略
let max = maxWidth ?? pre.maxWidth ?? 500;
2
3
4
这个操作符正式的名字叫“缺值合并”(nullish coalescing)操作符,但我没有使用这个叫法。因为这个操作符会选择自己的一个操作数,但我并没有看到它会“合并”操作数。
# 10、typeof 操作符
typeof 是个一元操作符,放在自己的操作数前面,这个操作数可以是任意类型。
x | typeof x |
---|---|
undefined | "undefined" |
null | "object" |
true 或 false | "boolean" |
任意数值 或 NaN | "number" |
任意字符串 | "string" |
任意符号 | "symbol" |
任意函数 | "function" |
任意非函数对象 | "object" |
# 11、void 操作符
void 是一元操作符,出现在它的操作数前面,这个操作数可以是任意类型。求值自己的操作数,然后丢弃这个值并返回 undefined。
let counter = 0;
const increment = () => void counter++;
increment(); // => undefined
counter; // => 1
2
3
4