1. Feature Overview
2 main features:
4 small features:
2. Async functions
A milestone feature, marking JS asynchronous programming experience rising to a new height, specifically see [From Generator to Async function](/articles/从 generator 到 async-function/)
3. Shared memory and atomics
Considered as infrastructure construction in multi-thread parallel capability aspects, divided into 2 parts:
-
SharedArrayBufferallows main thread, and [WebWorkers](/articles/理解 web-workers/) to share data between them -
Atomic operationsused to solve data synchronization problems, such as locking, transactions
For example:
// 主线程
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
}
Before
线程之间传递的是值 copy,而不是共享引用
Now can share same data through SharedArrayBuffer, and can also create shared data in worker thread:
Memory can be created in any agent and then shared with any other agent, and can be shared among many agents simultaneously.
Additionally, SharedArrayBuffer can be used as ArrayBuffer, so can also share 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);
Since data is multi-thread shared, inevitably face data synchronization problem, solved through some methods provided by Atomics global object:
// 读
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)
These atomic operations won't be interrupted (not interruptible), on this basis can implement:
-
Guarantee order of continuous read-write operations
-
Avoid write operations "lost" (such as writing to dirty data)
Additionally, allows suspend/wake (more friendly thread waiting method, doesn't occupy more resources):
Atomics.wait(typedArray, index, value[, timeout])
Atomics.wake(typedArray, index, count)
For example:
// 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
Instead of needing to rely on dead loop to implement blocking wait:
while (Atomics.load(ia, 37) == 163);
console.log(ia[37]); // Prints 123456
P.S. Interesting point, main thread not allowed to suspend:
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. For more information about Shared memory and atomics feature, please check:
4. Small Features
Object.values/Object.entries
// 返回 (1) 自身的 (2) 可枚举的 (3) 非 Symbol 类型的 属性的值
Object.values(obj)
polyfill 实现 roughly as follows:
function values(obj) {
var vals = [];
for (var key in obj) {
if (obj.hasOwnProperty(key) && obj.propertyIsEnumerable(key)) {
vals.push(obj[key]);
}
}
return vals;
}
Consistent with Object.keys(), all have 3 constraint conditions on properties (own && enumerable && non-Symbol-only). Therefore, not considering performance, can implement simpler polyfill:
function values(obj) {
return Object.keys(obj).map(key => obj[key]);
}
Similarly, also provides:
// 返回 (1) 自身的 (2) 可枚举的 (3) 非 Symbol 类型的 属性的键值对儿
Object.entries(obj)
polyfill also similar:
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;
};
Except return value form is different, with Object.values(obj) exactly the same
In application scenarios, Object.entries(obj) can be used to complete mapObject to [Map](/articles/集合(set 和 map)-es6 笔记 8/#articleHeader3) work:
new Map(Object.entries({
one: 1,
two: 2,
}))
// 输出 Map(2)?{"one" => 1, "two" => 2}
Enumerability, Prototype Properties and Symbol
-
Enumerability: Check through
obj.propertyIsEnumerable(key), below useenumerableto represent enumerable -
Whether prototype property: Check through
obj.hasOwnProperty(key), below useownto represent only targeting non-prototype properties -
Whether Symbol: Check through
typeof key === 'symbol', below usenon-Symbol-onlyto represent only targeting non-[Symbol](/articles/symbol-es6 笔记 7/) type properties, useSymbol-onlyto represent only targeting Symbol type properties
JS provides many utility methods around these 3 characteristics of object properties, besides above mentioned Object.keys(), Object.values(), Object.entries(), also have:
-
Object.getOwnPropertyNames(obj):
own && non-Symbol-only -
Object.getOwnPropertySymbols():
own && Symbol-only -
Reflect.ownKeys(obj):
own. Equivalent toObject.getOwnPropertyNames(target).concat(Object.getOwnPropertySymbols(target))
And 1 traversal method:
- for...in:
enumerable && non-Symbol-only
P.S. Reminded of for...of? This thing has little relationship with objects, only targets iterable, such as array-like objects (arguments, DOMNodeList etc.)
Object.getOwnPropertyDescriptors
// 以对象字典形式返回 (1) 自身的 所有属性的描述符
Object.getOwnPropertyDescriptors(obj)
Including Symbol type properties and non-enumerable properties, for example:
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
Can implement polyfill through Reflect.ownKeys(obj):
function getOwnPropertyDescriptors(obj) {
const result = {};
for (let key of Reflect.ownKeys(obj)) {
result[key] = Object.getOwnPropertyDescriptor(obj, key);
}
return result;
}
In application scenarios, mainly used to complete fine-grained object copy work:
// 连带属性描述符原样搬过去
function clone(obj) {
return Object.create(Object.getPrototypeOf(obj), Object.getOwnPropertyDescriptors(obj));
}
// 会丢失不可枚举属性以及原描述符
function copy(obj) {
return Object.assign({}, obj);
}
Difference as follows:
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
The left-pad module that once caused npm storm, won't be needed in future:
str.padStart(targetLength [, padString])
str.padEnd(targetLength [, padString])
Has some small details, for example:
// 默认补空格(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 small changes to basic syntax:
function foo(
param1,
param2, // 形参列表允许有多余逗号
) {
foo(
'abc',
'def', // 实参列表允许有多余逗号
);
}
Actually, similar changes also happened in ES5.1:
const object = {
foo: "bar",
baz: "qwerty",
age: 42, // 对象字面量键值对儿列表允许有多余逗号
};
Besides above 3 kinds, also language's initial syntax rules:
const arr = [
1,
2,
3, // 数组字面量允许有多余逗号
];
arr; // [1, 2, 3]
arr.length; // 3
Special:
const arr = [1, 2, 3,,,];
arr.length; // 5
In literal form sparse arrays, last comma belongs to trailing commas (ending extra commas) being ignored, therefore array size is 5
P.S. For more information about trailing commas, see Trailing commas
5. Summary
Async functions finally joined the luxury lunch in ES2017, infrastructure construction in multi-threading aspects is also gradually improving
Additionally, there are three unimportant Object methods, one string padding method, parameter list endings allow extra commas. For these icing-on-the-cake things, saw a proper attitude:
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.
No comments yet. Be the first to share your thoughts.