一.特性概観
2 つの主要特性:
4 つの小特性:
二.Async functions
一つのマイルストーン的な特性で、JS 非同期プログラミング体験が新たな高みに上昇したことを示しています。詳細は [Generator から Async function へ](/articles/从 generator 到 async-function/) を参照
三.Shared memory and atomics
マルチスレッド並行能力方面の基礎建設と言えます。2 部分に分かれます:
-
SharedArrayBufferはメインスレッド、および [WebWorkers](/articles/理解 web-workers/) 間でデータを共有することを許可 -
Atomic operations(原子操作)はデータ同期の問題を解決するために使用され、例えばロック、トランザクションなど
例えば:
// 主线程
var w = new Worker("myworker.js");
var sab = new SharedArrayBuffer(1024); // 1KiB shared memory
// 同样通过 postMessage 给 worker 线程丢过去
w.postMessage(sab);
// worker 线程(myworker.js)
var sab;
onmessage = function (ev) {
sab = ev.data; // 1KiB shared memory, the same memory as in the parent
}
以前は
线程之间传递的是值 copy,而不是共享引用
現在では SharedArrayBuffer を通じて同一のデータを共有でき、worker スレッド内でも共有データを作成できます:
Memory can be created in any agent and then shared with any other agent, and can be shared among many agents simultaneously.
さらに、SharedArrayBuffer は ArrayBuffer として使用できるため、TypedArray も共有できます:
var sab = new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT * 100000); // 100000 primes
var ia = new Int32Array(sab); // ia.length == 100000
var primes = new PrimeGenerator();
for ( let i=0 ; i < ia.length ; i++ )
ia[i] = primes.next();
w.postMessage(ia);
データはマルチスレッドで共有されるため、必ずデータ同期の問題に直面します。Atomics グローバルオブジェクトが提供するいくつかのメソッドを通じて解決します:
// 读
Atomics.load(typedArray, index)
// 写
Atomics.store(typedArray, index, value)
// 写,返回旧值
Atomics.exchange(array, index, value)
// 条件写,仅当旧值等于 oldval 时才写,返回旧值
compareExchange(array, index, oldval, newval)
// 带读写锁的运算(加、减、与、或、异或)
Atomics.add(array, index, value)
Atomics.sub(array, index, value)
Atomics.and(array, index, value)
Atomics.or(array, index, value)
Atomics.xor(array, index, value)
これらの原子操作は中断されません(not interruptible)。これを基礎として実装できます:
-
連続した読み書き操作の順序を保証
-
書き込み操作の「丢失」を回避(例えば汚れたデータに書き込むなど)
さらに、サスペンド/ウェイクアップを許可します(より友好的なスレッド待機方式で、リソースを多く占有しません):
Atomics.wait(typedArray, index, value[, timeout])
Atomics.wake(typedArray, index, count)
例えば:
// A 线程写
console.log(ia[37]); // Prints 163
Atomics.store(ia, 37, 123456);
Atomics.wake(ia, 37, 1);
// B 线程等着读
Atomics.wait(ia, 37, 163);
console.log(ia[37]); // Prints 123456
デッドループに頼ってブロッキング待機を実現する必要はありません:
while (Atomics.load(ia, 37) == 163);
console.log(ia[37]); // Prints 123456
P.S. 面白い一点、メインスレッドはサスペンドを許可されません:
The specification allows the browser to deny wait on the main thread, and it is expected that most browsers will eventually do so. A denied wait throws an exception.
P.S. Shared memory and atomics 特性のより多くの情報については、以下を参照:
四.小特性
Object.values/Object.entries
// 返回 (1) 自身的 (2) 可枚举的 (3) 非 Symbol 类型的 属性的值
Object.values(obj)
polyfill 実装 は大致以下の通り:
function values(obj) {
var vals = [];
for (var key in obj) {
if (obj.hasOwnProperty(key) && obj.propertyIsEnumerable(key)) {
vals.push(obj[key]);
}
}
return vals;
}
Object.keys() と一致し、属性に対して 3 つの限定条件があります(own && enumerable && non-Symbol-only)。したがって、パフォーマンスを考慮しない場合、よりシンプルな polyfill を実装できます:
function values(obj) {
return Object.keys(obj).map(key => obj[key]);
}
同様に、以下も提供されます:
// 返回 (1) 自身的 (2) 可枚举的 (3) 非 Symbol 类型的 属性的键值对儿
Object.entries(obj)
polyfill も類似:
function entries(obj) {
var entrys = [];
for (var key in obj) {
if (obj.hasOwnProperty(obj, key) && obj.propertyIsEnumerable(obj, key)) {
entrys.push([key, obj[key]]);
}
}
return entrys;
};
戻り値の形式が異なる以外、Object.values(obj) と一毛一样です
適用シナリオでは、Object.entries(obj) は mapObject を [Map](/articles/集合(set 和 map)-es6 笔记 8/#articleHeader3) に変換する作業を完了するために使用できます:
new Map(Object.entries({
one: 1,
two: 2,
}))
// 输出 Map(2)?{"one" => 1, "two" => 2}
列挙性、プロトタイプ属性と Symbol
-
列挙性:
obj.propertyIsEnumerable(key)でチェック。以下enumerableで列挙可能を表す -
プロトタイプ属性かどうか:
obj.hasOwnProperty(key)でチェック。以下ownで非プロトタイプ属性のみを対象とする -
Symbol かどうか:
typeof key === 'symbol'でチェック。以下non-Symbol-onlyで非 [Symbol](/articles/symbol-es6 笔记 7/) タイプ属性のみを対象とし、Symbol-onlyで Symbol タイプ属性のみを対象とする
JS はオブジェクト属性のこれら 3 つの特徴を巡って多くのツールメソッドを提供しています。上記の Object.keys()、Object.values()、Object.entries() の他に、以下があります:
-
Object.getOwnPropertyNames(obj):
own && non-Symbol-only -
Object.getOwnPropertySymbols():
own && Symbol-only -
Reflect.ownKeys(obj):
own。Object.getOwnPropertyNames(target).concat(Object.getOwnPropertySymbols(target))と同等
および 1 種類の走査方式:
- for...in:
enumerable && non-Symbol-only
P.S. for...of を思い出しましたか?これはオブジェクトとはあまり関係なく、iterable のみを対象とします。例えば配列様オブジェクト(arguments、DOMNodeList など)
Object.getOwnPropertyDescriptors
// 以对象字典形式返回 (1) 自身的 所有属性的描述符
Object.getOwnPropertyDescriptors(obj)
Symbol タイプ属性と列挙不可属性を含みます。例えば:
const obj = {
[Symbol('foo')]: 123
};
Object.defineProperty(obj, 'bar', {
value: 42,
enumerable: false
});
console.log(Object.getOwnPropertyDescriptors(obj));
// 输出
// {
// bar: {value: 42, writable: false, enumerable: false, configurable: false},
// Symbol(foo): {value: 123, writable: true, enumerable: true, configurable: true}
// }
// 而 Object.keys(obj).length === 0
Reflect.ownKeys(obj) を通じて polyfill を実装できます:
function getOwnPropertyDescriptors(obj) {
const result = {};
for (let key of Reflect.ownKeys(obj)) {
result[key] = Object.getOwnPropertyDescriptor(obj, key);
}
return result;
}
適用シナリオでは、主に精細なオブジェクトコピー作業を完了するために使用されます:
// 连带属性描述符原样搬过去
function clone(obj) {
return Object.create(Object.getPrototypeOf(obj), Object.getOwnPropertyDescriptors(obj));
}
// 会丢失不可枚举属性以及原描述符
function copy(obj) {
return Object.assign({}, obj);
}
違いは以下の通り:
const obj = {};
Object.defineProperty(obj, 'bar', {
value: 42,
enumerable: false
});
Object.defineProperty(obj, 'foo', {
value: 24,
enumerable: true,
writable: false
});
Object.getOwnPropertyDescriptors(clone(obj));
// 属性保持原状
// bar: {value: 42, writable: false, enumerable: false, configurable: false}
// foo: {value: 24, writable: false, enumerable: true, configurable: false}
Object.getOwnPropertyDescriptors(copy(obj));
// 不可枚举的 bar 丢了,foo 的属性描述符被重置回默认了
// foo: {value: 24, writable: true, enumerable: true, configurable: true}
String padding
かつて npm 風波 を引き起こした left-pad モジュールは、今後不要になります:
str.padStart(targetLength [, padString])
str.padEnd(targetLength [, padString])
いくつかの細かい点があります。例えば:
// 默认补空格(U+0020)
'1'.padStart(4) === '1'.padStart(4, ' ')
// 也可以填充指定串
'1'.padEnd(4, 0) === '1000'
// 填充串的长度不限于一个字符,太长会被裁剪掉
'1'.padEnd(4, 'abcde') === '1abc'
// 不用补就不补
'1345'.padStart(2) === '1345'
Trailing commas in function parameter lists and calls
基本構文の 2 つの小変更:
function foo(
param1,
param2, // 形参列表允许有多余逗号
) {
foo(
'abc',
'def', // 实参列表允许有多余逗号
);
}
実際、類似の変更は ES5.1 でも発生しました:
const object = {
foo: "bar",
baz: "qwerty",
age: 42, // 对象字面量键值对儿列表允许有多余逗号
};
上記 3 種の他に、言語最初の文法規則があります:
const arr = [
1,
2,
3, // 数组字面量允许有多余逗号
];
arr; // [1, 2, 3]
arr.length; // 3
特殊的:
const arr = [1, 2, 3,,,];
arr.length; // 5
リテラル形式の疎配列中、最後のカンマはtrailing commas(末尾余分カンマ)として無視されるため、配列サイズは 5 です
P.S. trailing commas のより多くの情報については、Trailing commas を参照
五.まとめ
Async functions ついに ES2017 で豪華ランチに追加され、マルチスレッド方面の基礎建設も徐々に整備されています
さらに、3 つの重要でない Object メソッド、1 つの文字列 padding メソッド、パラメータリスト末尾に余分カンマを許可。これらの錦上添花のものに対して、端正な態度を見ました:
Are people seriously considering to extend the language for something that can be implemented in 7 lines of code ?
Convenience matters, as does eliminating redundant code. JavaScript's runtime library is still very spartan compared to other programming languages.
コメントはまだありません