摘要:另一部分就是類型的屬性,也就是返回的屬性。,一開始提案為,其作用就是遞歸的將數組展平到指定深度,默認深度為。目前在使用時,我們唯一的選擇是命令行界面。
TypeScript 3.3 更新梳理
Object.assign vs Object Spread in Node.js
New in Chrome 72
New JavaScript features in ES2019
iOS 12.2 Beta"s 支持 Web Share API
Yarn"s Future - v2 and beyond
TypeScript 3.3 更新梳理首先需要聲明的是,TypeScript 3.3 是個小版本 release,不包含 breaking changes,so 升級的話應該比較輕松。那么 3.3 中有什么新東西呢?我們一起來探索一下。
聯合類型(union types)的優化 先梳理一下我們先梳理下之前聯合類型是怎樣的。假設我們有聯合類型 A | B,則可以訪問 A 或 B 共有的屬性或方法(也就是 A 或 B 的交集)。
interface A { aProp: string; commonProp: string; } interface B { bProp: number; commonProp: number } type Union = A | B; declare let x: Union; x.aProp; // error - "B" doesn"t have the property "aProp" x.bProp; // error - "A" doesn"t have the property "bProp" x.commonProp; // okay! Both "A" and "B" have a property named `commonProp`.
這一點還是符合直覺的,我們只能訪問聯合類型的公共部分,這一點頗有些像多態性。
而當我們不是想訪問屬性,而是想處理調用方法的返回類型時,當然,不論是什么類型,我們的標識符參數都是一樣的,那么也一樣 work:
type CallableA = (x: boolean) => string; type CallableB = (x: boolean) => number; type CallableUnion = CallableA | CallableB; declare let f: CallableUnion; let x = f(true); // Okay! Returns a "string | number".更新點
但是問題來了,有時候這些約束還是會有些嚴格了,我們來看下面的例子:
type Fruit = "apple" | "orange"; type Color = "red" | "orange"; type FruitEater = (fruit: Fruit) => number; // eats and ranks the fruit type ColorConsumer = (color: Color) => string; // consumes and describes the colors declare let f: FruitEater | ColorConsumer; // Cannot invoke an expression whose type lacks a call signature. // Type "FruitEater | ColorConsumer" has no compatible call signatures.ts(2349) f("orange");
上面的例子就相對復雜了些,除了聯合類型還用到了 declare 聲明關鍵字和 type 別名關鍵字。我們調用了函數 f,而函數 f 的聲明表示,它是 FruitEater 和 ColorConsumer 的聯合類型,其中,FruitEater 和 ColorConsumer 分別是兩種自定義的函數類型的別名,而它們的函數參數也都是聯合類型。
這個代碼很傻瓜但卻報了錯,FruitEater 和 ColorConsumer 都應該能夠接收 "orange" 參數,它既可以返回一個數字,也可以返回一個字符串。
上述的問題在 TypeScript 3.3 中被干掉了:
type Fruit = "apple" | "orange"; type Color = "red" | "orange"; type FruitEater = (fruit: Fruit) => number; // eats and ranks the fruit type ColorConsumer = (color: Color) => string; // consumes and describes the colors declare let f: FruitEater | ColorConsumer; f("orange"); // It works! Returns a "number | string". f("apple"); // error - Argument of type ""apple"" is not assignable to parameter of type ""orange"". f("red"); // error - Argument of type ""red"" is not assignable to parameter of type ""orange"".
上面就很清晰了,"orange" 符合聯合類型的要求,所以 f 應該可以接收并正確返回,我們只需要保證返回的值是數字或者字符串就夠了。
在 TypeScript 3.3 中,這些交叉的類型會創建新的簽名。舉個例子,FruitEater 和 ColorConsumer 的參數 fruit 和 color 被交叉成了一個新的參數類型:Fruit & Color,如替換掉別名,Fruit & Color 實際上就是 ("apple" | "orange") & ("red" | "orange"),我們繼續演進,其實就是 ("apple" & "red") | ("apple" & "orange") | ("orange" & "red") | ("orange" & "orange")。而我們取交集運算后,最后得到的結果就是 "orange" & "orange",也就是 "orange"。
我們整理一下,用數學中集合那一塊的運算重新演算一遍:
Fruit & Color = ("apple" | "orange") & ("red" | "orange") = ("apple" & "red") | ("apple" & "orange") | ("orange" & "red") | ("orange" & "orange") = "orange" & "orange" = "orange"
日了狗了,我不就寫寫 JS 嗎,怎么算起了數學呢?萬惡的 MS...
復合項目的增量 watchTypeScript 3.0 引入了一個用于構建過程的被稱為「復合項目」的新功能。 其目的有二:
確保用戶可以將大型項目拆分為更小的部分,從而快速構建
保留項目結構,不影響現有的 TypeScript 體驗
在3.3版本之前,在使用 --build、--watch 構建復合項目時,實際上并沒有使用 watch 增量文件的基礎結構。 如果一個項目中有了更新,將會強制完全重新構建該項目,而不是檢查項目中有哪些文件受到影響。
在TypeScript 3.3中, --build 模式的 --watch 標志也可以利用增量文件機制進行監視了。這意味著在 --build --watch 模式下構建速度能將更快。測試下來的構建時間比原來縮短了 50% 到 75%。
接下來的發展我們可以在 roadmap 里看到接下來的發展路線。TypeScript 3.4 中我們就可以用上「只讀 數組和元組」和 const 上下文了,后續我們再看吧。
源地址:https://blogs.msdn.microsoft....
Object.assign vs Object Spread in Node.js今天來比較下 Object.assign 和 Object Spread 的差異。
因為我們在項目中配了 Babel,所以這兩個也是常用的。其中,2018 年的時候,[Ojbect Rest/Spread Proposal] 提案就已經到了 stage 4,也就是說不久就會進入 ECMAScript 規范。當然,從 Node.js 8 的 LTS 版本開始,這一提案的內容就已經有了,我們可以直接進入 Node 環境使用它:
$ node -v v8.9.4 $ node > const obj = { foo: 1, bar: 1 }; undefined > ({ ...obj, baz: 1 }); { foo: 1, bar: 1, baz: 1 }
Object spread operator,即對象展開運算符 { ...obj } 和 Object.assign() 的功能是很相似的,那我們應該用哪個,它們有什么區別呢?
Object spread 概況對象展開運算符本質上是創建一個新的由現有對象的 own property 組成的普通對象。什么是 own property?一部分是 Object.getOwnPropertyNames() 返回的屬性。那 Object.getOwnPropertyNames() 返回的是什么屬性?它返回的是對象中所有的、包括不可枚舉屬性的、排除 Symbol 在外的的屬性。另一部分就是 Symbol 類型的屬性,也就是 Object.getOwnPropertySymbols() 返回的屬性。
因此,{ ...obj }返回的就是和 obj 所包含的屬性和值相同的對象。
const obj = { foo: "bar" }; const clone = { ...obj }; // `{ foo: "bar" }` obj.foo = "baz"; clone.foo; // "bar"
和 Object.assign() 一樣,對象展開運算符同樣不復制繼承來的屬性和類本身的信息(因為它們掛在原型上),且會復制 ES6 的 Symbol 類型:
class BaseClass { foo() { return 1; } } class MyClass extends BaseClass { bar() { return 2; } } const obj = new MyClass(); obj.baz = function() { return 3; }; obj[Symbol.for("test")] = 4; // Does _not_ copy any properties from `MyClass` or `BaseClass` const clone = { ...obj }; console.log(clone); // { baz: [Function], [Symbol(test)]: 4 } console.log(clone.constructor.name); // Object console.log(clone instanceof MyClass); // false
這就很清楚了,Object spread 把繼承關系一概丟掉,類相關信息一概丟掉,只留著普通對象的屬性,可不可枚舉都有,Symbol 也有。
我們還可以利用對象展開運算符來混合屬性,當然這里就很簡單了,受順序影響會產生覆蓋行為:
const obj = { a: "a", b: "b", c: "c" }; { a: 1, b: null, c: void 0, ...obj }; // { a: "a", b: "b", c: "c" } { a: 1, b: null, ...obj, c: void 0 }; // { a: "a", b: "b", c: undefined } { a: 1, ...obj, b: null, c: void 0 }; // { a: "a", b: null, c: undefined } { ...obj, a: 1, b: null, c: void 0 }; // { a: 1, b: null, c: undefined }差異對比
上述的例子里,這兩者其實沒什么區別。事實上這倆操作可以寫個等式:
{ ...obj } === Object.assign({}, obj) // 這個等式是開玩笑的!
因此有:
const obj = { a: "a", b: "b", c: "c" }; Object.assign({ a: 1, b: null, c: void 0 }, obj); // { a: "a", b: "b", c: "c" } Object.assign({ a: 1, b: null }, obj, { c: void 0 }); // { a: "a", b: "b", c: undefined } Object.assign({ a: 1 }, obj, { b: null, c: void 0 }); // { a: "a", b: null, c: undefined } Object.assign({}, obj, { a: 1, b: null, c: void 0 }); // { a: 1, b: null, c: undefined }
那么問題來了,既然沒啥區別,我干嘛要用一個而不是另一個?
行為差異之一也是大家一般都知道的點是,對象展開運算符總是會返回一個 POJO(Plain Old Java Object) 對象,而 Object.assign() 如果將原對象作為第一個參數傳入,原對象會被修改:
class MyClass { set val(v) { console.log("Setter called", v); return v; } } const obj = new MyClass(); Object.assign(obj, { val: 42 }); // Prints "Setter called 42"
換句話講,Object.assign() 會修改第一個參數的對象,并且會觸發 ES6 setter。因此,如果我們更希望使用 Immutable 技術,自然要配置一下用上 object spread。這也是為什么,很多時候我們用 Object.assign() 的方式就是第一個參數置為空對象:
const copyOne = Object.assign({}, obj);性能
總的來說,如果我們向 Object.assign() 的第一個參數傳入 {},那么對象展開運算符更快,否則基本差不多。
我們來使用 benchmark.js 對其進行評估:
const Benchmark = require("benchmark"); const suite = new Benchmark.Suite; const obj = { foo: 1, bar: 2 }; suite. add("Object spread", function() { ({ baz: 3, ...obj }); }). add("Object.assign()", function() { Object.assign({ baz: 3 }, obj); }). on("cycle", function(event) { console.log(String(event.target)); }). on("complete", function() { console.log("Fastest is " + this.filter("fastest").map("name")); }). run({ "async": true });
這種場景下,而這差別不大:
Object spread x 3,170,111 ops/sec +-1.50% (90 runs sampled)
Object.assign() x 3,290,165 ops/sec +-1.86% (88 runs sampled)
Fastest is Object.assign()
但如果向 Object.assign() 的第一個參數傳入 {},對象展開運算符就總是更快了:
suite. add("Object spread", function() { ({ baz: 3, ...obj }); }). add("Object.assign()", function() { Object.assign({}, obj, { baz: 3 }); })
得到結果為:
Object spread x 3,065,831 ops/sec +-2.12% (85 runs sampled)總結
Object.assign() x 2,461,926 ops/sec +-1.52% (88 runs sampled)
Fastest is Object spread
行為上,Object.assign() 可以修改第一個參數傳入的對象,觸發 ES6 setter
性能上,當Object.assign() 的第一個參數傳入 {},{ ...obj } 更快
New in Chrome 72在 Chrome 72 中新增支持如下:
創建類的共有域變得更加簡潔
新的 User Activation API 可以幫助我們知道一個頁面是否被「激活」
Intl.format() API 可以幫助我們更簡單的定位列表
當然,第一條我們曾經提到過,而第二第三條我沒有了解過。
Public class fields現在我們不再需要在 constructor 中聲明,只需要直接在類定義中聲明類的共有域即可。主要的使用就是通過下劃線來表明其域的身份,然后可以通過 getter、setter 來操作。
class Counter { _value = 0; get value() { return this._value; } increment() { this._value++; } } const counter = new Counter(); console.log(counter.value); // → 0 counter.increment(); console.log(counter.value); // → 1
對私有域的支持以及在開發中了。當然如果 Babel 動作更快的話,就又可以先用上了。
User Activation API我們可能都遇到過頁面加載好就自動播放音樂的場景,然后被嚇一跳,趕緊找個靜音鍵或者把 tab 關掉。這就是為什么一些 API 需要通過用戶的某種操作觸發后才起作用。不過不同瀏覽器對這個觸發的操作的處理并不相同。
Chrome 72 引入了 User Activation v2,它對所有這類 API 進行了簡化。v2 基于新的標準,為了能夠使所有瀏覽器標準化。
新的 userActivation 屬性掛在了 navigator 和 MessageEvent 上:hasBeenActive 和 isActive。
hasBeenActive 表明關聯的窗口是否在其周期內見到了 user activation
isActive 表明關聯的窗口是否已經觸發了 user activation
這一點沒了解過,略有些不理解。看下這個圖吧,圖為用戶觸發 User activation API 之前和之后的變化。
Localizing lists of things with Intl.format用我們想用的語言初始化,然后調用 format 方法,它就會使用正確的詞語和語法。例如下面的例子是將列表中的單詞拼接起來,并且按照指定的語言(fr,指法語),補充了相應語言的「and 與」及「or 或」的單詞。這部分操作都會交給 JS 引擎而不會犧牲性能。如下就是將一些動物名詞用 or 來拼接:
const opts = {type: "disjunction"}; const lf = new Intl.ListFormat("fr", opts); lf.format(["chien", "chat", "oiseau"]); // → "chien, chat ou oiseau" 意思是「狗、貓或鳥」 lf.format(["chien", "chat", "oiseau", "lapin"]); // → "chien, chat, oiseau ou lapin" 意思是「狗、貓、鳥或兔子」
源地址:https://developers.google.com...
New JavaScript features in ES2019Chrome 73 默認支持這些 ES2019 特性,因此今天來盤一部分新特性。
Array#{flat,flatMap}:Array.prototype.flat,一開始提案為 Array.prototype.flatten,其作用就是遞歸的將數組展平到指定深度,默認深度為 1。這個方法感覺像過去被問過的題。
// Flatten one level: const array = [1, [2, [3]]]; array.flat(); // → [1, 2, [3]] // Flatten recursively until the array contains no more nested arrays: array.flat(Infinity); // → [1, 2, 3]
提案還包括 Array.prototype.flatMap,它會把數組再展成新的數組。
[2, 3, 4].flatMap((x) => [x, x * 2]); // → [2, 4, 3, 6, 4, 8]
源地址:https://developers.google.com...
Object.fromEntries:Object.fromEntries 是針對 Object.entries 的補充,基本可以理解成 Object.fromEntries(Object.entries(object)) ≈ object。
const object = { x: 42, y: 50 }; const entries = Object.entries(object); // [["x", 42], ["y", 50]] const result = Object.fromEntries(entries); // { x: 42, y: 50 }
源地址:https://github.com/tc39/propo...
String#{trimStart,trimEnd}:除了已有的 String.prototype.trim(),V8 現在實現了 String.prototype.trimStart() 和 String.prototype.trimEnd()。過去這倆功能有非標準的 trimLeft() 和 trimRight()。
const string = " hello world "; string.trimStart(); // → "hello world " string.trimEnd(); // → " hello world" string.trim(); // → "hello world"
源地址:https://v8.dev/blog/v8-releas...
Symbol#description:Symbol.prototype.description 提案在 stage 4,所以也是 ES2019 中的內容。
當我們通過工廠函數 Symbol() 創建了一個 symbol 的時候,我們可以選擇傳入一個字符串作為說明:
const sym = Symbol("The description");
過去我們想要使用這個說明的方法是通過 String:
assert.equal(String(sym), "Symbol(The description)");
現在提案引入了 Symbol.prototype.description,我們可以通過原型鏈上的屬性來訪問:
assert.equal(sym.description, "The description");
源地址:http://2ality.com/2019/01/sym...
try {} catch {} // optional binding:這一條說的是 try-catch 可以不強制使用參數了,也就是 err。
try { doSomethingThatMightThrow(); } catch { // no binding! handleException(); }stable Array#sort:
過去 V8 對于超過 10 個元素的數組使用的是不穩定的快排,現在使用的是穩定的 TimSort 算法。
源地址:https://twitter.com/mathias/s...
iOS 12.2 Beta"s 支持 Web Share APIiOS 12.2 beta 版在 Safari 和其他 web 視圖里引入了 Web Share API。這說明什么呢?我們可以通過在頁面上創建一個按鈕,而這個按鈕可以觸發原生系統拉起「share sheet」。
具體是什么樣的呢?我們可以看下官方 Demo,頁面如下:
可以看下這個 Demo 的源碼,核心部分就是下面這句:
try { await navigator.share({ title, text, url }); } catch (error) { logError("Error sharing: " + error); return; }
所以這里我們可以做些能力檢測,再決定是否調用:
if (navigator.share === undefined) { logError("Error: You need to use a browser that supports this draft proposal."); }
其效果就是拉起「share sheet」,放張圖就知道了(當然這里并沒有升系統版本,但喚起的 share sheet 就是圖中所示):
補充:Web Share API 文檔見這里。
Yarn"s Future - v2 and beyond今天看下 Ma?l Nison 關于 Yarn 未來的展望。嗯,大佬終究是大佬,發量果然還可以。
Yarn 將成為一個開發優先的工具這話我們已經說了一段時間了,但是現在我們已經準備好開始了。包管理器不是應該在生產服務器上運行的工具。在那里運行的代碼越多,出現問題的可能性就越高,最終會導致生產系統崩潰。Yarn 的開發優先意味著我們將使您能夠做到像是克隆存儲庫的狀態。這包括重點使用 Plug"n"Play。
Yarn 將使用 TypeScript 重寫Yarn 已經完全被 Flow 類型覆蓋,而且運作的非常不錯。我們希望讓第三方貢獻者盡可能輕松地進行 shim 并幫助我們維護這個非常棒的工具,所以我們將代碼切換為 TypeScript 實現。我們希望這有助于使代碼庫比您已經貢獻的項目更熟悉。
Yarn 會成為一個 API,內部組件可以被拆分成模塊化實體這是個很大的目標。目前在使用 Yarn 時,我們唯一的選擇是命令行界面。我們沒有提供允許您利用我們實現的復雜邏輯的 primitives -— 無論是解析器、鏈接器還是訪問配置。Yarn 將首先是 API,然后是 CLI。
Yarn 會支持不同的安裝目標而不僅是 Node包管理是一個總是被不斷推翻重來的難題 - 即使 Yarn 過去也是這樣做的。我們認為原因是所有包管理器都需要以稍微不同的方式布置已安裝的包,以便宿主讀取它們。遺憾的是,這很難實現,最終重寫包管理器并丟棄已有的用戶體驗和功能反而變得更容易些。從 Berry 開始,我們明確了一個目標,即可以切換管道的每個組件以適應不同的安裝目標。在某種程度上,Yarn 現在將不僅是包管理器,還要成為包管理器平臺。如果您仍想使用 Yarn 來對 PHP、Python、Ruby 軟件包進行管理,開一個 issue,我們一起來做!
需要的時候,整體上的兼容性將會被保留這種 semver-major changes 在設計上是不向后兼容的,但我們會確保將它們保持在可接受的水平,特別是核心命令(yarn install、yarn add、yarn remove、yarn run)將保持相同的行為。先前 yarn.lock將被靜默遷移。一個重要的警告:我們的安裝現在默認使用 Plug"n"Play。在過去的幾個月里,我們已經證明這種方法是合理的,可以解決所有潛在的實施問題,最后與項目維護人員討論,以確定是否有任何我們可以做的事情來幫助他們確保一切準備就緒。現在是時候冒險了。
源地址:https://github.com/yarnpkg/ya...
「每日一瞥」是團隊內部日常業界動態提煉,發布時效可能略有延后。文章可隨意轉載,但請保留此 原文鏈接。
非常歡迎有激情的你加入 ES2049 Studio,簡歷請發送至 caijun.hcj(at)alibaba-inc.com 。
若有收獲,就賞束稻谷吧
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/101784.html
摘要:目前前端主要有以下四種方法會觸發對應的回調方法方法客戶端回調客戶端回調參考地址每日一瞥是團隊內部日常業界動態提煉,發布時效可能略有延后。 showImg(https://segmentfault.com/img/remote/1460000017975436?w=1200&h=630); 「ES2015 - ES2018」Rest / Spread Properties 梳理 Thr...
showImg(https://segmentfault.com/img/remote/1460000018793640?w=900&h=500); 簡介 安全、注入攻擊、XSS 13歲女學生被捕:因發布 JavaScript 無限循環代碼。 這條新聞是來自 2019年3月10日 很多同學匆匆一瞥便滑動屏幕去看下一條消息了,并沒有去了解這段代碼是什么,怎么辦才能防止這個問題。事情發生后為了抗議日本...
摘要:配置在設置項中確認包含增加設置項,值為一個字符串路徑,必須以結尾在模板中這樣引用在的目錄存放靜態文件開發期間使用極度低效時有別的做法注意默認為,一個列表,表示獨立于的靜態文件存放位置。 配置 1.在INSTALLED_APPS設置項中確認包含django.contrib.staticfiles 2.增加STATIC_URL設置項,值為一個字符串(路徑),必須以‘/’結尾 3.在模板中...
閱讀 2335·2021-11-24 09:39
閱讀 3778·2021-11-19 09:40
閱讀 2153·2021-09-27 13:36
閱讀 1897·2019-08-30 15:44
閱讀 390·2019-08-30 13:52
閱讀 2713·2019-08-30 11:13
閱讀 2171·2019-08-29 16:18
閱讀 1755·2019-08-29 15:43