recursal/MDN huggingface dataset:
减法（-）
=====

**减法**（**`-`**）运算符将两个操作数相减，并产生两者之差。

尝试一下
----

语法
--


```js
x - y
```

描述
--

减法运算符将两个操作数转换为数值，并根据两个操作数的类型执行数字减法或 BigInt 减法。如果类型不匹配，则抛出 `TypeError`。

示例
--

### 数值减法


```js
// Number - Number -> subtraction
5 - 3; // 2

// Number - Number -> subtraction
3 - 5; // -2
```

### 非数值减法


```js
// String - Number -> subtraction
"foo" - 3; // NaN; "foo" is converted to the number NaN

// Number - String -> subtraction
5 - "3"; // 2; "3" is converted to the number 3
```

### BigInt 减法


```js
// BigInt - BigInt -> subtraction
2n - 1n; // 1n
```


你不能在减法中混合使用 BigInt 和数字操作数。


```js
2n - 1; // TypeError: Cannot mix BigInt and other types, use explicit conversions
2 - 1n; // TypeError: Cannot mix BigInt and other types, use explicit conversions
```

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-subtraction-operator-minus |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

参见
--

* 加法运算符
* 除法运算符
* 乘法运算符
* 取余运算符
* 幂运算符
* 自增运算符
* 自减运算符
* 一元减运算符
* 一元加运算符
in
==

如果指定的属性在指定的对象或其原型链中，则 **`in`** **运算符**返回 `true`。

尝试一下
----

语法
--
```

prop in object
```

### 参数

`prop`

一个字符串类型或者 symbol 类型的属性名或者数组索引（非 symbol 类型将会强制转为字符串）。

`objectName`

检查它（或其原型链）是否包含具有指定名称的属性的对象。

描述
--

下面的例子演示了一些 `in` 运算符的用法。


```js
// 数组
var trees = new Array("redwood", "bay", "cedar", "oak", "maple");
0 in trees; // 返回 true
3 in trees; // 返回 true
6 in trees; // 返回 false
"bay" in trees; // 返回 false (必须使用索引号，而不是数组元素的值)

"length" in trees; // 返回 true (length 是一个数组属性)

Symbol.iterator in trees; // 返回 true (数组可迭代，只在 ES2015+ 上有效)

// 内置对象
"PI" in Math; // 返回 true

// 自定义对象
var mycar = { make: "Honda", model: "Accord", year: 1998 };
"make" in mycar; // 返回 true
"model" in mycar; // 返回 true
```


`in`右操作数必须是一个对象值。例如，你可以指定使用`String`构造函数创建的字符串，但不能指定字符串文字。


```js
var color1 = new String("green");
"length" in color1; // 返回 true
var color2 = "coral";
"length" in color2; // 报错 (color2 不是对象)
```

### 对被删除或值为 undefined 的属性使用`in`

如果你使用 `delete` 运算符删除了一个属性，则 `in` 运算符对所删除属性返回 `false`。


```js
var mycar = { make: "Honda", model: "Accord", year: 1998 };
delete mycar.make;
"make" in mycar; // 返回 false

var trees = new Array("redwood", "bay", "cedar", "oak", "maple");
delete trees[3];
3 in trees; // 返回 false
```


如果你只是将一个属性的值赋值为`undefined`，而没有删除它，则 `in` 运算仍然会返回`true`。


```js
var mycar = { make: "Honda", model: "Accord", year: 1998 };
mycar.make = undefined;
"make" in mycar; // 返回 true
```



```js
var trees = new Array("redwood", "bay", "cedar", "oak", "maple");
trees[3] = undefined;
3 in trees; // 返回 true
```

### 继承属性

如果一个属性是从原型链上继承来的，`in` 运算符也会返回 `true`。


```js
"toString" in {}; // 返回 true
```

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-relational-operators |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

参见
--

