JavaScript 對象(上)
簡述:
1、是 JavaScript 的基本類型
2、是一種復合值,可通過名字訪問這些值
3、可看作屬性的無序集合,每個屬性都是一個名/值對(屬性名是字符串或標識符)
4、可以從一個稱為原型的對象繼承屬性(核心特征)
5、是動態的,可新增或刪除屬性,操作對象是通過引用而不是值
6、屬性名可以是包含空字符在內的任意字符串,但對象中不能存在兩個或多個同名屬性;非嚴格模式下允許,但後者會覆蓋前者的值
註:除了字符串、數字、true、false、null 和 undefined 之外,JavaScript 中的值都是對象
原型:
1、大部分 JavaScript 對象都和另一個對象(原型)相關聯,每個對象都從原型繼承
2、可以通過 JavaScript 代碼 Object.prototype 獲得對其原型對象的引用
3、所有通過對象直接量創建的對象都具有同一個原型對象,使用相同構造函數的對象也具有同一個原型對象
4、所有的內置構造函數(以及大部分自定義的構造函數)都具有一個繼承自 Object.prototype 的原型
5、一個普通對象的原型可能也有原型,而這一系列鏈接的原型對象就是”原型鏈“
創建對象:
1、對象直接量:由若幹名/值對組成的映射表,名/值對中間用冒號分隔,名/值對之間用逗號分隔,整個映射表用花括號括起來
// 對象裏面的屬性值可以是對象let obj = {"name": "Yam", "other": {"weight": "yyy", "high": "xxx"}, "age": 200}; console.log(obj["other"]["high"]); // 輸出 xxx
console.log(obj.other.high);
註:對象直接量是一個表達式,這個表達式的每次運算都創建並初始化一個新的對象
2、關鍵字 new:關鍵字後跟隨一個函數(構造函數)調用,用以初始化一個新創建的對象
let arr = new Array(); // 創建一個空數組 let date = new Date(); //創建一個表示當前時間的 Date 對象
3、Object.create(proto [, more]):創建一個新對象,第一個參數為這個對象的原型,第二個參數可對對象的屬性進行進一步描述
// ES5 定義的 let obj = Object.create({"x": 1, "y": 2}); console.log(obj.x); // 輸出 1
屬性查詢和設置:
// inherit 函數來自 JavaScript 權威指南 function inherit(p) { if (p == null) throw TypeError(); if (Object.create) return Object.create(p); let t = typeof p; if (t != "object" && t != "function") throw TypeError(); function f() {}; // 定義一個空構造函數 f.prototype = p; return new f(); // 使用 f() 創建 p 的繼承對象 } let o = {}; o.x = 1; let p = inherit(o); p.y = 2; // 屬性賦值操作首先會檢查原型鏈,以此判斷是否允許賦值 // 賦值時也只是在原始對象上創建屬性或對已有屬性賦值,而不會修改原型鏈 // 屬性賦值要麽失敗,要麽創建一個屬性,要麽在原始對象中設置屬性 p.x = 3; console.log(o.x); // 輸出 1 // 屬性訪問可以通過點或方括號來操作 console.log(p["x"] + p.y); // 輸出 5 // 非嚴格模式下查詢一個不存在的屬性並不會報錯 console.log(p.z); // 但如果對象本身不存在,那麽查詢這個不存在的對象的屬性就會報錯(undefined、null) // console.log(p.z.i); // 報錯
註: 1、不能給只讀屬性重新賦值
2、不能通過同名自有屬性覆蓋只讀的繼承屬性
3、如果對象 obj 不可擴展,那麽不能在 obj 中定義新屬性
刪除屬性:
1、delete 運算符可以刪除對象的屬性,但只是斷開屬性和宿主對象的聯系,而不會去操作屬性中的屬性
2、delete 運算符只能刪除自有屬性,而不能刪除繼承屬性
3、delete 刪除成功或者沒有任何副作用時,它返回 true;若它後面不是一個屬性訪問表達式,同樣會返回 true!!!
4、不能刪除那些可配置性為 false 的屬性,但可以刪除不可擴展對象的可配置屬性,非嚴格模式下返回 false,嚴格模式報錯
let par = {"q": 10}; let a = Object.create(par); a.p = {"x": 1}; let b = a.p; delete a.p; // delete 只斷開屬性和宿主對象的聯系,而不會去操作屬性中的屬性,可能會造成內存泄漏 console.log(b.x); // 輸出 1 console.log(delete a.q); // 什麽也沒做,輸出 true console.log(a.q); // 輸出 10 console.log(delete a.t); // 輸出 true console.log(delete 20); // 輸出 true console.log(delete Object.prototype); // 輸出 false console.log(delete b); // 刪除一個通過變量聲明或函數聲明(var 和 let)的對象會返回 false
檢測屬性:
1、運算符 in:左側為屬性名,右側為對象,若對象的自有屬性或繼承屬性中包含這個屬性,則返回 true
2、hasOwnProperty() 方法:檢測給定屬性是不是對象的自有屬性
3、propertyIsEnumerable() 方法:檢測屬性是不是自有屬性且可枚舉
// 若對象的自有屬性或繼承屬性中包含這個屬性,則返回 true let ino = {"x": 1}; console.log("x" in ino); // true console.log("toString" in ino); // true console.log("y" in ino); // false // 檢測給定屬性是不是對象的自有屬性 console.log(ino.hasOwnProperty("toString")); // false // 檢測屬性是不是自有屬性且可枚舉 console.log(ino.propertyIsEnumerable("x")); // true console.log(Object.prototype.propertyIsEnumerable("toString")); // 不可枚舉,false
註:可以使用 "attr !== undefined;" 來判斷屬性是否存在,但若屬性存在且值為 undefined,則只能使用 in
枚舉屬性:
1、for/in 循環可以在循環體中遍歷對象中所有可枚舉的屬性(包括自有屬性和繼承屬性),並把屬性名賦值給循環變量
2、ES5 定義了 Object.keys(),它返回一個由對象中可枚舉的自有屬性的名稱組成的數組
3、ES5 定義了 Object.getOwnPropertyNames(),它返回對象的所有自有屬性的名稱,而不僅僅是可枚舉屬性
let foro = {"x": 1, "y": 2}; for (let temp in foro) console.log(temp); // 輸出 x y console.log(Object.keys(foro)); // 輸出 [‘x‘, ‘y‘] console.log(Object.getOwnPropertyNames(Object.prototype));
JavaScript 對象(上)