「每日一瞥 📰 」0114 ~ 0118

題圖

  • 「ES2015 - ES2018」Rest / Spread Properties 梳理
  • Three.js 概念梳理
  • 火狐 Nightly 支持 CSS Grids 動畫
  • 換個姿勢起 Node.js 工程
  • WebView & JS Bridge 筆記

「ES2015 - ES2018」Rest / Spread Properties 梳理

第 9 版 ECMAScript 標準,官方稱爲 ECMAScript 2018(或簡稱 ES2018),已於 2018 年 6 月發佈。從 ES2016 開始,ECMAScript 規範每年都會發布新版本,但添加的功能少於以前的主版本。最新版本發佈了 4 個新的 RegExp、Rest / Spread 屬性、Asynchronous Iteration、Promise.prototype.finally。此外,ES2018 從標記模板中刪除了轉義序列的語法限制。

這裏我們對 Rest / Spread Properties 進行梳理。

Spread

在 ES2015 中一個非常有趣的特性就是 spread operator(擴展操作符)。這一操作符是的複製和合並數組變得更爲簡潔。我們不再需要使用 concat() 方法或 slice() 方法,一個 ... 操作符已經足夠:

const arr1 = [10, 20, 30];

// make a copy of arr1
const copy = [...arr1];

console.log(copy);    // → [10, 20, 30]

const arr2 = [40, 50];

// merge arr2 with arr1
const merge = [...arr1, ...arr2];

console.log(merge);    // → [10, 20, 30, 40, 50]

不僅如此,我們還可以將數組作爲一個需要單獨一個個傳入參數的函數的參數傳入,這麼說可能有點繞,看個例子就懂了:

const arr = [10, 20, 30]

// equivalent to
// console.log(Math.max(10, 20, 30));
console.log(Math.max(...arr));    // → 30

在 ES2018 中,這一語法糖進一步擴展,對於對象屬性展開復制的場景也可以發揮作用。事實上這一特性從比較早的時候,我們就開始應用在了項目中:

const obj1 = {
  a: 10,
  b: 20
};

const obj2 = {
  ...obj1,
  c: 30
};

console.log(obj2);    // → {a: 10, b: 20, c: 30}

在上面的代碼中,... 操作符用於獲取 obj1 的屬性,並賦值給 obj2。在 ES2018 之前,這麼做是會拋出異常的。如果存在若干相同 key 的屬性,會選擇後賦值或生成的屬性:

const obj1 = {
  a: 10,
  b: 20
};

const obj2 = {
  ...obj1,
  a: 30
};

console.log(obj2);    // → {a: 30, b: 20}

當然,我們還可以使用擴展屬性來合併兩個甚至更多對象,當然我們也可用通過 Object.assign() 來實現:

const obj1 = {a: 10};
const obj2 = {b: 20};
const obj3 = {c: 30};

// ES2018
console.log({...obj1, ...obj2, ...obj3});    // → {a: 10, b: 20, c: 30}

// ES2015
console.log(Object.assign({}, obj1, obj2, obj3));    // → {a: 10, b: 20, c: 30}

不過有意思的是,擴展屬性並不總能生成與 Object.assign() 相同的結果,我們看下下面的場景:

Object.defineProperty(Object.prototype, 'a', {
  set(value) {
    console.log('set called!');
  }
});

const obj = {a: 10};

console.log({...obj});    
// → {a: 10}

console.log(Object.assign({}, obj));    
// → set called!
// → {}

Object.assign() 會執行集成的 setter 屬性,而擴展運算會忽略 setter。

值得注意的是,擴展屬性只會複製可枚舉屬性。下面的例子中,type屬性不會出現在複製的對象中,因爲它的 enumerable 屬性被置爲 false。

const car = {
  color: 'blue'
};

Object.defineProperty(car, 'type', {
  value: 'coupe',
  enumerable: false
});

console.log({...car});    // → {color: "blue"}

當然,即使是 enumerable 的屬性,繼承過來的仍然會被忽略

const car = {
  color: 'blue'
};

const car2 = Object.create(car, {
  type: {
    value: 'coupe',
    enumerable: true,
  }
});

console.log(car2.color);                      // → blue
console.log(car2.hasOwnProperty('color'));    // → false

console.log(car2.type);                       // → coupe
console.log(car2.hasOwnProperty('type'));     // → true

console.log({...car2});                       // → {type: "coupe"}

上面的代碼中,car2 從 car1 繼承了 color 屬性。因爲擴展運算只複製對象本身的屬性,color 就不含在返回的值中了。

要記住的一點是,擴展運算做的是對象的淺拷貝。如果一個屬性本身也是對象,那麼擴展運算只會複製這個對象的引用:

const obj = {x: {y: 10}};
const copy1 = {...obj};    
const copy2 = {...obj}; 

console.log(copy1.x === copy2.x);    // → true