* `for...in`
* `delete`
* `Object.hasOwn()`
* `Reflect.has()`
* 属性的可枚举性和所有权
逻辑空赋值（??=）
==========

逻辑空赋值运算符（`x ??= y`）仅在 `x` 是空值（`null` 或 `undefined`）时对其赋值。

尝试一下
----

语法
--


```js
expr1 ??= expr2
```

描述
--

### 短路评估

空值合并运算符从左至右求值，其使用以下规则测试是否可能进行语法短路求值：

`(结果非 null 或 undefined 的表达式) ?? expr` 被短路求值为左侧表达式，当左侧证明为既非 `null` 也非 `undefined`.

语法短路意味着 `expr` 部分**尚未被求值**，因此任何与其求值产生的相关副作用都不会生效（例如，如果 `expr` 是一个函数调用，则该调用将不会发生）。

逻辑空赋值的语法短路也意味着 `x ??= y` 等价于：


```js
x ?? (x = y);
```


而不等价于如下的表达式，因为其一定会发生赋值：


```js
x = x ?? y;
```

示例
--

### 使用逻辑空赋值


```js
function config(options) {
  options.duration ??= 100;
  options.speed ??= 25;
  return options;
}

config({ duration: 125 }); // { duration: 125, speed: 25 }
config({}); // { duration: 100, speed: 25 }
```

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-assignment-operators |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

参见
--

* 空值合并运算符（`??`）
* 空值
* 真值
* 假值
逻辑或（||）
=======

对于一组操作数的**逻辑或**（`||`，逻辑析取）运算符，当且仅当其一个或多个操作数为真，其运算结果为真。它通常与布尔（逻辑）值一起使用。当它是布尔值时，返回一个布尔值。然而，`||` 运算符实际上是返回一个指定的操作数的值，所以如果这个运算符被用于非布尔值，它将返回一个非布尔值。

尝试一下
----

语法
--


```js
expr1 || expr2
```

描述
--

如果 `expr1` 能转化为 `true`，返回 `expr1`；否则返回 `expr2`。

能够转化为 `true` 的值叫做真值，能够转化为 `false` 的值叫做假值。

能够转化为 false 的表达式的示例如下：

* `null`；
* `NaN`；
* `0`；
* 空字符串（`""` 或 `''` 或 ````）；
* `undefined`。

尽管 `||` 运算符可以与非布尔操作数一起使用，但它仍然被认为是一个布尔运算符，因为它的返回值总是可以被转换为布尔基本类型。要明确地将其返回值（或任何一般的表达式）转换为相应的布尔值，请使用双非运算符或 `Boolean` 构造函数。

### 短路求值

逻辑或从左到右进行求值，它使用如下规则进行“短路”测试：

`(some truthy expression) || expr` 被短路评估为真值。

短路意味着上面的 `expr` 部分**不被求值**，因此不会发生任何副作用（例如，如果 `expr` 是一个函数调用，调用就不会发生）。这是因为在对第一个操作数进行评估后，操作数的值已经确定。参见下述示例：


```js
function A() {
  console.log("调用了 A");
  return false;
}
function B() {
  console.log("调用了 B");
  return true;
}

console.log(B() || A());
// 由于调用了 B 函数，故会输出 "called B" 到控制台，
// 然后输出 true（运算符的运算结果）
```

### 运算符优先级

以下表达式看起来等价，但实际上不是，因为 `&&` 运算符比 `||` 运算符先执行（参见运算符优先级）。


```js
true || false && false; // 返回 true，因为 && 先执行
(true || false) && false; // 返回 false，因为分组运算符优先级更高
```

示例
--

### 使用或运算符

下列代码展示了 `||`（逻辑或）运算符的用法。


```js
true || true; // t || t returns true
false || true; // f || t returns true
true || false; // t || f returns true
false || 3 === 4; // f || f returns false
"Cat" || "Dog"; // t || t returns "Cat"
false || "Cat"; // f || t returns "Cat"
"Cat" || false; // t || f returns "Cat"
"" || false; // f || f returns false
false || ""; // f || f returns ""
false || varObject; // f || object returns varObject
```


