# 表达式与操作符

# 1、主表达式

包括常量或字面量值、某些语言关键字和变量引用

字面量是可以直接嵌入在程序中的常量值

1.23 // 数字字面量
"hello" // 字符串字面量
/pattern/ // 正则表达式字面量
1
2
3

程序中出现任何独立的标识符时,JavaScript 假设它是一个变量或常量或全局对象的属性,并查询它的值。如果不存在该名字的变量,则求值不存在的变量会导致抛出 ReferenceError。

# 2、条件式属性访问

ES2020 增加了两个新的属性访问表达式:

expression?.identifier;
expression?.[expression];
1
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 没有任何属性所以会报错
1
2
3
4
5

# 3、条件式调用

在 ES2020 中,可以使用?.()而非()来调用函数。

?.()只会检查左侧的值是不是 null 或 undefined,不会验证该值是不是函数。

log?.(x); // 若 log 值不是 null 或 undefined,则执行函数调用,若 log 不是函数则抛出错误。

o.m(); // 常规属性访问,常规调用
o?.m(); // 条件式属性访问,常规调用
o.m?.(); // 常规属性访问,条件式调用
1
2
3
4
5

# 4、对象创建表达式

new Object();
new Point(2, 3);

new Object(); // 可以省略圆括号
new Date();
1
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
1
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"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 8、条件操作符(?😃

条件操作符是 JavaScript 唯一一个三元操作符(有三个操作数),因此有时候也被叫作三元操作符。

x > 0 ? x : -x; // x 的绝对值
1

# 9、先定义操作符(??)

如果其左操作数不是 null 或 undefined,就返回该值。否则,它会返回右操作数的值。

??是短路的:它只在第一个操作数求值为 null 或 undefined 时才会求值第二个操作数。

?? 是对 || 的一个有用的替代,适合选择先定义的操作数,而不是第一个为真值的操作数。

// 如果 maxWidth 为 0 则会被忽略
let max = maxWidth || pre.maxWidth || 500;
// maxWidth 为 0 则不会被忽略
let max = maxWidth ?? pre.maxWidth ?? 500;
1
2
3
4

这个操作符正式的名字叫“缺值合并”(nullish coalescing)操作符,但我没有使用这个叫法。因为这个操作符会选择自己的一个操作数,但我并没有看到它会“合并”操作数。

# 10、typeof 操作符

typeof 是个一元操作符,放在自己的操作数前面,这个操作数可以是任意类型。

x typeof x
undefined "undefined"
null "object"
truefalse "boolean"
任意数值NaN "number"
任意字符串 "string"
任意符号 "symbol"
任意函数 "function"
任意非函数对象 "object"

# 11、void 操作符

void 是一元操作符,出现在它的操作数前面,这个操作数可以是任意类型。求值自己的操作数,然后丢弃这个值并返回 undefined。

let counter = 0;
const increment = () => void counter++;
increment(); // => undefined
counter; // => 1
1
2
3
4
上次更新: 2/21/2023, 9:39:49 PM