不会Object.defineProperty你就out了
從上面看,貌似使用Object.defineProperty很麻煩,那為啥存在這樣的方法呢?
帶著疑問,我們來看下 Object.defineProperty的定義。
what is Object.defineProperty
The Object.defineProperty() method defines a new property directly on an object, or modifies an exisiting property on an object, and returns the object.
從上面得知,我們可以通過Object.defineProperty這個方法,直接在一個對象上定義一個新的屬性,或者是修改已存在的屬性。最終這個方法會返回該對象。
語法
Object.defineProperty(object, propertyname, descriptor)
參數
- object?必需。 要在其上添加或修改屬性的對象。 這可能是一個本機 JavaScript對象(即用戶定義的對象或內置對象)或 DOM 對象。propertyname?必需。 一個包含屬性名稱的字符串。descriptor?必需。 屬性描述符。 它可以針對數據屬性或訪問器屬性。
屬性的狀態設置
其中descriptor的參數值得我們關注下,該屬性可設置的值有:
- 【value】 屬性的值,默認為 undefined。【writable】 該屬性是否可寫,如果設置成 false,則任何對該屬性改寫的操作都無效(但不會報錯),對于像前面例子中直接在對象上定義的屬性,這個屬性該特性默認值為為 true。
- 【configurable]】如果為false,則任何嘗試刪除目標屬性或修改屬性以下特性(writable, configurable, enumerable)的行為將被無效化,對于像前面例子中直接在對象上定義的屬性,這個屬性該特性默認值為為 true。 。
- 【enumerable】 是否能在for-in循環中遍歷出來或在Object.keys中列舉出來。對于像前面例子中直接在對象上定義的屬性,這個屬性該特性默認值為為 true。
注意?在調用Object.defineProperty()方法時,如果不指定, configurable, enumerable, writable特性的默認值都是false,這跟之前所 說的對于像前面例子中直接在對象上定義的屬性,這個特性默認值為為 true。并不沖突,如下代碼所示:
//調用Object.defineProperty()方法時,如果不指定 var someOne = { }; someOne.name = 'coverguo'; console.log(Object.getOwnPropertyDescriptor(someOne, 'name')); //輸出 Object {value: "coverguo", writable: true, enumerable: true, configurable: true}//直接在對象上定義的屬性,這個特性默認值為為 true var otherOne = {}; Object.defineProperty(otherOne, "name", {value:"coverguo" }); console.log(Object.getOwnPropertyDescriptor(otherOne, 'name')); //輸出 Object {value: "coverguo", writable: false, enumerable: false, configurable: false}- 【get】一旦目標對象訪問該屬性,就會調用這個方法,并返回結果。默認為 undefined。【set】 一旦目標對象設置該屬性,就會調用這個方法。默認為 undefined。
從上面,可以得知,我們可以通過使用Object.defineProperty,來定義和控制一些特殊的屬性,如屬性是否可讀,屬性是否可枚舉,甚至修改屬性的修改器(setter)和獲取器(getter)
那什么場景和地方適合使用到特殊的屬性呢?
實際運用
在一些框架,如vue、express、qjs等,經常會看到對Object.defineProperty的使用。那這些框架是如何使用呢?
MVVM中數據‘雙向綁定’實現
如vue,qjs等大部分mvvm框架(angular用的是臟處理)都是通過Object.defineProperty來實現數據綁定的 為了更詳細的說明,我將在下一篇文章跟大家講解下。下面篇幅先不展開。(別扔磚。。。)
優化對象獲取和修改屬性方式
這個優化對象獲取和修改屬性方式,是什么意思呢? 過去我們在設置dom節點transform時是這樣的。
//加入有一個目標節點, 我們想設置其位移時是這樣的 var targetDom = document.getElementById('target'); var transformText = 'translateX(' + 10 + 'px)'; targetDom.style.webkitTransform = transformText; targetDom.style.transform = transformText;通過上面,可以看到如果頁面是需要許多動畫時,我們這樣編寫transform屬性是十分蛋疼的。(┬_┬)
但如果通過Object.defineProperty, 我們則可以
//這里只是簡單設置下translateX的屬性,其他如scale等屬性可自己去嘗試Object.defineProperty(dom, 'translateX', { set: function(value) {var transformText = 'translateX(' + value + 'px)';dom.style.webkitTransform = transformText;dom.style.transform = transformText; } //這樣再后面調用的時候, 十分簡單 dom.translateX = 10; dom.translateX = -10; //甚至可以拓展設置如scale, originX, translateZ,等各個屬性,達到下面的效果 dom.scale = 1.5; //放大1.5倍 dom.originX = 5; //設置中心點X }上面只是個簡單的版本,并不是最合理的寫法,但主要是為了說明具體的意圖和方法
有興趣了解更多可以看下面這個庫:https://github.com/AlloyTeam/AlloyTouch/blob/master/transform.js
增加屬性獲取和修改時的信息
如在Express4.0中,該版本去除了一些舊版本的中間件,為了讓用戶能夠更好地發現,其有下面這段代碼,通過修改get屬性方法,讓用戶調用廢棄屬性時拋錯并帶上自定義的錯誤信息。
['json','urlencoded','bodyParser','compress','cookieSession','session','logger','cookieParser','favicon','responseTime','errorHandler','timeout','methodOverride','vhost','csrf','directory','limit','multipart','staticCache', ].forEach(function (name) {Object.defineProperty(exports, name, {get: function () {throw new Error('Most middleware (like ' + name + ') is no longer bundled with Express and must be installed separately. Please see https://github.com/senchalabs/connect#middleware.');},configurable: true}); });其他如設置常量等用途。。。
兼容
?
最后注意下,Object.defineProperty是ES5的屬性,大部分場景使用是沒問題的, 但在一些場景如IE8以下是使用不到的哈。轉載于:https://www.cnblogs.com/mjian/p/9250085.html
總結
以上是生活随笔為你收集整理的不会Object.defineProperty你就out了的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: PHP FTP函数
- 下一篇: Hadoop配置学习