**备注：** 如果你使用这个操作符为某些变量提供默认值，要注意任何*假*值都不会被使用。如果你只需要过滤掉 `null` 或 `undefined`，可以考虑使用空值合并运算符。

### 布尔值转化规则

#### 与运算符转化为或运算符

下述涉及到**布尔**运算符的运算：


```js
bCondition1 && bCondition2
```


总是与此表达式相同：


```js
!(!bCondition1 || !bCondition2)
```


#### 或运算符转化为与运算符

下述涉及到**布尔**运算符的运算：


```js
bCondition1 || bCondition2
```


总是与此表达式相同：


```js
!(!bCondition1 && !bCondition2)
```

### 去除嵌套的括号

由于逻辑表达式是从左到右进行求值的，只要遵循一定的规则，总是可以从一个复杂的表达式中删除括号。

下述涉及到**布尔**运算符的复杂运算：


```js
bCondition1 && (bCondition2 || bCondition3)
```


总是与此表达式相同：


```js
!(!bCondition1 || !bCondition2 && !bCondition3)
```

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # prod-LogicalORExpression |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

参见
--

* 空值合并运算符（`??`）
* `Boolean`
* 真值
* 假值
按位或赋值（|=）
=========

**按位或赋值**（**`|=`**) 运算符使用两个操作数的二进制表示，对它们执行按位或运算并将结果分配给变量。

尝试一下
----

语法
--


```js
x |= y // x = x | y
```

示例
--

### 使用按位或赋值


```js
let a = 5;
a |= 2; // 7
// 5: 00000000000000000000000000000101
// 2: 00000000000000000000000000000010
// -----------------------------------
// 7: 00000000000000000000000000000111
```

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-assignment-operators |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

参见
--

* JS 指南中的赋值运算符
* 按位或运算符
* 逻辑或赋值（`||=`）
大于（>）
=====

大于运算符（`>`）在左操作数大于右操作数时返回 `true`，否则返回 `false`。

尝试一下
----

语法
--


```js
x > y
```

描述
--

操作数比较使用与小于运算符相同的算法，只是两个操作数交换了。

示例
--

### 字符串与字符串比较


```js
console.log("a" > "b"); // false
console.log("a" > "a"); // false
console.log("a" > "3"); // true
```

### 字符串与数值比较


```js
console.log("5" > 3); // true
console.log("3" > 3); // false
console.log("3" > 5); // false

console.log("hello" > 5); // false
console.log(5 > "hello"); // false

console.log("5" > 3n); // true
console.log("3" > 5n); // false
```

### 数值与数值比较


```js
console.log(5 > 3); // true
console.log(3 > 3); // false
console.log(3 > 5); // false
```

### 数值与大整型比较


```js
console.log(5n > 3); // true
console.log(3 > 5n); // false
```

### 比较 Boolean、null、undefined 和 NaN


```js
console.log(true > false); // true
console.log(false > true); // false

console.log(true > 0); // true
console.log(true > 1); // false

console.log(null > 0); // false
console.log(1 > null); // true

console.log(undefined > 3); // false
console.log(3 > undefined); // false

console.log(3 > NaN); // false
console.log(NaN > 3); // false
```

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-relational-operators |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

参见
--

* 大于等于运算符
* 小于运算符
* 小于等于运算符
减法赋值（-=）
========

**减法赋值**（**`-=`**）运算符从变量中减去右操作数的值，并将结果赋值给该变量。

尝试一下
----

语法
--


```js
x -= y // x = x - y
```

示例
--

### 使用减法赋值


```js
let bar = 5;

bar -= 2; // 3
bar -= "foo"; // NaN
```

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-assignment-operators |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

参见
--

* JS 指南中的赋值运算符
* 减法运算符
按位与（&）
======

