輕鬆學習 JavaScript——第 7 部分:物件屬性描述符
本文由碼農網 – 小峰原創翻譯,轉載請看清文末的轉載要求,歡迎參與我們的付費投稿計劃!
在JavaScript中,你可以如下所示建立一個物件字面量:
var cat = { name: 'foo', age: 9 };
乍一看,好像物件cat有字串和數字值這兩個屬性。然而,這不僅僅是JavaScript直譯器。在ES5中,介紹了屬性描述符的概念。在我們繼續討論屬性描述符之前,讓我們試著回答幾個問題:
- 如何建立只讀屬性?
- 如何制定不可列舉的屬性?
- 如何使屬性不可配置?
- 如何確定一個屬性是否是隻讀的?
如果你理解屬性描述符,那麼你就可以回答所有這些問題。
請看下面的程式碼:
var cat = { name: 'foo', age: 9 }; var a = Object.getOwnPropertyDescriptor(cat, 'name'); console.log(a);
輸出將如下所示:
正如你在這裡看到的,這個屬性有四個特徵:
value儲存屬性的資料,而writable,enumerable和configurable則描述屬性的其他特徵。接下來我們將對這些特徵一一闡述。
writable
屬性的值是否可以更改是由writable特徵決定的。如果writable設定為false,那麼屬性的值不能更改,JavaScript將忽略屬性值中的任何更改。請看下面的程式碼:
var cat = { name: 'foo', age: 9 }; Object.defineProperty(cat, 'name', { writable: false }); console.log(cat.name); // foo cat.name = "koo"; // JavaScript will ignore it as writable is set to false console.log(cat.name); // foo
你可以使用Object.defineProperty更改writable、enumerable和configurable特徵的值。我們稍後會在這篇文章中詳細討論Object.defineProperty,但正如你在上面的程式碼片段中看到的那樣,我們已經將writable屬性設定為false,從而改變了name屬性的值。JavaScript將忽略重新分配,並且name屬性的值將保持為foo。
如果以嚴格模式執行程式碼,那麼為了重新分配writable設定為false的屬性值,JavaScript將丟擲異常。請看下面的程式碼:
'use strict'; var cat = { name: 'foo', age: 9 }; Object.defineProperty(cat, 'name', { writable: false }); console.log(cat.name); // foo cat.name = "koo"; // error
在這裡,JavaScript以嚴格模式執行,因此,當你重新分配name屬性的值時,JavaScript將丟擲異常,如下所示:
這裡的錯誤訊息說,你不能賦值到只讀屬性。也就是說,如果屬性的writable特徵設定為false,那麼屬性將充當只讀屬性。
configurable
屬性的其他特徵是否可以配置取決於configurable的值。如果屬性configurable設定為false,則不能更改writable和enumerable的值。請看下面的程式碼:
var cat = { name: 'foo', age: 9 }; Object.defineProperty(cat, 'name', { configurable: false }); Object.defineProperty(cat, 'name', { enumerable: false });
在這裡,我們將name屬性的configurable設定為false。之後,我們將enumerable設定為false。如前所述,一旦一個屬性的configurable設定為false,那麼你就不能改變另一個特徵。
對於上面的程式碼,JavaScript會丟擲一個TypeError異常,如下圖所示。你會得到無法重新定義屬性名稱的錯誤:
在使用configurable的時候,你需要記住,改變configurable的值只能做一次。如果將屬性的configurable設定為false,那麼你就不能重新分配它;你無法撤消對configurable的更改。請看下面的程式碼:
var cat = { name: 'foo', age: 9 }; Object.defineProperty(cat, 'name', { configurable: false }); Object.defineProperty(cat, 'name', { configurable: true });
我們在重新分配name屬性的configurable,但是,JavaScript會對上述操作丟擲一個TypeError,如下圖所示。正如你所看到的,一旦configurable被設定為false,就不能撤銷那個更改。
另一個重要的事情是,即使configurable設定為false,writable也可以從true更改為false——但反之則不然。請看下面的程式碼:
var cat = { name: 'foo', age: 9 }; Object.defineProperty(cat, 'name', { configurable: false }); Object.defineProperty(cat, 'name', { writable: false }); cat.name = 'koo'; console.log(cat.name); // foo
如果不是在嚴格模式下,上面的程式碼不會丟擲任何異常。正如我們前面所討論的,即使configurable為false,writable也可以從true變為false,反之則不然。另一個需要牢記的重要事項是,你無法刪除configurable設定為false的屬性。
var cat = { name: 'foo', age: 9 }; Object.defineProperty(cat, 'name', { configurable: false }); delete cat.name; // wont delete as configurable is false console.log(cat.name); // foo delete (cat.age); // will be deleted console.log(cat.age); // undefined
在上面的程式碼中,你會發現JavaScript不會刪除name屬性,因為name屬性的configurable設定為false。
enumerable
對於一個屬性,如果你設定了enumerable:false,那麼這個屬性將不會出現在列舉中,因此它不能用在諸如for … in迴圈這樣的語句中。
請看下面的程式碼:
var cat = { name: 'foo', age: 9 }; Object.defineProperty(cat, 'name', { enumerable: false }); for (let f in cat) { console.log(f); // will print only age }
在這裡,你只能得到age,因為name的enumerable被設定為了false。這是另一個需要記住的重要事項:通過設定enumerable:false,唯一的屬性將不可用於列舉。我們來看下面的程式碼:
var cat = { name: 'foo', age: 9 }; Object.defineProperty(cat, 'name', { enumerable: false }); console.log(cat.name); // foo console.log('name' in cat); // true
在這裡,name屬性enumerable設定為false,但你可以訪問它。在檢查name是否屬於cat的屬性時,你也會發現是true。
有時,你可能需要檢查某個特定屬性enumerable是否設定為false或true。你可以通過使用propertyIsEnumerable方法來做到這一點:
var cat = { name: 'foo', age: 9 }; Object.defineProperty(cat, 'name', { enumerable: false }); console.log(cat.propertyIsEnumerable("name")); // false
結論
作為一名專業的JavaScript開發人員,你必須對JavaScript物件屬性描述符有一個很好的理解,我希望你能從這篇文章中學到一些知識!請繼續關注我們的下一篇文章,繼續學習JavaScript中更重要的概念。
系列目錄
輕鬆學習 JavaScript——第 1 部分:瞭解 let 語句
輕鬆學習 JavaScript——第 2 部分:函式中的 Rest 引數
輕鬆學習 JavaScript——第 3 部分:函式中的預設引數
輕鬆學習 JavaScript——第 4 部分:函式中的 arguments 物件
輕鬆學習 JavaScript——第 5 部分:簡化函式提升
輕鬆學習 JavaScript——第 6 部分:JavaScript 箭頭函式
輕鬆學習 JavaScript——第 7 部分:物件屬性描述符
輕鬆學習 JavaScript——第 8 部分:JavaScript 中的類
譯文連結:http://www.codeceo.com/article/easy-javascript-07-object-property-descriptors.html
英文原文:Easy JavaScript Part 7 : Object Property Descriptors
翻譯作者:碼農網 – 小峰
[ 轉載必須在正文中標註並保留原文連結、譯文連結和譯者等資訊。]
相關文章
- 輕鬆學習 JavaScript(7):物件屬性描述符JavaScript物件
- 輕鬆學習 JavaScript——第 4 部分:函式中的 arguments 物件JavaScript函式物件
- 輕鬆學習 JavaScript——第 8 部分:JavaScript 中的類JavaScript
- 輕鬆學習 JavaScript——第 6 部分:JavaScript 箭頭函式JavaScript函式
- 輕鬆學習 JavaScript——第 1 部分:瞭解 let 語句JavaScript
- 輕鬆學習 JavaScript——第 5 部分:簡化函式提升JavaScript函式
- 輕鬆學習 JavaScript——第 2 部分:函式中的 Rest 引數JavaScript函式REST
- 輕鬆學習 JavaScript——第 3 部分:函式中的預設引數JavaScript函式
- 輕鬆學習 JavaScript (4):函式中的 arguments 物件JavaScript函式物件
- 怎麼輕鬆學習JavaScriptJavaScript
- JavaScript中的物件學習筆記(屬性操作)JavaScript物件筆記
- 輕鬆學習 JavaScript(8):JavaScript 中的類JavaScript
- 深層屬性,輕鬆提取
- 輕鬆學習 JavaScript(6):JavaScript 箭頭函式JavaScript函式
- javascript屬性描述符詳細介紹JavaScript
- 輕鬆學習 JavaScript(1):瞭解 let 語句JavaScript
- 輕鬆學習 JavaScript(5):簡化函式提升JavaScript函式
- 理解 JavaScript 物件的屬性JavaScript物件
- javascript原型物件的屬性不能夠覆蓋物件自有屬性JavaScript原型物件
- (JavaScript學習記錄):jQuery 屬性操作JavaScriptjQuery
- JavaScript ----- 操作DOM物件的屬性JavaScript物件
- JavaScript遍歷物件的屬性JavaScript物件
- JavaScript學習總結(二)陣列和物件部分JavaScript陣列物件
- 讀懂屬性描述符
- 揭秘Java反射:如何輕鬆獲取類的屬性及父類屬性Java反射
- 輕鬆學習 JavaScript (2):函式中的 Rest 引數JavaScript函式REST
- JavaScript學習筆記023-物件方法0包裝物件0靜態屬性JavaScript筆記物件
- 重新認識javascript物件(一)——物件及其屬性JavaScript物件
- JavaScript物件的資料屬性與訪問器屬性JavaScript物件
- JavaScript遍歷物件屬性順序JavaScript物件
- JavaScript刪除和清空物件屬性JavaScript物件
- JavaScript物件屬性是有序的嗎?JavaScript物件
- 輕鬆學習 JavaScript (3):函式中的預設引數JavaScript函式
- javascript獲取物件直接量中的屬性和屬性值JavaScript物件
- JavaScript學習——物件JavaScript物件
- JavaScript訪問物件的屬性和方法JavaScript物件
- 如何輕鬆學習 Kubernetes?
- Java淺複製大揭秘:如何輕鬆複製兩個不同物件的某些相同屬性Java物件