SlideShare a Scribd company logo
9. meta-programming
• 學習目標
– 探索物件特性
– 判斷物件型態
– 認識Reflect API
– 結合Proxy與Reflect API
2
• meta前置詞源於希臘文,原本相當於之後
(after)、超越(beyond)之意
• 後續衍生出許多意義,像是關於(about)
– metadata是「與資料相關的資料」(data
about data)
3
• meta-programming可以對比為「與程式
設計相關的程式設計」(programming
about programming)
• 不同於靜態的data,programming是動態
的,「meta-programming從事的程式設
計,會影響另一個程式設計」
4
• 就JavaScript而言…
• 檢視程式行為、修改程式行為,甚至是修
改語言預設行為等,可以令程式受到影響
的程式設計
5
修補API
6
• 要運用這種手法,必須是特性值不會被設
為Falsy family成員的情況
• 如果無法避免這類情況,必須做更嚴格的
檢查
7
8
特性/值清單
• for..in針對的是實例本身以及繼承而來
的可列舉(emnuerable)特性
• propertyIsEnumerable()
9
• Object.keys()
• Object.values()
• Object.entries()
10
• Object.getOwnPropertyNames()
• Object.getOwnPropertySymbols()
11
特性順序
• EnumerateObjectProperties規範只從實
例本身以及原型鏈取得可列舉特性,for
in就是實作之一
• 沒有規範順序排列問題,因此for in列舉
的特性順序因不同引擎實作而有所差別
• Object.keys()的順序是依賴在實作品
12
• [[OwnPropertyKeys]]規範如何取得自身
特性,也定義了順序
– 會先考慮數字索引,以數字遞增方式取得,接
著是特性被建立的順序,然後才是符號被建立
的順序
• 採用的函式有…
– Object.getOwnPropertyNames()
– Object.getOwnPropertySymbols()
– Reflect.ownKeys()
13
物件型態
• 對於基本型態、函式、undefined、
Function實例的話,許多場合會使用
typeof,對於其他的物件型態
• 如果想判斷物件是否屬於某個繼承關係,
常見使用instanceof
• 在沒有進一步定義下,instanceof的判
斷依據是原型鏈
14
• Symbol.hasInstance靜態方法傳回值決
定了使用instanceof判斷時,受測實例
是否被視為此類別型態
15
constructor特性
• 不是個別實例擁有,而是建構式或類別
prototype上的特性
• 也常見作為型態檢測的依據
• constructor可以修改
• 使用原型鏈實現繼承時,建議設定
constructor指向子建構式
• 使用類別語言定義子類別時,會自動設定
constructor特性
16
Object.prototype.toString()
• ECMAScript規範要求呼叫後,必須傳回
'[object class]'格式的字串
17
• 基於對標準的支持,不少程式庫也會使用
這個來作為標準內建型態的判斷依據
• ES5以前,沒有方式可以調整'[object
class]'格式中'class'的部份
• Object.prototype.toString()實際
上是取得引擎內部實作[[Class]]的資訊
18
• ES6在定義建構或類別時,可以定義
Symbol.toStringTag特性,決定
'[object class]'格式'class'的部份
19
20
真陣列?
• Array.isArray()就是根據內部實作特
性[[Class]]的值'Array‘
• 在ES5剛釋出的那個年代,若想修補
Array.isArray()該怎麼做呢?
21
• 真正的Array.isArray()看的是[[Class]]
22
Symbol.species
• 陣列的方法執行後若傳回陣列,使用類別
語法繼承Array的子型態,呼叫這類方法
後傳回的物件也會是子型態
• 指定子類別要使用哪個類別來建構實例
23
24
25
物件相等性
• ==
• ===
• SameValueZero
• SameValue
26
• Set元素、Map的鍵在比較相等性時,使用
SameValueZero演算
– 採用===,然而NaN等於NaN,0等於-0。
• SameValue演算與SameValueZero演算不
同的地方只在於,0不等於-0,
27
• 採用SameValue演算的API之一是
Object.is()函式
28
• Object.defineProperty()、
Object.defineProperties()
29
• 多數API基本上採用===就好了
• 如果真的不能避免NaN,或者必須區分0與-
0,就要留意SameValueZero與
SameValue的差別
30
Reflect與Proxy
• ECMAScript規範[[GetPrototypeOf]]、
[[SetPrototypeOf]]、[[IsExtensible]]等
• 在實現JavaScript引擎時,這類演算實現為
引擎的內部方法(Internal method)
• 在ES5時,可以存取內部方法的API,隨意
地配置為Object的函式
31
• ES6以後,提供了Reflect API作為存取內
部方法的統一管道,並提供更多的控制細
節
• ES6以後也新增Proxy API,提供了干涉內
部方法的時機點,可干涉的點與Reflect
API一對一對應
• 透過Proxy與Reflect的各種結合,就可
為 meta-programming提供諸多的可能性
32
Reflect API
• Object被取代的函式
– Reflect.getPrototypeOf()
– Reflect.setPrototypeOf()
– Reflect.isExtensible()
– Reflect.preventExtensions()
– Reflect.defineProperty()
– Reflect.getOwnPropertyDescriptor()
33
• 與Object上相對應的函式,功能上基本相
同
• 略作調整的地方
– Object有些對應的函式執行完會傳回物件本
身,而Reflect會傳回布林值
– Object對應的函式target參數若是基本型態,
會使用對應的類別實例來包裹基本型態值,然
而,Reflect在此時會拋出TypeError
34
• 在ES6以後,建議使用Reflect的這些方法,
來取代Object對應的方法
• 未來與內部方法存取相關的函式,只會在
Reflect上配置
35
36
進階函式控制
• func.apply(self, args)這類呼叫,
隱含地假設func實例本身沒有定義
apply()方法
• 若想不想發生同名問題,方式之一是使用
Function.prototype.apply.apply(
func, [self, args])
37
• ES6以後,可以使用Reflect.apply()來
達到相同目的
• Reflect.apply(func, self, args)
38
• 定義取值函式或設值函式,如果想控制
this的對象呢?
39
• ES6以後,可以使用Reflect.get()或
Reflect.set()
40
• Reflect.get()或Reflect.set()存取
的是[[GET]]、[[SET]]內部方法
• 純綷用來當成是存取特性值也是可行的
41
運算子的對應函式
• in、delete、new運算子使用到內部方法
• 對應函式Reflect.has()、
Reflect.deleteProperty()、
Reflect.construct()
42
• 非嚴格模式下,對於不可組態的特性,
delete刪除失敗會傳回false,若是嚴格
模式,刪除失敗會引發TypeError
• Reflect.deleteProperty() 成功的
話會傳回true,刪除失敗會傳回false
43
• 在建構物件時會使用new運算子,
Reflect.construct()是對應的函式
44
• 可以指定建構式中new.target的實際建
構式或類別
45
• new.target代表建構式,建構式的
prototype,會成為實例的原型
46
Proxy API
• 希望能在存取物件特性時進行
console.log(),記錄有哪些特性被存取了?
• Proxy實例會捕捉(Trap)並呼叫處理器上
定義的對應方法
47
48
代理模式
• Reflect的函式,與Proxy處理器可設定
的捕捉方法是一對一對應的
• Proxy實例可捕捉內部方法被操作的時機,
在處理器中Reflect用來存取內部方法
49
• 實作上提供代理物件給客戶端操作,代理
物件具有與目標物件相同介面
• 在客戶端對實作毫不知情下,不會意識到
正在操作的是代理物件
• 代理物件可以單純地將任務轉發給目標物
件,或者是在這前後附加額外的邏輯
50
• 明顯地被違反物件既有的協定,試圖實作
代理會拋出TypeError
51
52
this又是誰?
53
54
55
56
57
• 想要有個可撤消的(Revocable)的Proxy
實例,可使用Proxy.revocable()函式
58