**按位与**（**`&`**）运算符在两个操作数对应的二进位都为 `1` 时，该位的结果值才为 `1`。

尝试一下
----

语法
--


```js
a & b
```

描述
--

操作数被转换为 32 位整数，并由一系列位（0 和 1）表示。超过 32 位的数字将丢弃其最高有效位。例如，以下大于 32 位的整数将被转换为 32 位整数：
```

Before: 11100110111110100000000000000110000000000001
After:              10100000000000000110000000000001
```


第一个操作数中的每个位都与第二个操作数中的相应位配对：*第一位*到*第一位*，*第二位*到*第二位*，依此类推。

将运算符应用于每对位，然后按位构造结果。

与运算的真值表：

| a | b | a AND b |
| --- | --- | --- |
| 0 | 0 | 0 |
| 0 | 1 | 0 |
| 1 | 0 | 0 |
| 1 | 1 | 1 |
```

     9 (base 10) = 00000000000000000000000000001001 (base 2)
    14 (base 10) = 00000000000000000000000000001110 (base 2)
                   --------------------------------
14 & 9 (base 10) = 00000000000000000000000000001000 (base 2) = 8 (base 10)
```


任何数字 `x` 与 `0` 进行按位与运算都会得到 `0`。

示例
--

### 使用按位与


```js
// 5: 00000000000000000000000000000101
// 2: 00000000000000000000000000000010
5 & 2; // 0
```

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # prod-BitwiseANDExpression |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

参见
--

* JS 指南中的位运算符
* 按位与赋值运算符
严格相等（===）
=========

严格相等运算符（`===`）会检查它的两个操作数是否相等，并且返回一个布尔值结果。与相等运算符不同，严格相等运算符总是认为不同类型的操作数是不同的。

尝试一下
----

语法
--


```js
x === y
```

描述
--

严格相等运算符（`===` 和 `!==`）提供了严格相等判定语义。

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

严格相等运算符与相等（`==`）运算符最显著的区别是，如果操作数的类型不同，`==` 运算符会在比较之前尝试将它们转换为相同的类型。

示例
--

### 比较相同类型的操作数


```js
"hello" === "hello"; // true
"hello" === "hola"; // false

3 === 3; // true
3 === 4; // false

true === true; // true
true === false; // false

null === null; // true
```

### 比较不同类型的操作数


```js
"3" === 3; // false
true === 1; // false
null === undefined; // false
```

### 比较对象


```js
const object1 = {
  key: "value",
};

const object2 = {
  key: "value",
};

console.log(object1 === object2); // false
console.log(object1 === object1); // true
```

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-equality-operators |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

参见
--

* 相等运算符
* 不相等运算符
* 严格不相等运算符
async function\* 表达式
====================

**`async function*`** 关键字可用于在表达式中定义一个异步生成器函数。

你也可以使用 `async function*` 声明定义一个异步生成器函数。

尝试一下
----

语法
--


```js
async function\* (param0) {
  statements
}
async function\* (param0, param1) {
  statements
}
async function\* (param0, param1, /\* … ,\*/ paramN) {
  statements
}

async function\* name(param0) {
  statements
}
async function\* name(param0, param1) {
  statements
}
async function\* name(param0, param1, /\* … ,\*/ paramN) {
  statements
}
```


**备注：** 为了避免 `async function*` 声明所带来的歧义，表达式语句不能以关键字 `async function` 开头。`async function` 关键字仅在上下文中无法接受语句时，才会被视为表达式的开头。

### 参数

`name` 可选

函数名。在这种情况下，函数名是*匿名的*，可以被省略。该名称仅在函数主体的内部有效。

`paramN` 可选

传递给函数的参数名称。

`statements` 可选

构成函数主体的语句。

描述
--

