[1]屬性查詢 [2]屬性設置 [3]屬性刪除 [4]屬性繼承 ...
×
目錄
[1]查詢 [2]設置 [3]刪除[4]繼承前面的話
對於對象來說,屬性操作是繞不開的話題。類似於“增刪改查”的基本操作,屬性操作分為屬性查詢、屬性設置、屬性刪除,還包括屬性繼承。本文是對象系列的第二篇——屬性操作
屬性查詢
屬性查詢一般有兩種方法,包括點運算符和方括弧運算符
var o = { p: 'Hello World' }; o.p // "Hello World" o['p'] // "Hello World"
[註意]變數中可以存在中文,因為中文相當於字元,與英文字元同樣對待,因此可以寫成person.白或person['白']
var person = { 白 : 1 } person.白;//1 person['白'];//1
【點運算符】
點運算符是很多面向對象語句的通用寫法,由於其比較簡單,所以較方括弧運算符相比,更常用
由於javascript是弱類型語言,在任何對象中都可以創建任意數量的屬性。但當通過點運算符(.)訪問對象的屬性時,屬性名用一個標識符來表示,標識符要符合變數命名規則。標識符必須直接出現在javascript程式中,它們不是數據類型,因此程式無法修改它們
var o = { a:1, 1:2 }; console.log(o.a);//1 //由於變數不可以以數字開頭,所以o.1報錯 console.log(o.1);//Uncaught SyntaxError: missing ) after argument list
【方括弧運算符】
當通過方括弧運算符([])來訪問對象的屬性時,屬性名通過字元串來表示。字元串是javascript的數據類型,在程式運行中可以修改和創建它們
使用方括弧運算符有兩個優點
【1】可以通過變數來訪問屬性
var a = 1; var o = { 1: 10 } o[a];//10
【2】屬性名稱可以為javascript無效標識符
var myObject = { 123:'zero', class:'foo' }; console.log(myObject['123'],myObject['class']);//'zero' 'foo' console.log(myObject.123);//報錯
方括弧中的值若是非字元串類型會使用String()隱式轉換成字元串再輸出;如果是字元串類型,若有引號則原值輸出,否則會被識別為變數,若變數未定義,則報錯
var person = {}; person[0]; //[]中的數字不會報錯,而是自動轉換成字元串 person[a]; //[]中符合變數命名規則的元素會被當成變數,變數未被定義,而報錯 person['']; //[]中的空字元串不會報錯,是實際存在的且可以調用,但不會在控制台右側的集合中顯示 person[undefined];//不會報錯,而是自動轉換成字元串 person[null];//不會報錯,而是自動轉換成字元串 person[true];//不會報錯,而是自動轉換成字元串 person[false];//不會報錯,而是自動轉換成字元串
可計算屬性名
在方括弧運算符內部可以使用表達式
var a = 1; var person = { 3: 'abc' }; person[a + 2];//'abc'
但如果要在對象字面量內部對屬性名使用表達式,則需要使用ES6的可計算屬性名
var a = 1; //Uncaught SyntaxError: Unexpected token + var person = { a + 3: 'abc' };
ES6增加了可計算屬性名,可以在文字中使用[]包裹一個表達式來當作屬性名
var a = 1; var person = { [a + 3]: 'abc' }; person[4];//'abc'
屬性查詢錯誤
【1】查詢一個不存在的屬性不會報錯,而是返回undefined
var person = {}; console.log(person.a);//undefined
【2】如果對象不存在,試圖查詢這個不存在的對象的屬性會報錯
console.log(person.a);//Uncaught ReferenceError: person is not defined
可以利用這一點,來檢查一個全局變數是否被聲明
// 檢查a變數是否被聲明 if (a) {...} // 報錯
//所有全局變數都是window對象的屬性。window.a的含義就是讀取window對象的a屬性,如果該屬性不存在,就返回undefined,並不會報錯 if (window.a) {...} // 不報錯
屬性設置
屬性設置又稱為屬性賦值,與屬性查詢相同,具有點運算符和方括弧運算符這兩種方法
o.p = 'abc';
o['p'] = 'abc';
在給對象設置屬性之前,一般要先檢測對象是否存在
var len = undefined; if(book){ if(book.subtitle){ len = book.subtitle.length; } }
上面代碼可以簡化為
var len = book && book.subtitle && book.subtitle.length;
[註意]關於邏輯與&&運算符的應用移步至此
null.a = 1;//Uncaught TypeError: Cannot set property 'a' of null undefined.a = 1;//Uncaught TypeError: Cannot set property 'a' of undefined
由於string、number和boolean有對應的包裝對象,所以給它們設置屬性不會報錯
'abc'.a = 1;//1 (1).a = 1;//1 true.a = 1;//1
屬性刪除
使用delete運算符可以刪除對象屬性(包括數組元素)
var o = { a : 1 }; console.log(o.a);//1 console.log('a' in o);//true console.log(delete o.a);//true console.log(o.a);//undefined console.log('a' in o);//false
[註意]給對象屬性置null或undefined,並沒有刪除該屬性
var o = { a : 1 }; o.a = undefined; console.log(o.a);//undefined console.log('a' in o);//true console.log(delete o.a);//true console.log(o.a);//undefined console.log('a' in o);//false
使用delete刪除數組元素時,不會改變數組長度
var a = [1,2,3]; delete a[2]; 2 in a;//false a.length;//3
delete運算符只能刪除自有屬性,不能刪除繼承屬性(要刪除繼承屬性必須從定義這個屬性的原型對象上刪除它,而且這會影響到所有繼承自這個原型的對象)
var o = { a:1 } var obj = Object.create(o); obj.a = 2; console.log(obj.a);//2 console.log(delete obj.a);//true console.log(obj.a);//1 console.log(delete obj.a);//true console.log(obj.a);//1
返回值
delete操作符的返回值是個布爾值true或false
【1】當使用delete操作符刪除對象屬性或數組元素刪除成功時,返回true
var o = {a:1}; var arr = [1]; console.log(delete o.a);//true console.log(delete arr[0]);//true
【2】當使用delete操作符刪除不存在的屬性或非左值時,返回true
var o = {}; console.log(delete o.a);//true console.log(delete 1);//true console.log(delete {});//true
【3】當使用delete操作符刪除變數時,返回false,嚴格模式下會拋出ReferenceError錯誤
var a = 1; console.log(delete a);//false console.log(a);//1 'use strict'; var a = 1; //Uncaught SyntaxError: Delete of an unqualified identifier in strict mode console.log(delete a);
【4】當使用delete操作符刪除不可配置的屬性時,返回false,嚴格模式下會拋出TypeError錯誤
var obj = {}; Object.defineProperty(obj,'a',{configurable:false}); console.log(delete obj.a);//false 'use strict'; var obj = {}; Object.defineProperty(obj,'a',{configurable:false}); //Uncaught TypeError: Cannot delete property 'a' of #<Object> console.log(delete obj.a);
屬性繼承
每一個javascript對象都和另一個對象相關聯。“另一個對象”就是我們熟知的原型,每一個對象都從原型繼承屬性。所有通過對象直接量創建的對象都具有同一個原型對象,並可以通過Object.prototype獲得對原型對象的引用
var obj = {}; console.log(obj.__proto__ === Object.prototype);//true
[註意]Object.prototype的原型對象是null,所以它不繼承任何屬性
console.log(Object.prototype.__proto__ === null);//true
對象本身具有的屬性叫自有屬性(own property),從原型對象繼承而來的屬性叫繼承屬性
var o = {a:1}; var obj = Object.create(o); obj.b = 2; //繼承自原型對象o的屬性a console.log(obj.a);//1 //自有屬性b console.log(obj.b);//2
in
in操作符可以判斷屬性在不在該對象上,但無法區別自有還是繼承屬性
var o = {a:1}; var obj = Object.create(o); obj.b = 2; console.log('a' in obj);//true console.log('b' in obj);//true console.log('b' in o);//false
for-in
通過for-in迴圈可以遍歷出該對象中所有的可枚舉的屬性
var o = {a:1}; var obj = Object.create(o); obj.b = 2; for(var i in obj){ console.log(obj[i]);//2 1 }
hasOwnProperty()
通過hasOwnProperty()方法可以確定該屬性是自有屬性還是繼承屬性
var o = {a:1}; var obj = Object.create(o); obj.b = 2; console.log(obj.hasOwnProperty('a'));//false console.log(obj.hasOwnProperty('b'));//true
Object.keys()
Object.keys()方法返回所有可枚舉的自有屬性
var o = {a:1}; var obj = Object.create(o,{ c:{value:3,configurable: false} }); obj.b = 2; console.log(Object.keys(obj));//['b']
Object.getOwnPropertyNames()
與Object.keys()方法不同,Object.getOwnPropertyNames()方法返回所有自有屬性(包括不可枚舉的屬性)
var o = {a:1}; var obj = Object.create(o,{ c:{value:3,configurable: false} }); obj.b = 2; console.log(Object.getOwnPropertyNames(obj));//['c','b']
參考資料
【1】 W3School-Javascript高級教程——對象應用 http://www.w3school.com.cn/js/
【2】 阮一峰Javascript標準參考教程——對象 http://javascript.ruanyifeng.com/grammar/object.html
【3】《javascript權威指南(第6版)》第6章 對象
【4】《javascript高級程式設計(第3版)》第6章 面向對象的程式設計
【5】《javascript語句精粹》第3章 對象
【6】《javascript面向對象精要》 第3章 理解對象
【7】《你不知道的javascript上捲》第3章 對象
【8】《ECMAScript6入門》 第7章 對象的擴展