More Related Content

What's hot

Java SE 7 技術手冊投影片第 16 章 - 自訂泛型、列舉與標註
Java SE 7 技術手冊投影片第 16 章 - 自訂泛型、列舉與標註Java SE 7 技術手冊投影片第 16 章 - 自訂泛型、列舉與標註
Java SE 7 技術手冊投影片第 16 章 - 自訂泛型、列舉與標註
Justin Lin
 
Java SE 7 技術手冊投影片第 07 章 - 介面與多型
Java SE 7 技術手冊投影片第 07 章 - 介面與多型Java SE 7 技術手冊投影片第 07 章 - 介面與多型
Java SE 7 技術手冊投影片第 07 章 - 介面與多型
Justin Lin
 
Java SE 7 技術手冊投影片第 11 章 - 執行緒與並行API
Java SE 7 技術手冊投影片第 11 章 - 執行緒與並行APIJava SE 7 技術手冊投影片第 11 章 - 執行緒與並行API
Java SE 7 技術手冊投影片第 11 章 - 執行緒與並行API
Justin Lin
 

What's hot (20)

10. 資料永續與交換
10. 資料永續與交換10. 資料永續與交換
10. 資料永續與交換
 
並行、平行與非同步
並行、平行與非同步並行、平行與非同步
並行、平行與非同步
 
並行與平行
並行與平行並行與平行
並行與平行
 
Java SE 8 技術手冊第 5 章 - 物件封裝
Java SE 8 技術手冊第 5 章 - 物件封裝Java SE 8 技術手冊第 5 章 - 物件封裝
Java SE 8 技術手冊第 5 章 - 物件封裝
 