`async function*` 表达式与 `async function*` 声明非常相似，语法几乎相同。*函数名*是 `async function*` 表达式和 `async function*` 声明之间最主要的区别，在 `async function*` 表达式中，可以创建*匿名*函数去忽略函数名。`async function*` 表达式可以用作立即调用函数表达式（IIFE），该表达式在被定义后立即运行，允许你去创建一个临时的异步的可迭代对象。有关更多信息，请参见函数这个章节。

示例
--

### 使用 async function\*

以下示例定义了一个没有名称的异步生成器函数并将它分配给变量 `x`。这个函数产生它参数的平方。


```js
const x = async function\* (y) {
  yield Promise.resolve(y \* y);
};
x(6)
  .next()
  .then((res) => console.log(res.value)); // 36
```

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-async-generator-function-definitions |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

参见
--

* `async function*` 语句
* `AsyncGeneratorFunction` 对象
* 迭代协议
* `GeneratorFunction` 对象
* `yield`
* `yield*`
* `Function` 对象
* 函数
空值合并运算符（??）
===========

**空值合并运算符**（**`??`**）是一个逻辑运算符，当左侧的操作数为 `null` 或者 `undefined` 时，返回其右侧操作数，否则返回左侧操作数。

与逻辑或运算符（`||`）不同，逻辑或运算符会在左侧操作数为假值时返回右侧操作数。也就是说，如果使用 `||` 来为某些变量设置默认值，可能会遇到意料之外的行为。比如为假值（例如，`''` 或 `0`）时。见下面的例子。

尝试一下
----

语法
--


```js
leftExpr ?? rightExpr
```

示例
--

### 使用空值合并运算符

在这个例子中，我们使用空值合并运算符为常量提供默认值，保证常量不为 `null` 或者 `undefined`。


```js
const nullValue = null;
const emptyText = ""; // 空字符串，是一个假值，Boolean("") === false
const someNumber = 42;

const valA = nullValue ?? "valA 的默认值";
const valB = emptyText ?? "valB 的默认值";
const valC = someNumber ?? 0;

console.log(valA); // "valA 的默认值"
console.log(valB); // ""（空字符串虽然是假值，但不是 null 或者 undefined）
console.log(valC); // 42
```

### 为变量赋默认值

以前，如果想为一个变量赋默认值，通常的做法是使用逻辑或运算符（`||`）：


```js
let foo;

// foo is never assigned any value so it is still undefined
let someDummyText = foo || "Hello!";
```


然而，由于 `||` 是一个布尔逻辑运算符，左侧的操作数会被强制转换成布尔值用于求值。任何假值（`0`， `''`， `NaN`， `null`， `undefined`）都不会被返回。这导致如果你使用`0`，`''`或`NaN`作为有效值，就会出现不可预料的后果。


```js
let count = 0;
let text = "";

let qty = count || 42;
let message = text || "hi!";
console.log(qty); // 42，而不是 0
console.log(message); // "hi!"，而不是 ""
```


空值合并运算符可以避免这种陷阱，其只在第一个操作数为`null` 或 `undefined` 时（而不是其他假值）返回第二个操作数：


```js
let myText = ""; // An empty string (which is also a falsy value)

let notFalsyText = myText || "Hello world";
console.log(notFalsyText); // Hello world

let preservingFalsy = myText ?? "Hi neighborhood";
console.log(preservingFalsy); // '' (as myText is neither undefined nor null)
```

### 短路

与 OR 和 AND 逻辑运算符相似，当左表达式不为 `null` 或 `undefined` 时，不会对右表达式进行求值。


```js
function A() {
  console.log("函数 A 被调用了");
  return undefined;
}
function B() {
  console.log("函数 B 被调用了");
  return false;
}
function C() {
  console.log("函数 C 被调用了");
  return "foo";
}

console.log(A() ?? C());
// 依次打印 "函数 A 被调用了"、"函数 C 被调用了"、"foo"
// A() 返回了 undefined，所以运算符两边的表达式都被执行了

console.log(B() ?? C());
// 依次打印 "函数 B 被调用了"、"false"
// B() 返回了 false（既不是 null 也不是 undefined）
// 所以右侧表达式没有被执行
```

