iT邦幫忙

2022 iThome 鐵人賽

DAY 4
2
Modern Web

咩色用得好,歸剛沒煩惱 - 從 ECMAScript 偷窺 JavaScript Array method系列 第 4

Day 4 咩色用得好 - 我要如何看得懂 ECMAScript ?(part -1)

  • 分享至 

  • xImage
  •  

Prelude

我是阿傑,我們在 Day 3 簡單介紹了該如何起手 ECMAScript ,而今天就要進入較為 hardcore 的部分,但其實也沒想像中地這麼可怕,大家可以安心服用。

俗話說射人先射馬,這馬就是 ECMAScript 裡使用的各種術語(terms),理解這些你會發現這世界尚未如此險惡,今天會看以下 4 個名詞:

  • Abstract Operation
  • List
  • Internal Method
  • Internal Slots

那我們就開始吧!


Abstract Operation

我們都知道工程師的人生哲學就是不要一直做重複的事,而 function 便是程式碼中最好的體現 - 重複使用某個區塊的程式碼。

寫規範的人也不例外,ECMAScript 中有非常多重複的操作,撰寫規範的人為了避免不斷地複製貼上,所以 Abstract Operation 便應孕而生,它最大的功能就是將這些需要複用的邏輯、演算法抽離出來,只要這份規範有任何需要它的地方便呼叫它。

會用 呼叫 一詞就是因為它長得跟 function 沒什麼差別,例如 Array.prototype.find 裡用到的 Get(O,Pk) ,(圖 4.1):

4.1

是不是似曾相識?它看起來就像物件取值的 getter,並被帶入了 2 個參數 (O - 物件、Pk - 屬性的 key) 呼叫,而它也跟普通 funciton 一樣可以 return 一個值給你,你可以試著點進 Get 這個連結看看它做了哪些事。

當然也有些看起來像是 method 的抽象操作,例如 someValue.OperationName(arg1,arg2),就好像我們在使用一個 method 一樣!

Note:
抽象操作僅限於 ECMAScript 規範內部使用,並沒有要求實際語言將其實作出來,它只是為了簡化規範而產生的一種凝鍊寫法。


List

List 是 ECMAScript 內部的一種規範類型 (specification type),也就是說他並不存在於 JavaScript 等實作語言中!當函式呼叫或其他演算法需要一連串的參數 (argument list) 時,它便用來在規範內處理這件事。

List 跟 Array 的形式很像,它是一個有序且可通過索引 (index) 將值取出,例如 arguments[2] 表示 arguments 這個 List 的第 3 個 element,且它有自己的字面語法 (literal),例如: « 1, 2 » 代表一個包含 2 個元素的 List、而一個 new empty List 可以用 « » 來表示。

它目前最常出現的地方應該就是在 arguments 上了,所以暫時把它想像成一般的 Array 也無妨,我們來看看在 Array.prototype.find 的 List 出現在哪 (圖 4.2):

4.2

這個 Call abstrac operation 會呼叫一個 function,並在呼叫時帶入了 3 個參數:

  • predicate - 為一個 function
  • thisArg - 為指定的 this value
  • « kValue, ?(k), O » - 呼叫 predicate 這個 function時所帶入的參數列表 (argumentsList)

也就是 Call 帶入了 argumentsList 來呼叫 predicate 這個 function。


Internal Methods

在 ECMAScript 中,一個物件的實際語義 (actual semantic) 是透過 internal methods 來定義的...

你給翻譯翻譯

這句話很短但非常難理解,我試著用一個簡單的例子說明看看 - 大家可能聽過林書豪,但世界上有千百萬個林書豪,如果不透過他的身分證字號 (ID),我們該如何確定他就是我們要找的這個林書豪?其實不難,我們可以透過他的行為模式 - 這個「在 NBA 打球、球技精湛且輸球就吃麥當勞」的林書豪。

