摘要:例如通過哈希表映射需要一個(gè)操作來檢查值是否相等,另一個(gè)操作用于創(chuàng)建哈希碼。如果使用哈希碼,則對(duì)象應(yīng)該是不可變的。模式匹配提案目前處于第階段。在本文,我們研究其中的智能管道另一個(gè)提議被稱為。更強(qiáng)大,更重量級(jí),并附帶自己的數(shù)據(jù)結(jié)構(gòu)。
翻譯:瘋狂的技術(shù)宅
原文:http://2ality.com/2019/01/fut...
本文首發(fā)微信公眾號(hào):jingchengyideng
歡迎關(guān)注,每天都給你推送新鮮的前端技術(shù)文章
近年來,JavaScript 的功能得到了大幅度的增加,本文探討了其仍然缺失的東西。
說明:
我只列出了我所發(fā)現(xiàn)的最重要的功能缺失。當(dāng)然還有很多其它有用的功能,但同時(shí)也會(huì)增加太多的風(fēng)險(xiǎn)。
我的選擇是主觀的。
本文中提及的幾乎所有內(nèi)容都在 TC39 的技術(shù)雷達(dá)上。 也就是說,它還可以作為未來可能的 JavaScript 的預(yù)覽。
有關(guān)前兩個(gè)問題的更多想法,請(qǐng)參閱本文第8節(jié):語言設(shè)計(jì)部分。
1. 值 1.1 按值比較對(duì)象目前,JavaScript 只能對(duì)原始值(value)進(jìn)行比較,例如字符串的值(通過查看其內(nèi)容):
> "abc" === "abc" true
相反,對(duì)象則通過身份ID(identity)進(jìn)行比較(對(duì)象僅嚴(yán)格等于自身):
> {x: 1, y: 4} === {x: 1, y: 4} false
如果有一種能夠創(chuàng)建按值進(jìn)行比較對(duì)象的方法,那將是很不錯(cuò)的:
> #{x: 1, y: 4} === #{x: 1, y: 4} true
另一種可能性是引入一種新的類(確切的細(xì)節(jié)還有待確定):
@[ValueType] class Point { // ··· }
旁注:這種類似裝飾器的將類標(biāo)記為值類型的的語法基于草案提案。
1.2 將對(duì)象放入數(shù)據(jù)結(jié)構(gòu)中如果對(duì)象通過身份ID進(jìn)行比較,將它們放入 ECMAScript 數(shù)據(jù)結(jié)構(gòu)(如Maps)中并沒有太大意義:
const m = new Map(); m.set({x: 1, y: 4}, 1); m.set({x: 1, y: 4}, 2); assert.equal(m.size, 2);
可以通過自定義值類型修復(fù)此問題。 或者通過自定義 Set 元素和 Map keys 的管理。 例如:
通過哈希表映射:需要一個(gè)操作來檢查值是否相等,另一個(gè)操作用于創(chuàng)建哈希碼。 如果使用哈希碼,則對(duì)象應(yīng)該是不可變的。 否則破壞數(shù)據(jù)結(jié)構(gòu)就太容易了。
通過排序樹映射:需要一個(gè)比較值的操作用來管理它存儲(chǔ)的值。
1.3 大整數(shù)JavaScript 的數(shù)字總是64位的(雙精度),它能為整數(shù)提供53位二進(jìn)制寬度。這意味著如果超過53位,就不好使了:
> 2 ** 53 9007199254740992 > (2 ** 53) + 1 // can’t be represented 9007199254740992 > (2 ** 53) + 2 9007199254740994
對(duì)于某些場景,這是一個(gè)相當(dāng)大的限制?,F(xiàn)在有[BigInts提案](http://2ality.com/2017/03/es-...),這是真正的整數(shù),其精度可以隨著需要而增長:
> 2n ** 53n 9007199254740992n > (2n ** 53n) + 1n 9007199254740993n
BigInts還支持 casting,它為你提供固定位數(shù)的值:
const int64a = BigInt.asUintN(64, 12345n); const int64b = BigInt.asUintN(64, 67890n); const result = BigInt.asUintN(64, int64a * int64b);1.4 小數(shù)計(jì)算
JavaScript 的數(shù)字是基于 IEEE 754 標(biāo)準(zhǔn)的64位浮點(diǎn)數(shù)(雙精度數(shù))。鑒于它們的表示形式是基于二進(jìn)制的,在處理小數(shù)部分時(shí)可能會(huì)出現(xiàn)舍入誤差:
> 0.1 + 0.2 0.30000000000000004
這在科學(xué)計(jì)算和金融技術(shù)(金融科技)中尤其成問題?;谑M(jìn)制運(yùn)算的提案目前處于階段0。它們可能最終被這樣使用(注意十進(jìn)制數(shù)的后綴 m):
> 0.1m + 0.2m 0.3m1.5 對(duì)值進(jìn)行分類
目前,在 JavaScript 中對(duì)值進(jìn)行分類非常麻煩:
首先,你必須決定是否使用 typeof 或 instanceof。
其次,typeof 有一個(gè)眾所周知的的怪癖,就是把 null 歸類為“對(duì)象”。我還認(rèn)為函數(shù)被歸類為 "function" 同樣是奇怪的。
> typeof null "object" > typeof function () {} "function" > typeof [] "object"
第三,instanceof 不適用于來自其他realm(框架等)的對(duì)象。
也許可能通過庫來解決這個(gè)問題(如果我有時(shí)間,就會(huì)實(shí)現(xiàn)一個(gè)概念性的驗(yàn)證)。
2. 函數(shù)式編程 2.1 更多表達(dá)式不幸的是C風(fēng)格的語言在表達(dá)式和語句之間做出了區(qū)分:
// 條件表達(dá)式 let str1 = someBool ? "yes" : "no"; // 條件聲明 let str2; if (someBool) { str2 = "yes"; } else { str2 = "no"; }
特別是在函數(shù)式語言中,一切都是表達(dá)式。 Do-expressions 允許你在所有表達(dá)式上下文中使用語句:
let str3 = do { if (someBool) { "yes" } else { "no" } };
下面的代碼是一個(gè)更加現(xiàn)實(shí)的例子。如果沒有 do-expression,你需要一個(gè)立即調(diào)用的箭頭函數(shù)來隱藏范圍內(nèi)的變量 result :
const func = (() => { let result; // cache return () => { if (result === undefined) { result = someComputation(); } return result; } })();
使用 do-expression,你可以更優(yōu)雅地編寫這段代碼:
const func = do { let result; () => { if (result === undefined) { result = someComputation(); } return result; }; };2.2 匹配:解構(gòu) switch
JavaScript 使直接使用對(duì)象變得容易。但是根據(jù)對(duì)象的結(jié)構(gòu),沒有內(nèi)置的切換 case 分支的方法??雌饋硎沁@樣的(來自提案的例子):
const resource = await fetch(jsonService); case (resource) { when {status: 200, headers: {"Content-Length": s}} -> { console.log(`size is ${s}`); } when {status: 404} -> { console.log("JSON not found"); } when {status} if (status >= 400) -> { throw new RequestError(res); } }
正如你所看到的那樣,新的 case 語句在某些方面類似于 switch,不過它使用解構(gòu)來挑選分支。當(dāng)人們使用嵌套數(shù)據(jù)結(jié)構(gòu)(例如在編譯器中)時(shí),這種功能非常有用。 模式匹配提案目前處于第1階段。
2.3 管道操作管道操作目前有兩個(gè)競爭提案 。在本文,我們研究其中的 智能管道(另一個(gè)提議被稱為 F# Pipelines)。
管道操作的基本思想如下。請(qǐng)考慮代碼中的嵌套函數(shù)調(diào)用。
const y = h(g(f(x)));
但是,這種表示方法通常不能體現(xiàn)我們對(duì)計(jì)算步驟的看法。在直覺上,我們將它們描述為:
從值 x 開始。
然后把 f() 作用在 x 上。
然后將 g() 作用于結(jié)果。
然后將 h() 應(yīng)用于結(jié)果。
最后將結(jié)果賦值給 y。
管道運(yùn)算符能讓我們更好地表達(dá)這種直覺:
const y = x |> f |> g |> h;
換句話說,以下兩個(gè)表達(dá)式是等價(jià)的。
f(123) 123 |> f
另外,管道運(yùn)算符支持部分應(yīng)用程序(類似函數(shù)的 .bind() 方法):以下兩個(gè)表達(dá)式是等價(jià)的。
123 |> f(#) 123 |> (x => f(x))
使用管道運(yùn)算符一個(gè)最大的好處是,你可以像使用方法一樣使用函數(shù)——而無需更改任何原型:
import {map} from "array-tools"; const result = arr |> map(#, x => x * 2);
最后,讓我們看一個(gè)長一點(diǎn)的例子(取自提案并稍作編輯):
promise |> await # |> # || throw new TypeError( `Invalid value from ${promise}`) |> capitalize // function call |> # + "!" |> new User.Message(#) |> await stream.write(#) |> console.log // method call ;3 并發(fā)
一直以來 JavaScript 對(duì)并發(fā)性的支持很有限。并發(fā)進(jìn)程的事實(shí)標(biāo)準(zhǔn)是 Worker API,可以在 web browsers 和 Node.js (在 v11.7 及更高版本中沒有標(biāo)記)中找到。
在Node.js中的使用方法它如下所示:
const { Worker, isMainThread, parentPort, workerData } = require("worker_threads"); if (isMainThread) { const worker = new Worker(__filename, { workerData: "the-data.json" }); worker.on("message", result => console.log(result)); worker.on("error", err => console.error(err)); worker.on("exit", code => { if (code !== 0) { console.error("ERROR: " + code); } }); } else { const {readFileSync} = require("fs"); const fileName = workerData; const text = readFileSync(fileName, {encoding: "utf8"}); const json = JSON.parse(text); parentPort.postMessage(json); }
唉,相對(duì)來說 Workers 是重量級(jí)的 —— 每個(gè)都有自己的 realm(全局變量等)。我想在未來看到一個(gè)更加輕量級(jí)的構(gòu)造。
4. 標(biāo)準(zhǔn)庫JavaScript 仍然明顯落后于其他語言的一個(gè)領(lǐng)域是它的標(biāo)準(zhǔn)庫。當(dāng)然保持最小化是有意義的,因?yàn)橥獠繋旄菀走M(jìn)化和適應(yīng)。但是有一些核心功能也是有必要的。
4.1 用模塊替代命名空間對(duì)象JavaScript 標(biāo)準(zhǔn)庫是在其語言具有模塊之前創(chuàng)建的。因此函數(shù)被放在命名空間對(duì)象中,例如Object,Reflect,Math和JSON:
Object.keys()
Reflect.ownKeys()
Math.sign()
JSON.parse()
如果將這個(gè)功能放在模塊中會(huì)更好。它必須通過特殊的URL訪問,例如使用偽協(xié)議 std:
// Old: assert.deepEqual( Object.keys({a: 1, b: 2}), ["a", "b"]); // New: import {keys} from "std:object"; assert.deepEqual( keys({a: 1, b: 2}), ["a", "b"]);
好處是:
JavaScript 將變得更加模塊化(這可以加快啟動(dòng)時(shí)間并減少內(nèi)存消耗)。
調(diào)用導(dǎo)入的函數(shù)比調(diào)用存儲(chǔ)在對(duì)象中的函數(shù)更快。
4.2 可迭代工具 (sync 與 async)迭代 的好處包括按需計(jì)算和支持許多數(shù)據(jù)源。但是目前 JavaScript 只提供了很少的工具來處理 iterables。例如,如果要 過濾、映射或消除重復(fù),則必須將其轉(zhuǎn)換為數(shù)組:
const iterable = new Set([-1, 0, -2, 3]); const filteredArray = [...iterable].filter(x => x >= 0); assert.deepEqual(filteredArray, [0, 3]);
如果 JavaScript 具有可迭代的工具函數(shù),你可以直接過濾迭代:
const filteredIterable = filter(iterable, x => x >= 0); assert.deepEqual( // We only convert the iterable to an Array, so we can // check what’s in it: [...filteredIterable], [0, 3]);
以下是迭代工具函數(shù)的一些示例:
// Count elements in an iterable assert.equal(count(iterable), 4); // Create an iterable over a part of an existing iterable assert.deepEqual( [...slice(iterable, 2)], [-1, 0]); // Number the elements of an iterable // (producing another – possibly infinite – iterable) for (const [i,x] of zip(range(0), iterable)) { console.log(i, x); } // Output: // 0, -1 // 1, 0 // 2, -2 // 3, 3
筆記:
有關(guān)迭代器的工具函數(shù)示例,請(qǐng)參閱 Python 的 itertools (https://docs.python.org/3/lib...)。
對(duì)于 JavaScript,迭代的每個(gè)工具函數(shù)應(yīng)該有兩個(gè)版本:一個(gè)用于同步迭代,一個(gè)用于異步迭代。
4.3 不可變數(shù)據(jù)很高興能看到對(duì)數(shù)據(jù)的非破壞性轉(zhuǎn)換有更多的支持。兩個(gè)相關(guān)的庫是:
Immer 相對(duì)輕量,適用于普通對(duì)象和數(shù)組。
Immutable.js 更強(qiáng)大,更重量級(jí),并附帶自己的數(shù)據(jù)結(jié)構(gòu)。
4.4 更好地支持日期和時(shí)間JavaScript 對(duì)日期和時(shí)間的內(nèi)置支持有許多奇怪的地方。這就是為什么目前建議用庫來完成除了最基本任務(wù)之外的其它所有工作。
值得慶幸的是 temporal 是一個(gè)更好的時(shí)間 API:
const dateTime = new CivilDateTime(2000, 12, 31, 23, 59); const instantInChicago = dateTime.withZone("America/Chicago");5. 可能不需要的功能 5.1 optional chaining 的優(yōu)缺點(diǎn)
一個(gè)相對(duì)流行的提議功能是 optional chaining。以下兩個(gè)表達(dá)式是等效的。
obj?.prop (obj === undefined || obj === null) ? undefined : obj.prop
此功能對(duì)于屬性鏈特別方便:
obj?.foo?.bar?.baz
但是,仍然存在缺點(diǎn):
深層嵌套的結(jié)構(gòu)更難管理。
由于在訪問數(shù)據(jù)時(shí)過于寬容,隱藏了以后可能會(huì)出現(xiàn)的問題,更難以調(diào)試。
optional chaining 的替代方法是在單個(gè)位置提取一次信息:
你可以編寫一個(gè)提取數(shù)據(jù)的輔助函數(shù)。
或者你可以編寫一個(gè)函數(shù),使其輸入是深層嵌套數(shù)據(jù),但是輸出更簡單、標(biāo)準(zhǔn)化的數(shù)據(jù)。
無論采用哪種方法,都可以執(zhí)行檢查并在出現(xiàn)問題時(shí)盡早拋出異常。
進(jìn)一步閱讀:
“Overly defensive programming” by Carl Vitullo
Thread on Twitter by Cory House
5.2 我們需要運(yùn)算符重載嗎?目前正在為 運(yùn)算符重載 進(jìn)行早期工作,但是 infix 函數(shù)可能就足夠了(目前還沒有提案):
import {BigDecimal, plus} from "big-decimal"; const bd1 = new BigDecimal("0.1"); const bd2 = new BigDecimal("0.2"); const bd3 = bd1 @plus bd2; // plus(bd1, bd2)
infix 函數(shù)的好處是:
你可以創(chuàng)建 JavaScript 以外的運(yùn)算符。
與普通函數(shù)相比,嵌套表達(dá)式的可讀性仍然很好。
下面是嵌套表達(dá)式的例子:
a @plus b @minus c @times d times(minus(plus(a, b), c), d)
有趣的是,管道操作符還有助于提高可讀性:
plus(a, b) |> minus(#, c) |> times(#, d)6. 各種小東西
以下是我偶爾會(huì)遺漏的一些東西,但我認(rèn)為不如前面提到的那些重要:
鏈?zhǔn)疆惓#菏鼓隳軌虿东@錯(cuò)誤,能夠包含其他信息并再次拋出。
new ChainedError(msg, origError)
可組合的正則表達(dá)式:
re`/^${RE_YEAR}-${RE_MONTH}-${RE_DAY}$/u`
正則表達(dá)式的轉(zhuǎn)義文本(對(duì)于.replace()很重要):
> const re = new RegExp(RegExp.escape(":-)"), "ug"); > ":-) :-) :-)".replace(re, "
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/101983.html
摘要:編程中經(jīng)常定義一些短小的匿名函數(shù),使用箭頭函數(shù)語法可使得這類函數(shù)的定義更加簡潔。外部函數(shù)的,等價(jià)于定義個(gè)局部變量修改內(nèi)部的所以這樣,,也就無法修改箭頭函數(shù)的值的。拋異常即箭頭函數(shù)不能作為構(gòu)造函數(shù),其也不具有屬性。 一、概述 箭頭函數(shù)是指通過=>語法定義的函數(shù)。JS編程中經(jīng)常定義一些短小的匿名函數(shù),使用箭頭函數(shù)語法可使得這類函數(shù)的定義更加簡潔。 // ES3/5方式 var fun1 =...
摘要:接下來,我會(huì)檢查每個(gè)頁面以確保它使用有用的標(biāo)簽,包括標(biāo)題標(biāo)簽。這個(gè)問題讓面試官有機(jī)會(huì)了解潛在員工對(duì)工作難以勝任的部分。面試官可能需要考慮這種弱點(diǎn)對(duì)團(tuán)隊(duì)的影響。面試官可能會(huì)發(fā)現(xiàn)自己公司的計(jì)劃與未來員工的職業(yè)目標(biāo)是否保持一致。 翻譯:瘋狂的技術(shù)宅原文:https://www.indeed.com/hire/i... 本文首發(fā)微信公眾號(hào):jingchengyideng歡迎關(guān)注,每天都給你...
摘要:在整個(gè)年,看到發(fā)布版增加了許多功能,包括新的生命周期方法新的上下文指針事件延遲函數(shù)和。它在等待渲染異步響應(yīng)時(shí)數(shù)據(jù),是延遲函數(shù)背后用來管理組件的代碼分割的。發(fā)布自第版開始將近年后,于年發(fā)布。 前端發(fā)展發(fā)展迅速,非常的快。 本文將回顧2018年一些重要的前端新聞,事件和 JavaScript 趨勢。 想閱讀更多優(yōu)質(zhì)文章請(qǐng)猛戳GitHub博客,一年百來篇優(yōu)質(zhì)文章等著你! showImg(ht...
摘要:并且于年月日,四個(gè)主要的瀏覽器一致同意宣布的版本已經(jīng)完成,即將推出一個(gè)瀏覽器可以搭載的穩(wěn)定版本。因此本文著重介紹為什么比更快。本文主要表達(dá)的是為什么應(yīng)該是更快的。則不同,它是由幾大主要的瀏覽器廠商共同設(shè)計(jì)的。 作者:Alon Zakai 編譯:胡子大哈 翻譯原文:http://huziketang.com/blog/posts/detail?postId=58ce80d2a6d8a0...
閱讀 1694·2021-10-13 09:39
閱讀 3166·2021-10-12 10:11
閱讀 558·2021-09-28 09:36
閱讀 2642·2019-08-30 15:55
閱讀 1392·2019-08-30 13:04
閱讀 635·2019-08-29 17:08
閱讀 1915·2019-08-29 14:14
閱讀 3415·2019-08-28 18:23