### 不能与 AND 或 OR 运算符共用

将 `??` 直接与 AND（`&&`）和 OR（`||`）运算符组合使用是不可取的。（译者注：应当是因为空值合并运算符和其他逻辑运算符之间的运算优先级/运算顺序是未定义的）这种情况下会抛出 `SyntaxError` 。


```js
null || undefined ?? "foo"; // 抛出 SyntaxError
true || undefined ?? "foo"; // 抛出 SyntaxError
```


但是，如果使用括号来显式表明运算优先级，是没有问题的：


```js
(null || undefined) ?? "foo"; // 返回 "foo"
```

### 与可选链式运算符（`?.`）的关系

空值合并运算符针对 `undefined` 与 `null` 这两个值，可选链式运算符（`?.`） 也是如此。在这访问属性可能为 `undefined` 与 `null` 的对象时，可选链式运算符非常有用。


```js
let foo = { someFooProp: "hi" };

console.log(foo.someFooProp?.toUpperCase()); // "HI"
console.log(foo.someBarProp?.toUpperCase()); // undefined
```

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # prod-CoalesceExpression |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

参见
--

* 逻辑空赋值运算符（`??=`）
* 可选链运算符（`?.`）
* 逻辑或运算符（`||`）
* 函数中的默认参数值
右移赋值（>>=）
=========

右移赋值运算符（`>>=`）将变量向右移动指定的位数，并将结果赋值给变量。

尝试一下
----

语法
--


```js
x >>= y // x = x >> y
```

示例
--

### 使用右移赋值


```js
let a = 5; // (00000000000000000000000000000101)
a >>= 2; // 1 (00000000000000000000000000000001)

let b = -5; // (-00000000000000000000000000000101)
b >>= 2; // -2 (-00000000000000000000000000000010)
```

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-assignment-operators |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

参考
--

* JS 指南中的赋值运算符
* 右移运算符
import.meta
===========

`import.meta`是一个给 JavaScript 模块暴露特定上下文的元数据属性的对象。它包含了这个模块的信息，比如说这个模块的 URL。

语法
--
```

import.meta
```

描述
--

`import.meta`对象由一个关键字`"import"`,一个点符号和一个`meta`属性名组成。通常情况下`"import."`是作为一个属性访问的上下文，但是在这里`"import"`不是一个真正的对象。

`import.meta`对象是由 ECMAScript 实现的，它带有一个`null`的原型对象。这个对象可以扩展，并且它的属性都是可写，可配置和可枚举的。

示例
--

这里有一个 `my-module.mjs 模块`


```html
<script type="module" src="my-module.mjs"></script>
```


你可以通过 `import.meta` 对象获取这个模块的元数据信息。


```js
console.log(import.meta); // { url: "file:///home/user/my-module.mjs" }
```


它返回一个带有`url`属性的对象，指明模块的基本 URL。也可以是外部脚本的 URL，还可以是内联脚本所属文档的 URL。

注意，url 也可能包含参数或者哈希（比如后缀`?`或`#`）

以下面的 HTML 为例：
```

<script type="module">
import './index.mjs?someURLInfo=5';
</script>
```


...下面的 JavaScript 会打印`someURLInfo`这个参数：
```

// index.mjs
new URL(import.meta.url).searchParams.get('someURLInfo'); // 5
```


在脚本中引入别的脚本同样生效：
```

// index.mjs
import './index2.mjs?someURLInfo=5';

// index2.mjs
new URL(import.meta.url).searchParams.get('someURLInfo'); // 5
```


虽然在上述例子中，Node.js 允许携带参数（或哈希），但以 Node 14.1.0 为例，使用`node --experimental-modules index.mjs?someURLInfo=5` 执行脚本，查询 URL 参数将会报错（该环境下`index.mjs?someURLInfo=5` 被视作一个文件而不是 URL）