Java Tutorial:Learn Java in 06:00:00
Java Tutorial:Learn Java in 06:00:00Java Tutorial:Learn Java in 06:00:00
Java Tutorial:Learn Java in 06:00:00
 
自訂泛型、列舉與標註
自訂泛型、列舉與標註自訂泛型、列舉與標註
自訂泛型、列舉與標註
 
CH11:執行緒與並行API
CH11:執行緒與並行APICH11:執行緒與並行API
CH11:執行緒與並行API
 
Java SE 7 技術手冊投影片第 16 章 - 自訂泛型、列舉與標註
Java SE 7 技術手冊投影片第 16 章 - 自訂泛型、列舉與標註Java SE 7 技術手冊投影片第 16 章 - 自訂泛型、列舉與標註
Java SE 7 技術手冊投影片第 16 章 - 自訂泛型、列舉與標註
 
Java SE 8 技術手冊第 18 章 - 自訂泛型、列舉與標註
Java SE 8 技術手冊第 18 章 - 自訂泛型、列舉與標註Java SE 8 技術手冊第 18 章 - 自訂泛型、列舉與標註
Java SE 8 技術手冊第 18 章 - 自訂泛型、列舉與標註
 
CH10:輸入輸出
CH10:輸入輸出CH10:輸入輸出
CH10:輸入輸出
 
Ch02 撰寫與設定Servlet
Ch02 撰寫與設定ServletCh02 撰寫與設定Servlet
Ch02 撰寫與設定Servlet
 
資料永續與交換
資料永續與交換資料永續與交換
資料永續與交換
 
流程語法與函式
流程語法與函式流程語法與函式
流程語法與函式
 
Java SE 7 技術手冊投影片第 05 章 - 物件封裝
Java SE 7 技術手冊投影片第 05 章  - 物件封裝Java SE 7 技術手冊投影片第 05 章  - 物件封裝
Java SE 7 技術手冊投影片第 05 章 - 物件封裝
 
Ch08 自訂標籤
Ch08 自訂標籤Ch08 自訂標籤
Ch08 自訂標籤
 
Ch13 整合 Spring MVC/Security
Ch13 整合 Spring MVC/SecurityCh13 整合 Spring MVC/Security
Ch13 整合 Spring MVC/Security
 
Java SE 7 技術手冊投影片第 07 章 - 介面與多型
Java SE 7 技術手冊投影片第 07 章 - 介面與多型Java SE 7 技術手冊投影片第 07 章 - 介面與多型
Java SE 7 技術手冊投影片第 07 章 - 介面與多型
 
Java SE 7 技術手冊投影片第 11 章 - 執行緒與並行API
Java SE 7 技術手冊投影片第 11 章 - 執行緒與並行APIJava SE 7 技術手冊投影片第 11 章 - 執行緒與並行API
Java SE 7 技術手冊投影片第 11 章 - 執行緒與並行API
 
CH19:深入模組化
CH19:深入模組化CH19:深入模組化
CH19:深入模組化
 
CH16:整合資料庫
CH16:整合資料庫CH16:整合資料庫
CH16:整合資料庫
 

Similar to 9. meta-programming

信息系统开发平台OpenExpressApp
信息系统开发平台OpenExpressApp信息系统开发平台OpenExpressApp
信息系统开发平台OpenExpressApp
zhoujg
 
全文搜尋引擎的進階實作與應用
全文搜尋引擎的進階實作與應用全文搜尋引擎的進階實作與應用
全文搜尋引擎的進階實作與應用
建興 王
 
美团前端架构简介
美团前端架构简介美团前端架构简介
美团前端架构简介
pan weizeng
 
Django敏捷开发 刘天斯
Django敏捷开发 刘天斯Django敏捷开发 刘天斯
Django敏捷开发 刘天斯
liuts
 
高级PHP应用程序漏洞审核技术
高级PHP应用程序漏洞审核技术高级PHP应用程序漏洞审核技术
高级PHP应用程序漏洞审核技术
wensheng wei
 

Similar to 9. meta-programming (20)

Introduction the Repository Pattern
Introduction the Repository PatternIntroduction the Repository Pattern
Introduction the Repository Pattern
 
Chapter 4 models
Chapter 4 modelsChapter 4 models
Chapter 4 models
 
Hibernate教程
Hibernate教程Hibernate教程
Hibernate教程
 
kotlin-big-nerd-ranch ch4 function
kotlin-big-nerd-ranch ch4 functionkotlin-big-nerd-ranch ch4 function
kotlin-big-nerd-ranch ch4 function
 
Javascript进阶编程
Javascript进阶编程Javascript进阶编程
Javascript进阶编程
 
A brief introduction to Machine Learning
A brief introduction to Machine LearningA brief introduction to Machine Learning
A brief introduction to Machine Learning
 
