文章出處

前面的話

  對于對象來說,屬性操作是繞不開的話題。類似于“增刪改查”的基本操作,屬性操作分為屬性查詢、屬性設置、屬性刪除,還包括屬性繼承。本文是對象系列的第二篇——屬性操作

 

屬性查詢

  屬性查詢一般有兩種方法,包括點運算符和方括號運算符

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;

  [注意]關于邏輯與&&運算符的應用移步至此

  nullundefined不是對象,給它們設置屬性會報錯

null.a = 1;//Uncaught TypeError: Cannot set property 'a' of null
undefined.a = 1;//Uncaught TypeError: Cannot set property 'a' of undefined

  由于stringnumberboolean有對應的包裝對象,所以給它們設置屬性不會報錯

'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章 對象的擴展


文章列表


不含病毒。www.avast.com
arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()