像这种特定于文件的参数传递可能是对应用范围内`location.href`（ps: 通过在 HTML 路径添加参数或哈希）（而在 Node.js 中是`process.env`）的补充

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # prod-ImportMeta |
| HTML Standard # hostgetimportmetaproperties |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

参见
--

* import
* `export`
左移赋值（<<=）
=========

左移赋值运算符（`<<=`）将变量向左移动指定的位数，并将结果赋值给变量。

尝试一下
----

语法
--


```js
x <<= y // x = x << y
```

示例
--

### 使用左移赋值


```js
let a = 5;
// 00000000000000000000000000000101

a <<= 2; // 20
// 00000000000000000000000000010100
```

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-assignment-operators |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

参考
--

* JS 指南中的赋值运算符
* 左移运算符
幂赋值（\*\*=）
==========

**幂赋值**（**`**=`**）对两个操作数执行幂运算，并将结果赋给左操作数。

尝试一下
----

语法
--


```js
x \*\*= y // x = x \*\* y
```

示例
--

### 使用幂赋值


```js
let bar = 5;

bar \*\*= 2; // 25
bar \*\*= "foo"; // NaN
```

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-assignment-operators |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

参见
--

* JS 指南中的赋值运算符
* 幂运算符
赋值（=）
=====

简单赋值运算符（`=`）用于给变量赋值。赋值表达式本身的值为要赋值的值。为了将一个值赋给多个变量，可以链式使用赋值运算符。

尝试一下
----

语法
--


```js
x = y
```

示例
--

### 简单赋值和链式赋值


```js
// 假设已经存在以下变量
// x = 5
// y = 10
// z = 25

x = y; // x 为 10
x = y = z; // x, y 都为 25
```

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-assignment-operators |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

参见
--

* JS 指南中的赋值运算符
yield
=====

`yield` 关键字用于暂停和恢复生成器函数。

尝试一下
----

语法
--
```

[rv] = yield [expression];
```


`expression`

定义通过迭代器协议从生成器函数返回的值。如果省略，则返回 `undefined`。

`rv`

返回传递给生成器的 `next()` 方法的可选值，以恢复其执行。

描述
--

`yield` 关键字使生成器函数执行暂停，`yield` 关键字后面的表达式的值返回给生成器的调用者。它可以被认为是一个基于生成器的版本的 `return` 关键字。

`yield` 关键字实际返回一个 `IteratorResult` 对象，它有两个属性，`value` 和 `done`。`value` 属性是对 `yield` 表达式求值的结果，而 `done` 是 `false`，表示生成器函数尚未完全完成。

一旦遇到 `yield` 表达式，生成器的代码将被暂停运行，直到生成器的 `next()` 方法被调用。每次调用生成器的 `next()` 方法时，生成器都会恢复执行，直到达到以下某个值：

* `yield`，导致生成器再次暂停并返回生成器的新值。下一次调用 `next()` 时，在 `yield` 之后紧接着的语句继续执行。
* `throw` 用于从生成器中抛出异常。这让生成器完全停止执行，并在调用者中继续执行，正如通常情况下抛出异常一样。
* 到达生成器函数的结尾。在这种情况下，生成器的执行结束，并且 `IteratorResult` 给调用者返回 `value` 的值是 `undefined` 并且 `done` 为 `true`。
* 到达 `return` 语句。在这种情况下，生成器的执行结束，并将 `IteratorResult` 返回给调用者，其 `value` 的值是由 `return` 语句指定的，并且 `done` 为 `true`。

如果将参数传递给生成器的 `next()` 方法，则该值将成为生成器当前 `yield` 操作返回的值。

在生成器的代码路径中的 `yield` 运算符，以及通过将其传递给 `Generator.prototype.next()` 指定新的起始值的能力之间，生成器提供了强大的控制力。

**警告：** 不幸地是，`next()` 是不对称的，但这并不是没有帮助：它总是向当前暂停的 `yield` 发送一个值，但是返回的是 `yield` 之后表达式的运算结果。