Code guidelines
Code guidelinesCode guidelines
Code guidelines
 
信息系统开发平台OpenExpressApp
信息系统开发平台OpenExpressApp信息系统开发平台OpenExpressApp
信息系统开发平台OpenExpressApp
 
2012/05/23 AU Talk - 讓事情發生
2012/05/23 AU Talk - 讓事情發生2012/05/23 AU Talk - 讓事情發生
2012/05/23 AU Talk - 讓事情發生
 
運用MMLSpark 來加速Spark 上 機器學習專案
運用MMLSpark 來加速Spark 上機器學習專案運用MMLSpark 來加速Spark 上機器學習專案
運用MMLSpark 來加速Spark 上 機器學習專案
 
Reactive application with akka.NET & .NET Core
Reactive application with akka.NET & .NET CoreReactive application with akka.NET & .NET Core
Reactive application with akka.NET & .NET Core
 
全文搜尋引擎的進階實作與應用
全文搜尋引擎的進階實作與應用全文搜尋引擎的進階實作與應用
全文搜尋引擎的進階實作與應用
 
开源应用日志收集系统
开源应用日志收集系统开源应用日志收集系统
开源应用日志收集系统
 
Spark tutorial
Spark tutorialSpark tutorial
Spark tutorial
 
Model 設定與 Seeding
Model 設定與 SeedingModel 設定與 Seeding
Model 設定與 Seeding
 
美团前端架构简介
美团前端架构简介美团前端架构简介
美团前端架构简介
 
Model 設定與 Seeding
Model 設定與 SeedingModel 設定與 Seeding
Model 設定與 Seeding
 
Django敏捷开发 刘天斯
Django敏捷开发 刘天斯Django敏捷开发 刘天斯
Django敏捷开发 刘天斯
 
高级PHP应用程序漏洞审核技术
高级PHP应用程序漏洞审核技术高级PHP应用程序漏洞审核技术
高级PHP应用程序漏洞审核技术
 
Postgre sql intro 0
Postgre sql intro 0Postgre sql intro 0
Postgre sql intro 0
 

More from Justin Lin

More from Justin Lin (20)

Ch14 簡介 Spring Boot
Ch14 簡介 Spring BootCh14 簡介 Spring Boot
Ch14 簡介 Spring Boot
 
Ch12 Spring 起步走
Ch12 Spring 起步走Ch12 Spring 起步走
Ch12 Spring 起步走
 
Ch11 簡介 JavaMail
Ch11 簡介 JavaMailCh11 簡介 JavaMail
Ch11 簡介 JavaMail
 
Ch10 Web 容器安全管理
Ch10 Web 容器安全管理Ch10 Web 容器安全管理
Ch10 Web 容器安全管理
 
Ch09 整合資料庫
Ch09 整合資料庫Ch09 整合資料庫
Ch09 整合資料庫
 
Ch07 使用 JSTL
Ch07 使用 JSTLCh07 使用 JSTL
Ch07 使用 JSTL
 
Ch06 使用 JSP
Ch06 使用 JSPCh06 使用 JSP
Ch06 使用 JSP
 
Ch05 Servlet 進階 API、過濾器與傾聽器
Ch05 Servlet 進階 API、過濾器與傾聽器Ch05 Servlet 進階 API、過濾器與傾聽器
Ch05 Servlet 進階 API、過濾器與傾聽器
 
Ch04 會話管理
Ch04 會話管理Ch04 會話管理
Ch04 會話管理
 
Ch03 請求與回應
Ch03 請求與回應Ch03 請求與回應
Ch03 請求與回應
 
Ch02 撰寫與設定 Servlet
Ch02 撰寫與設定 ServletCh02 撰寫與設定 Servlet
Ch02 撰寫與設定 Servlet
 
CH1. 簡介 Web 應用程式
CH1. 簡介 Web 應用程式CH1. 簡介 Web 應用程式
CH1. 簡介 Web 應用程式
 
14. 進階主題
14. 進階主題14. 進階主題
14. 進階主題
 
13.並行、平行與非同步
13.並行、平行與非同步13.並行、平行與非同步
13.並行、平行與非同步
 
12. 除錯、測試與效能
12. 除錯、測試與效能12. 除錯、測試與效能
12. 除錯、測試與效能
 
11. 常用內建模組
11. 常用內建模組11. 常用內建模組
11. 常用內建模組
 
9. 資料結構
9. 資料結構9. 資料結構
9. 資料結構
 
8. open() 與 io 模組
8. open() 與 io 模組8. open() 與 io 模組
8. open() 與 io 模組
 
7. 例外處理
7. 例外處理7. 例外處理
7. 例外處理
 
6. 類別的繼承
6. 類別的繼承6. 類別的繼承
6. 類別的繼承
 

9. meta-programming