摘要:本文是重溫基礎系列文章的第十四篇。元,是指程序本身。有理解不到位,還請指點,具體詳細的介紹,可以查看維基百科元編程。攔截,返回一個布爾值。
本文是 重溫基礎 系列文章的第十四篇。
這是第一個基礎系列的最后一篇,后面會開始復習一些中級的知識了,歡迎持續關注呀!
接下來會統一整理到我的【Cute-JavaScript】的JavaScript基礎系列中。
今日感受:獨樂樂不如眾樂樂。
系列目錄:
【復習資料】ES6/ES7/ES8/ES9資料整理(個人整理)
【重溫基礎】1.語法和數據類型
【重溫基礎】2.流程控制和錯誤處理
【重溫基礎】3.循環和迭代
【重溫基礎】4.函數
【重溫基礎】5.表達式和運算符
【重溫基礎】6.數字
【重溫基礎】7.時間對象
【重溫基礎】8.字符串
【重溫基礎】9.正則表達式
【重溫基礎】10.數組
【重溫基礎】11.Map和Set對象
【重溫基礎】12.使用對象
【重溫基礎】13.迭代器和生成器
本章節復習的是JS中的元編程,涉及的更多的是ES6的新特性。
1. 概述元編程,其實我是這么理解的:讓代碼自動寫代碼,可以更改源碼底層的功能。
元,是指程序本身。
有理解不到位,還請指點,具體詳細的介紹,可以查看維基百科 元編程 。
從ES6開始,JavaScrip添加了對Proxy和Reflect對象的支持,允許我們連接并定義基本語言操作的自定義行為(如屬性查找,賦值,枚舉和函數調用等),從而實現JavaScrip的元級別編程。
Reflect: 用于替換直接調用Object的方法,并不是一個函數對象,也沒有constructor方法,所以不能用new操作符。
Proxy: 用于自定義對象的行為,如修改set和get方法,可以說是ES5中Object.defineProperty()方法的ES6升級版。
兩者聯系: API完全一致,但Reflect一般在Proxy需要處理默認行為的時候使用。
參考資料:
名稱 | 地址 |
---|---|
Reflect | MDN Reflect |
Proxy | MDN Proxy |
元編程 | MDN 元編程 |
本文主要從Proxy介紹,還會有幾個案例,實際看下怎么使用。
2. Proxy介紹proxy 用于修改某些操作的默認行為,可以理解為一種攔截外界對目標對象訪問的一種機制,從而對外界的訪問進行過濾和修改,即代理某些操作,也稱“代理器”。
2.1 基礎使用基本語法:
let p = new Proxy(target, handler);
proxy實例化需要傳入兩個參數,target參數表示所要攔截的目標對象,handler參數也是一個對象,用來定制攔截行為。
let p = new Proxy({}, { get: function (target, handler){ return "leo"; } }) p.name; // leo p.age; // leo p.abcd; // leo
上述a實例中,在第二個參數中定義了get方法,來攔截外界訪問,并且get方法接收兩個參數,分別是目標對象和所要訪問的屬性,所以不管外部訪問對象中任何屬性都會執行get方法返回leo。
注意:
只能使用Proxy實例的對象才能使用這些操作。
如果handler沒有設置攔截,則直接返回原對象。
let target = {}; let handler = {}; let p = new Proxy(target, handler); p.a = "leo"; target.a; // "leo"
同個攔截器函數,設置多個攔截操作:
let p = new Proxy(function(a, b){ return a + b; },{ get:function(){ return "get方法"; }, apply:function(){ return "apply方法"; } })
這里還有一個簡單的案例:
let handler = { get : function (target, name){ return name in target ? target[name] : 16; } } let p = new Proxy ({}, handler); p.a = 1; console.log(p.a , p.b); // 1 16
這里因為 p.a = 1 定義了p中的a屬性,值為1,而沒有定義b屬性,所以p.a會得到1,而p.b會得到undefined從而使用name in target ? target[name] : 16;返回的默認值16;
Proxy支持的13種攔截操作:
13種攔截操作的詳細介紹:打開阮一峰老師的鏈接。
get(target, propKey, receiver):
攔截對象屬性的讀取,比如proxy.foo和proxy["foo"]。
set(target, propKey, value, receiver):
攔截對象屬性的設置,比如proxy.foo = v或proxy["foo"] = v,返回一個布爾值。
has(target, propKey):
攔截propKey in proxy的操作,返回一個布爾值。
deleteProperty(target, propKey):
攔截delete proxy[propKey]的操作,返回一個布爾值。
ownKeys(target):
攔截Object.getOwnPropertyNames(proxy)、Object.getOwnPropertySymbols(proxy)、Object.keys(proxy)、for...in循環,返回一個數組。該方法返回目標對象所有自身的屬性的屬性名,而Object.keys()的返回結果僅包括目標對象自身的可遍歷屬性。
getOwnPropertyDescriptor(target, propKey):
攔截Object.getOwnPropertyDescriptor(proxy, propKey),返回屬性的描述對象。
defineProperty(target, propKey, propDesc):
攔截Object.defineProperty(proxy, propKey, propDesc)、Object.defineProperties(proxy, propDescs),返回一個布爾值。
preventExtensions(target):
攔截Object.preventExtensions(proxy),返回一個布爾值。
getPrototypeOf(target):
攔截Object.getPrototypeOf(proxy),返回一個對象。
isExtensible(target):
攔截Object.isExtensible(proxy),返回一個布爾值。
setPrototypeOf(target, proto):
攔截Object.setPrototypeOf(proxy, proto),返回一個布爾值。如果目標對象是函數,那么還有兩種額外操作可以攔截。
apply(target, object, args):
攔截 Proxy 實例作為函數調用的操作,比如proxy(...args)、proxy.call(object, ...args)、proxy.apply(...)。
construct(target, args):
攔截 Proxy 實例作為構造函數調用的操作,比如new proxy(...args)。
2.2 取消Proxy實例使用Proxy.revocable方法取消Proxy實例。
let a = {}; let b = { get: function(target, name) { return "[[" + name + "]]"; } }; let revoke = Proxy.revocable(a, b); let proxy = revoke.proxy; proxy.age; // "[[age]]" revoke.revoke(); proxy.age; // Uncaught TypeError: Cannot perform "get" on a proxy that has been revoked proxy.age = 10; // Uncaught TypeError: Cannot perform "set" on a proxy that has been revoked delete proxy.age; // Uncaught TypeError: Cannot perform "deleteProperty" on a proxy that has been revoked typeof proxy; // "object"2.3 實現 Web服務的客戶端
const service = createWebService("http://le.com/data"); service.employees().than(json =>{ const employees = JSON.parse(json); }) function createWebService(url){ return new Proxy({}, { get(target, propKey, receiver{ return () => httpGet(url+"/"+propKey); }) }) }3. Proxy實踐 3.1 數據攔截驗證
通過Proxy代理對象的set和get方法來進行攔截數據,像Vue就是用數據攔截來實現數據綁定。
let handler = { // 攔截并處理get方法 // 可以理解為設置get方法返回的默認值 get : function (target, key){ return key in target ? target[key] : 30; }, // 攔截并處理set方法 // 可以理解為設置set方法的默認行為 set : function (target, key, value){ if(key === "age"){ if (!Number.isInteger(value)){ throw new TypeError("age不是一個整數!"); } if (value > 200){ throw new TypeError("age不能大于200!"); } } // 保存默認行為 target[key] = value; } } let p = new Proxy({}, handler); p.a = 10; // p.a => 10 p.b = undefined; // p.b => undefined p.c; // 默認值 30 p.age = 100; // p.age => 100 p.age = 300; // Uncaught TypeError: age不能大于200! p.age = "leo"; // Uncaught TypeError: age不是一個整數!3.2 函數節流
通過攔截handler.apply()方法的調用,實現函數只能在1秒之后才能再次被調用,經常可以用在防止重復事件的觸發。
let p = (fun, time) => { // 獲取最后點擊時間 let last = Date.now() - time; return new Proxy (fun, { apply(target, context, args){ if(Date.now() - last >= time){ fun.bind(target)(args); // 重復設置當前時間 last = Date.now(); } } }) } let p1 = () => { console.log("點擊觸發"); } let time = 1000; // 設置時間 let proxyObj = p(p1, time); // 監聽滾動事件 document.addEventListener("scroll", proxyObj);3.3 實現單例模式
通過攔截construct方法,讓不同實例指向相同的constructer,實現單例模式。
let p = function(fun){ let instance; let handler = { // 攔截construct方法 construct: function(targer, args){ if(!instance){ instance = new fun(); } return instance; } } return new Proxy(fun, handler); } // 創建一個construct案例 function Cons (){ this.value = 0; } // 創建實例 let p1 = new Cons(); let p2 = new Cons(); // 操作 p1.value = 100; // p1.value => 100 , p2.value => 0 // 因為不是相同實例 // 通過Proxy實現單例 let singleton = p(Cons); let p3 = new singleton(); let p4 = new singleton(); p3.value = 130; // p1.value => 130 , p2.value => 130 // 現在是相同實例參考資料
1. MDN 元編程
2. ES6中的元編程-Proxy & Reflect
本部分內容到這結束
Author | 王平安 |
---|---|
pingan8787@qq.com | |
博 客 | www.pingan8787.com |
微 信 | pingan8787 |
每日文章推薦 | https://github.com/pingan8787... |
JS小冊 | js.pingan8787.com |
歡迎關注微信公眾號【前端自習課】每天早晨,與您一起學習一篇優秀的前端技術博文 .
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/100806.html
摘要:構造函數通常首字母大寫,用于區分普通函數。這種關系常被稱為原型鏈,它解釋了為何一個對象會擁有定義在其他對象中的屬性和方法。中所有的對象,都有一個屬性,指向實例對象的構造函數原型由于是個非標準屬性,因此只有和兩個瀏覽器支持,標準方法是。 從這篇文章開始,復習 MDN 中級教程 的內容了,在初級教程中,我和大家分享了一些比較簡單基礎的知識點,并放在我的 【Cute-JavaScript】系...
摘要:通常在轉換不同數據類型時,相等和不相等會遵循以下規則若有一個操作數是布爾值,則比較前會將布爾值轉換為數值轉為,轉為。 本文是 重溫基礎 系列文章的第十八篇。今日感受:優化自己的代碼,也是很愉快的事情。 系列目錄: 【復習資料】ES6/ES7/ES8/ES9資料整理(個人整理) 【重溫基礎】1-14篇 【重溫基礎】15.JS對象介紹 【重溫基礎】16.JSON對象介紹 【重溫基礎...
摘要:系列目錄復習資料資料整理個人整理重溫基礎篇重溫基礎對象介紹本章節復習的是中的關于對象相關知識。概念概念有三點全稱對象表示法。對象沒有分號,而對象有。序列化對象時,所有函數及原型成員都會被忽略,不體現在結果上。 本文是 重溫基礎 系列文章的第十六篇。今日感受:靜。 系列目錄: 【復習資料】ES6/ES7/ES8/ES9資料整理(個人整理) 【重溫基礎】1-14篇 【重溫基礎】15...
摘要:內存泄露內存泄露概念在計算機科學中,內存泄漏指由于疏忽或錯誤造成程序未能釋放已經不再使用的內存。判斷內存泄漏,以字段為準。 本文是 重溫基礎 系列文章的第二十二篇。 今日感受:優化學習方法。 系列目錄: 【復習資料】ES6/ES7/ES8/ES9資料整理(個人整理) 【重溫基礎】1-14篇 【重溫基礎】15.JS對象介紹 【重溫基礎】16.JSON對象介紹 【重溫基礎】1...
摘要:系列目錄復習資料資料整理個人整理重溫基礎篇重溫基礎對象介紹重溫基礎對象介紹重溫基礎介紹重溫基礎相等性判斷本章節復習的是中的關于閉包,這個小哥哥呀,看看。這里隨著閉包函數的結束,執行環境銷毀,變量回收。 本文是 重溫基礎 系列文章的第十九篇。今日感受:將混亂的事情找出之間的聯系,也是種能力。 系列目錄: 【復習資料】ES6/ES7/ES8/ES9資料整理(個人整理) 【重溫基礎】...
閱讀 984·2021-11-24 09:39
閱讀 2185·2021-11-16 11:54
閱讀 2077·2021-11-11 17:22
閱讀 2372·2021-09-30 09:55
閱讀 3591·2021-08-12 13:22
閱讀 1626·2019-08-30 15:44
閱讀 1168·2019-08-29 12:12
閱讀 3263·2019-08-27 10:58