示例
--

### 使用 yield

以下代码是一个生成器函数的声明。


```js
function\* countAppleSales() {
  const saleList = [3, 7, 5];
  for (let i = 0; i < saleList.length; i++) {
    yield saleList[i];
  }
}
```


一旦生成器函数已定义，可以通过构造一个迭代器来使用它。


```js
const appleStore = countAppleSales(); // Generator { }
console.log(appleStore.next()); // { value: 3, done: false }
console.log(appleStore.next()); // { value: 7, done: false }
console.log(appleStore.next()); // { value: 5, done: false }
console.log(appleStore.next()); // { value: undefined, done: true }
```


你也可以将带有 `next(value)` 的值发送给生成器。在 `rv = yield expression` 这个语法中，`step` 用于接收返回值——尽管第一次调用 `next()` 时忽略传递给生成器 `next()` 方法的值。


```js
function\* counter(value) {
  let step;

  while (true) {
    step = yield value++;
    if (step) {
      value += step;
    }
  }
}

const generatorFunc = counter(0);
console.log(generatorFunc.next().value); // 0
console.log(generatorFunc.next().value); // 1
console.log(generatorFunc.next().value); // 2
console.log(generatorFunc.next().value); // 3
console.log(generatorFunc.next(10).value); // 14
console.log(generatorFunc.next().value); // 15
console.log(generatorFunc.next(10).value); // 26
```

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # prod-YieldExpression |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

参见
--

* 迭代协议
* `function*`
* `function*` 表达式
* `yield*`
new.target
==========

 **`new.target`** 属性允许你检测函数或构造方法是否是通过new运算符被调用的。在通过new运算符被初始化的函数或构造方法中，`new.target`返回一个指向构造方法或函数的引用。在普通的函数调用中，`new.target` 的值是`undefined`。语法
--
```

new.target
```

描述
--

`new.target`语法由一个关键字"`new`"，一个点，和一个属性名"`target`"组成。通常"`new.`"`的`作用是提供属性访问的上下文，但这里"`new.`"其实不是一个真正的对象。不过在构造方法调用中，`new.target`指向被`new`调用的构造函数，所以"`new.`"成为了一个虚拟上下文。

`new.target`属性适用于所有函数访问的元属性。在 arrow functions 中，`new.target` 指向最近的外层函数的`new.target`（An arrow function expression does not have its own this, arguments, super , or new.target) 。

示例
--

### 函数调用中的 new.target

在普通的函数调用中（和作为构造函数来调用相对），`new.target`的值是`undefined`。这使得你可以检测一个函数是否是作为构造函数通过new被调用的。


```js
function Foo() {
  if (!new.target) throw "Foo() must be called with new";
  console.log("Foo instantiated with new");
}

Foo(); // throws "Foo() must be called with new"
new Foo(); // logs "Foo instantiated with new"
```

### 构造方法中的 new.target

在类的构造方法中，`new.target`指向直接被`new`执行的构造函数。并且当一个父类构造方法在子类构造方法中被调用时，情况与之相同。


```js
class A {
  constructor() {
    console.log(new.target.name);
  }
}

class B extends A {
  constructor() {
    super();
  }
}

var a = new A(); // logs "A"
var b = new B(); // logs "B"

class C {
  constructor() {
    console.log(new.target);
  }
}
class D extends C {
  constructor() {
    super();
  }
}

var c = new C(); // logs class C{constructor(){console.log(new.target);}}
var d = new D(); // logs class D extends C{constructor(){super();}}
```


从上面类 C 和 D 的例子可以看出来，new.target 指向的是初始化类的类定义。比如当 D 通过 new 初始化的时候，打印出了 D 的类定义，C 的例子与之类似，打印出的是 C 的类定义。

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-built-in-function-objects |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

参见
--

* 函数
* 类
* `new`
* `this`