對象是由多個名/值對組成的無序的集合。對象中每一個屬性對應任意類型的值。
定義對象可使用構造函數或字面量的形式:javascript
var obj = new Object; //obj = {} obj.name = "張三"; //添加描述 obj.say = function(){}; //添加行爲
除了以上添加屬性的方式,還可使用Object.defineProperty定義新屬性或修改原有的屬性。vue
語法:java
Object.defineProperty(obj, prop, descriptor)
參數說明:git
obj:必需。目標對象
prop:必需。需定義或修改的屬性的名字
descriptor:必需。目標屬性所擁有的特性github
返回值:web
傳入函數的對象。即第一個參數objtypescript
針對屬性,咱們能夠給這個屬性設置一些特性,好比是否只讀不能夠寫;是否能夠被for..in或Object.keys()遍歷。express
給對象的屬性添加特性描述,目前提供兩種形式:數據描述和存取器描述。json
Object.defineProperty ,顧名思義,爲對象定義屬性。在js中咱們能夠經過下面這幾種方法定義屬性cookie
// (1) define someOne property name someOne.name = 'cover'; //or use (2) someOne['name'] = 'cover'; // or use (3) defineProperty Object.defineProperty(someOne, 'name', { value : 'cover' })
從上面看,貌似使用Object.defineProperty很麻煩,那爲啥存在這樣的方法呢?
帶着疑問,咱們來看下 Object.defineProperty的定義。
var someOne = { }; Object.defineProperty(someOne, "name", { value:"coverguo" , //因爲設定了writable屬性爲false 致使這個量不能夠修改 writable: false }); console.log(someOne.name); // 輸出 coverguo someOne.name = "linkzhu"; console.log(someOne.name); // 輸出coverguo
var someOne = { }; Object.defineProperty(someOne, "name", { value:"coverguo" , configurable: false }); delete someOne.name; console.log(someOne.name);// 輸出 coverguo someOne.name = "linkzhu"; console.log(someOne.name); // 輸出coverguo
注意 在調用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}
從上面,能夠得知,咱們能夠經過使用Object.defineProperty,來定義和控制一些特殊的屬性,如屬性是否可讀,屬性是否可枚舉,甚至修改屬性的修改器(setter)和獲取器(getter)
那什麼場景和地方適合使用到特殊的屬性呢?
在一些框架,如vue、express、qjs等,常常會看到對Object.defineProperty的使用。那這些框架是如何使用呢?
如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如下是使用不到的哈。
在ie8下只能在DOM對象上使用,嘗試在原生的對象使用 Object.defineProperty()會報錯