目錄
- 第二章 - 03: 前端 進階技巧之高階函數
- 一、防篡改對象
- 1-1:Configurable 和 Writable
- 1-2:Enumerable
- 1-3:get 、set
- 2-1:不可擴充項物件
- 2-2:密封的對象
- 2-3:凍結的對象
- 二、自訂事件
第二章 - 03: 前端 進階技巧之高階函數一、防篡改對象
JavaScript共用的本質一直是開發人員心頭的痛,因為任何對象都可以被在同一個環境中啟動並執行代碼修改。
ECMAScript5致力於解決這個問題,可以讓開發人員定義防篡改對象
(tamper-proof object)。它的原理就是
通過設定每個對象的屬性的一下的預設屬性:
- [[Configurable]] --- 是否可配置
- [[Writable]] --- 是否可以重新賦值
- [[Enumerable]] --- 是否可列舉的
- [[Value]] --- 預設值
- [[Get]]
- [[Set]]
1-1:Configurable 和 Writable
下面我們就針對以上每一個屬性進行 解析一下:
// Demo onevar o = {}Object.defineProperty(o, 'name', { value: 'zhang', configurable: false})console.log(o)Object.defineProperty(o, 'name', { writable: false})o.name = 'Li'console.log(o) // {name: 'zhange'} 屬性未被改變
上面的 Demo 中 我們將 configurable 屬性設定成為 false, 再對比下面的 Demo 來看 configurable 屬性作用
// Demo twovar o = {}Object.defineProperty(o, 'name', { value: 'zhang', configurable: false})console.log(o)Object.defineProperty(o, 'name', { writable: true})o.name = 'Li' // Uncaught TypeError: Cannot redefine property: name 報錯
總結: 當 [[Configurable]] 為 fasle 的時候 [[Writable]] 預設已經被設定 false, 如果去修改 [[Writable]] 的時候
則會報錯。 那麼我們就可以理解為 當 [[Configurable]] 為 false 的時候, [[Writable]] 是只能為 false的。
1-2:Enumerable
我們還是用 Demo 來進行對比解釋:
var o = {}Object.defineProperty(o, 'age', { enumerable: true, value: 18})for(item in o) { console.log(item, o[item]) // age 18}
把 enumerable 設定成 false
var o = {}Object.defineProperty(o, 'age', { enumerable: false, value: 19})for(item in o) { console.log(item, o[item]) // undefined}
1-3:get 、set
get 和 set 這對雙胞胎我們已經說過多次了。這次我們仔細來看下這個~
var o = {}var v = 'coder'Object.defineProperty(o, 'job', { get: function() { console.log('get:', v) return v }, set: function(newV) { console.log('set:', newV) v = newV }})o.job = 'xxx' // set: xxx// 很奇怪的一點就是 當我們在 瀏覽器控制台點開 o 對象的時候,再次去點擊 job 屬性,就會觸發 get 方法。
2-1:不可擴充項物件
Object.preventExtensions(o)
可以使得 不能再給對象添加屬性和方法
var o = {name: 'zhang'}Object.preventExtensions(o)o.age = '12'console.log(o) // {name: 'zhang'}// 已經阻止了給對象添加屬性和方法了。再去添加 也未能添加上
Object.isExtensible(o)
確定對象是否可以擴充
var o = {name: 'zhang'}var res1 = Object.isExtensible(o)Object.preventExtensions(o)var res2 = Object.isExtensible(o)console.log(res1, res2) // true false
2-2:密封的對象
Object.seal(o)
密封對象不可擴充,而且已有成員的[[Configurable]]特性被設定為false,意味著不能刪除屬性和方法。不可增加,不能刪除。
var o = {name: 'Li'}Object.isSealed(o) // falseObject.seal(o)Object.isSealed(o) // true
Object.isSealed(o)
檢測時候被密封了( )
2-3:凍結的對象
Object.freeze(o)
最嚴格的防篡改層級就是凍結對象(frozen object)。凍結的對象不能擴充,又是密封的,而且對象屬性的[[Writable]]特性會被設定為false。
如果定義了[[Set]]函數,訪問器屬性仍然是可寫的。
var obj = {age: 123}Object.freeze(obj)Object.isFrozen(obj) // trueObject.isSealed(obj) // trueObject.isExtensible(obj) // false
Object.isFrozen(o)
檢查是否被凍結
二、自訂事件
基於 觀察者模式
的一種建立鬆散耦合代碼的技術。使用自訂事件有助於解耦相關對象,保持功能的隔絕。
function EventTarget(){ this.handlers = {};}EventTarget.prototype = { constructor : EventTraget, addHandler : function(type,handler){ if(typeof this.handlers[type] === 'undefined'){ this.handlers[type] = []; } this.handlers[type].push(handler); }, fire : function(event){ if(!event.target){ event.target = this; } if(this.handlers[type] instanceof Array){ var handlers = this.handlers[event.type]; for(var i = 0,len = handlers.length; i < len; i++){ handlers[i](event);//執行回呼函數 } } }, removeHandler : function(type,handler){ if(this.handlers[type] instanceof Array){ var handlers = this.handlers[type]; for(var i = 0,len = handlers.length; i < len; i++){ if(handlers[i] === handler){ break; } } handlers.splice(i,1);//刪除 } }}
總結: 以上則為高階函數中的相關的一些情境的應用,但是這也僅僅是屬於基礎部分,實際的使用情境還需要大家自己靈活處理。
好了,本期這篇 blog 就先寫到這裡。
GitHub 地址:(歡迎 star 、歡迎推薦 : )
前端 進階技巧之高階函數(下)