屬性查詢 屬性查詢一般有兩種方法,包括點運算符和方括號運算符: var o = { p: 'Hello World' }; o.p // "Hello World" o['p'] // "Hello World" 1➢ 點運算 點運算符是很多面向對象語句的通用寫法,由於其比較簡單,所以較方括號運算符相比,更常用。 當通過點運算符訪問對象的屬性時,屬性名用一個標識符來表示,標識符必須要符合變量命名規則。 標識符必須直接出現在javascript程序中,它們不是數據類型,因此程序無法修改它們。 var o = { a:1, 1:2 }; console.log(o.a);//1 //由於變量不可以以數字開頭,所以o.1報錯 console.log(o.1);//Uncaught SyntaxError: missing ) after argument list 2➢ 方括號運算 當通過方括號運算符來訪問對象的屬性時,屬性名最終通過字符串來表示。字符串是javascript的數據類型,在程序運行中可以修改和創建它們。 使用方括號運算符有兩個優點。 【一】可以通過變量來訪問屬性 var a = 1; var o = { 1: 10 } o[a];//10 【二】屬性名稱可以為 javascript無效標識符(即,不符合變量命名規則) var myObject = { 123:'zero', class:'foo' }; console.log(myObject['123'],myObject['class']);//'zero' 'foo' console.log(myObject.123);//報錯 2.1➢ 判斷調用String()隱式轉換 【1】方括號中的值若是 字符串類型(外面有引號),就會正常按字符串訪問對象的屬性; 【2】方括號中的值若是 非字符串類型(外面沒有引號),就會先判斷是否符合變量命名規則, 【2-1】如果不符合,就會底層調用String()隱式轉換成字符串再交由方括號運算; 【2-2】如果符合,就是變量了,被當作通過變量來訪問屬性的情況(這個時候,如果對應變量沒有定義,當然就會報錯)。 2.1.1➢ 看demo我們就很容易理解: var myObject = { 123:'this is 123', clasz:'this is clasz' }; console.log(myObject["123"]) // 正常訪問'this is 123' console.log(myObject["clasz"]) // 正常訪問'this is clasz' console.log(myObject[123]) // 123隱式轉換成字符串"123",訪問得到'this is 123' console.log(myObject[clasz]) // clasz符合變量命名規則,被當作變量:Error: clasz is not defined 2.1.2➢ 再細看【2-2】: var myObject = { 123:'this is 123', clasz:'this is clasz', extra: 'this is 補充' }; console.log(myObject[clasz]) // clasz符合變量命名規則,被當作變量:Error: clasz is not defined 對比: var myObject = { 123:'this is 123', clasz:'this is clasz', extra: 'this is 補充' }; var clasz = "extra" console.log(myObject["clasz"]) // 訪問得到'this is 補充' 現在我們就能理解為什么【2】要這么設置了。 2.2➢ 可計算屬性名 在方括號運算符內部可以使用表達式: 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' 3➢ 屬性查詢錯誤 【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) {...} // 不報錯 屬性設置 屬性設置又稱為屬性賦值,與屬性查詢相同,具有點運算符和方括號運算符這兩種方法。 在給對象設置屬性之前,一般要先檢測對象是否存在: var len = undefined; if(book){ if(book.subtitle){ len = book.subtitle.length; } } 上面代碼可以簡化為: var len = book && book.subtitle && book.subtitle.length; 1➢ 屬性設置錯誤 null和undefined不是對象,給它們設置屬性會報錯: 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 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對象都和另一個對象相關聯。“另一個對象”就是我們熟知的原型,每一個對象都從原型繼承屬性。 對象本身具有的屬性叫自有屬性(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 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 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 3➢ 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 } 4➢ 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'] 5➢ 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']