copy1 中的 x 屬性與 copy2 的 x 屬性在內存中引用的是相同的對象,因此「嚴格等於」運算符返回的是 true。

Rest

ES2015 中引入的另一個有用的特性是 rest parameters,它可以使得我們使用 ... 來把一些值作爲數組返回。舉個例子就明白了:

const arr = [10, 20, 30];
const [x, ...rest] = arr;

console.log(x);       // → 10
console.log(rest);    // → [20, 30]

這裏,arr 的第一個項賦值給了 x,而剩下的項被複制給了 rest。這個模式我們稱之爲 array destructuring,中文翻譯爲「數組解構」,這個模式在 Ecma 技術委員會決定將其帶到對象中後變得非常的流行:

const obj = {
  a: 10,
  b: 20,
  c: 30
};

const {a, ...rest} = obj;

console.log(a);       // → 10
console.log(rest);    // → {b: 20, c: 30}

在這段代碼中,通過結構的方式,我們複製了可枚舉屬性並複製到新的對象中。注意,rest 屬性總是出現在對象的最後,否則就會拋出異常:

const obj = {
  a: 10,
  b: 20,
  c: 30
};

const {...rest, a} = obj;    // → SyntaxError: Rest element must be last element

同樣需要注意的是,如果在同一個對象中使用多個 rest,也會導致錯誤,除非這些 rest 是嵌套的形式:

const obj = {
  a: 10,
  b: {
    x: 20,
    y: 30,
    z: 40
  }
};

const {b: {x, ...rest1}, ...rest2} = obj;    // no error

const {...rest, ...rest2} = obj;    // → SyntaxError: Rest element must be last element

兼容性

Chrome Firefox Safari Edge
60 55 11.1 No
Chrome Android Firefox Android iOS Safari Edge Mobile Samsung Internet Android Webview
60 55 11.3 No 8.2 60

對應 Node.js,兼容性如下:

  • 8.0.0 (需要 --harmony 運行時 flag)
  • 8.3.0 (完全支持)

源地址:https://css-tricks.com/new-es...

Three.js 概念梳理

Three.js 是一款運行在瀏覽器中的 3D 引擎,我們可以用它創建各種三維場景。今天我們來對這一塊進行一些初步的學習和梳理。

兼容性

Three.js 基於 WebGL 進行封裝,因此其兼容性由 WebGL 在不同瀏覽器的兼容性決定。其中,WebGL 的兼容性如下:

可以看出,WebGL 的兼容性還是不錯的。

然而 WebGL 2 的兼容性就不那麼好了,

可以看到,Safari 對 WebGL 2 的支持還不是很好,而知名的 TensorFlow.js 的瀏覽器版本就是基於 WebGL 2,因此 TensorFlow.js 在 Safari 上就有些無力了。

小工具

在瞭解的過程中發現了一個不錯的工具,可以查看當前瀏覽器對 WebGL 1.0/2.0 的支持情況。

概念點和關係梳理

火狐 Nightly 支持 CSS Grids 動畫

在火狐瀏覽器 Nightly (66) 版本中,CSS Grids 的軌跡可以動畫化了,可以看看視頻,效果很酷炫。

這一效果用 CSS 動畫以及 grid-template-columnsgrid-template-rows 即可實現,具體 Demo 可見這裏

源地址:https://twitter.com/jensimmon...

換個姿勢起 Node.js 工程

通常起 Node.js 項目的姿勢

通常我們會使用 npm 來起一個新的 Node.js 工程:

$ npm init

npm 接下來會問一系列的問題,並根據我們的回答來生成 package.json。然後呢?我們不可避免的從 Github 上的一些倉庫裏 copy & paste 一個 .gitignore 模板來用。當然如果我們玩的是開源項目,還得記得附上一些 LICENSE 文件來聲明我們使用的協議。

但這樣也太沒效率了!如果每次都這麼搞一遍,真的能忍?

更有效率的方式

這周我在推上看到這麼一條:

這四條指令足以把我手動做的這些事都做掉,而且還不止,然後我們就能夠成功的創建起一個工程了。下面我們逐條解釋下這四條的作用:

  • npx license mit 會使用 license 包來下載該協議對應的選項,這裏的例子是指 MIT 協議。
  • npx gitignore node 使用 gitignore 包來從 GitHub 倉庫自動下載對應的 .gitignore 文件。
  • npx covgen 使用 covgen 包來生成 Contributor Covenant(參與者公約)。
  • npm init -y 會自動選擇 npm init 詢問的那些問題的默認選項。

自定義 npm init

是的,npm 支持一些自定義配置。我們可以通過在命令行輸入 npm config list 來看下 npm 的配置。當然如果只想看與 npm init 相關的配置項,可以搭配使用 grep

npm config list | grep init