所以如果你想成為林書豪並不是改個名字整個容就成了(這個情節似乎在不少電影、漫畫都出現過),你同時還必須擁有跟他一樣的行為模式 - 「在NBA 打球、球技精湛且輸球就吃麥當勞」,但就算如此,別人可能也只會稱你為 小林書豪 XD,因為你們兩個還是不同的個體 (instance)。

如果將林書豪比喻成一個物件,那這些行為就是他的屬性方法 (method),也就是這些屬性方法讓他成為了林書豪。

而在 ECMAScript 裡,不同的物件擁有一系列不同的 internal method,這些 internal method 讓它們在程式運行期間 (runtime) 有著不同的行為,比如一個基本物件會有 [[Get]] 這個 essential internal method,而 function 物件卻有著另一個 [[Call]] internal method,這個多出來的 [[Call]] 便使它們成為兩個不同種類的物件。

看到這邊,細心如你應該也發現 [[Get]] 看起來就像是 Record 的一個 field,那該如何區分呢?很簡單,就是從它的上下文 (context) 來看,例如:

4.2

這個 dot (.) 前面是一個物件,後面又使用了圓括號 (parentheses) 來呼叫,因此這個 [[Get]] 是一個 internal method。

而這裡的 [[Get]](P,O) 實際語義為 - "讀取 O 物件的 P 屬性", 在 JavaScript 裡就是 o.po["p"]

Note:
Internal method 並非實作語言的一部分,它在 ECMAScript 單純是作為說明而存在的,但實作出來的物件行為必須跟 internal method 所表現的行為一致,至於實現的方法則不在 ECMAScript 的範疇裡。


Internal Slots

Internal Slots,一個很難理解的名詞, ECMAScript 利用它來保存資訊並代表物件的內部狀態,但要注意的是 internal slots 並不是物件的屬性而且也不會被繼承 。

在 ECMAScript 中,所有的一般物件 (ordinary object) 都有 [[Prototype]] 這個 internal slot,如果一個物件的 [[Prototype]] 的值不是 null,就表示它可以存取 [[Prototype]] 的屬性。

而在 JavaScript 中,所有 array instance 的 [[Prototype]] 指向的物件跟 Array.prototype 是一樣的,我們先來看看下面這張圖 (圖 4.3):

4.3

從瀏覽器的 console 可以看到這個 emptyArray 只有一個 length 屬性,而大部分的 Array method 都被放在 [[Prototype]] 裡面,聰明的你應該想到怎麼拿到他們了吧?

沒錯,就是直接取用,例如以下( 圖4.4):

4.4

雖然 emptyArray 沒有這些 Array method,但它會順著原型鏈 (prototype chain) 往上拿到自己沒有的屬性或 method,很方便吧!而這同時又產生了另一個好處 - 就是我們不需要把所有的屬性跟 method 都定義在 instance 。

最後,我們可以透過瀏覽器提供的 __proto__ 屬性及 Object.getPrototypeOf() 這個正規方法來驗證 emptyArray[[Prototype]]Array.prototype 是否指向同一物件:

4.5

Note:
我們無法透過 JavaScript 觀察到 internal slots,但可以透過瀏覽器的 DevTools 將其曝露出來。


Conclusion

我們將在 Day 5 繼續聊聊另外 4 個術語:

  • Record
  • Completion Record
  • ReturnIfAbrupt
  • ReturnIfAbrupt shorthand - ? & !

希望大家可以開心地使用各種咩色,體驗它帶給你的便利,祝大家歸剛沒煩惱。


參考資源


上一篇
Day 3 咩色用得好 - ECMAScript 該從哪邊下手啊?
下一篇
Day 5 咩色用得好 - 我要如何看得懂 ECMAScript ?(part -2)
系列文
咩色用得好,歸剛沒煩惱 - 從 ECMAScript 偷窺 JavaScript Array method30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
安揪拉
iT邦新手 4 級 ‧ 2022-09-21 15:25:30

我為什麼跪著讀(part-1)

我要留言

立即登入留言