我可以設置許多默認配置:作者姓名、作者電子郵件、作者 URL、許可證和版本。如果要設置它們,我們可以在命令行中輸入下面對應語句,或者使用 npm config edit 在文本編輯器中打開配置文件。使用命令行很簡單,你可以設置所有五個默認值:

npm set init.author.name "Your name"
npm set init.author.email "[email protected]"
npm set init.author.url "https://your-url.com"
npm set init.license "MIT"
npm set init.version "1.0.0"

當你已經做好自定義配置後,npm init -y 就會直接生成你想要的配置了。

最後

這樣你就可以換個姿勢來開啓一個 Node 工程啦!

源地址:https://philna.sh/blog/2019/0...

WebView & JS Bridge 筆記

這一篇是總結了一些文檔和博客的筆記。

什麼是 WebView

對於這個問題,我們可以谷歌一下,去開發者官方文檔看看文檔是怎麼說的:

總結下來就一句話:WebView 就是個用於展示頁面的 View。可以看到 android.webkit.WebView 繼承自 android.view.View,只要接觸過一些 native 的東西,大致就知道它是類似 div 一樣的東西。View 本身是 widget 的基類,而 widget 就是用來創建交互 UI 的組件(如按鈕、文字域之類)。

那麼 WebView 可以做什麼呢?

首先,WebView 只可以讓你在 app 的界面上展示網頁內容,但不具備通常瀏覽器的完整功能,如導航控制、地址欄等。當然,WebView 使得開發者可以將 web 頁面嵌到 app 上,在一些場景下是一種不錯的模式。

其次,你可以通過一些 native 技術來爲 WebView 提供一些 bridge,從而獲得一些原生能力,這也就是我們通常所說的 js bridge。但是現實總是殘酷的,我們可以看下這一段

國產手機的廠商基本在出廠時都自帶了瀏覽器,查看系統應用時,發現並沒有內置 com.android.webview 或者com.google.android.webview 包,這些瀏覽器並不是簡單地套了一層 WebView 的殼,而是直接使用了 Chromium 內核,至於有沒有魔改過內核源碼,不得而知。國產出品的瀏覽器,如 360 瀏覽器、QQ 瀏覽器、UC 瀏覽器,幾乎都魔改了內核。值得一提的是,騰訊出品的 X5 內核,號稱頁面渲染流暢度高於原生內核,客戶端減少了 WebView 帶來坑的同時,增加了前端適配的難度,功能實現上需要有更多地考慮。

JS Bridge 基本原理

JS Bridge 是爲了支持 JavaScript 與 native 相互通信的模塊(庫/組件),有了 JS Bridge 我們就能夠在 WebView 裏使用一些 native 提供的能力。

JavaScript 調用 native 的方式大致可以有三類:注入映射、攔截 schema、攔截方法。

下面以安卓爲例來解釋下兩種思路:

  1. 注入映射類的方式:
//定義好 Java 接口對象
public class SDK extends Object {
    @JavascriptInterface
    public void hello(String msg) {
        System.out.println("Hello World");
    }
}

//Webview 中調用
WebView webview = (WebView) findViewById(R.id.webview);
webview.addJavascriptInterface(new SDK(), 'sdk');
webview.loadUrl('http://imnerd.org'); //注入後加載頁面

可以看到 addJavascriptInterface 方法定義了映射,我們就可以通過 sdk.hello() 來執行 native 方法了。不過這個方法存在安全問題,這裏僅作演示。

作爲對比,我們看看 iOS 的,意思是差不多的:

- (void)webViewDidFinishLoad:(UIWebView *)webView
{
    self.jsContext = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
    self.jsContext[@"hello"] = ^() {
        NSLog(@"Hello World");
    };
}
  1. 攔截 schema 的方式:

這一種方式我們很容易理解,我們可以約定 url 的 schema,當發生 url 跳轉時,如果符合約定的 schema,就交給客戶端來攔截相應操作。

  1. 攔截方法的方式

JS 的一些方法執行時會觸發客戶端中的一些回調,因此可以通過對前端參數進行識別來執行對應的客戶端代碼。目前前端主要有以下四種方法會觸發對應的回調方法:

JS 方法 Android 客戶端回調 iOS 客戶端回調
alert onJsAlert runJavaScriptAlertPanelWithMessage
prompt onJsPrompt runJavaScriptTextInputPanelWithPrompt
confirm onJsConfirm runJavaScriptConfirmPanelWithMessage

參考地址:

https://developer.android.com...
https://juejin.im/post/5a94f9...
https://juejin.im/post/5abca8...
https://75team.com/post/andro...

「每日一瞥」是團隊內部日常業界動態提煉,發佈時效可能略有延後。

文章可隨意轉載,但請保留此 原文鏈接

非常歡迎有激情的你加入 ES2049 Studio,簡歷請發送至 caijun.hcj(at)alibaba-inc.com 。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章