筆記-你不知道的JS-對象

1 如何定義

// 聲明形式,大部分狀況下使用聲明形式
let obj ={
  a:2,
  b:3
};
// 構造形式
let obj= = new Object();
obj.a=2;
obj.b=3;

2 類型

7種類型:string、boolean、number、null 、 undefined、object、symbol正則表達式

typeof null === object,原理是這樣的,不一樣的對象在底層都表示爲二進制,在 JavaScript 中二進制前三位都爲 0 的話會被判斷爲 object 類型,null 的二進制表示是全 0,天然前三位也是 0,因此執行 typeof 時會返回「object」。算法

內置對象:String, Number, Object, Date, Boolean, Array, Function, RegExp, Error,在 JavaScript 中,它們實際上只是一些內置函數。這些內置函數能夠看成構造函數,使用 new 調用,產生新對象。數組

在必要時語言會自動把字符串字面量轉換成一個 String 對象,也就是說你並不須要顯式建立一個對象。安全

var strPrimitive = "I am a string"; 
console.log( strPrimitive.length ); // 13 
console.log( strPrimitive.charAt( 3 ) ); // "m"

咱們均可以直接在字符串字面量上訪問屬性或者方法,之因此能夠這樣作,是由於引擎自動把字面量轉換成 String 對象,因此能夠訪問屬性和方法。一樣引擎會自動把數字字面量轉換爲Number對象,如使用3.1415.toFixed(2)函數

null 和 undefined 沒有對應的構造形式,它們只有文字形式。相反,Date 只有構造,沒有文字形式。
對於 Object、Array、Function 和 RegExp(正則表達式)來講,不管使用文字形式仍是構造形式,它們都是對象,不是字面量。prototype

Error 對象不多在代碼中顯式建立,通常是在拋出異常時被自動建立。也可使用 newError(..) 這種構造形式來建立。code

3 屬性

. 操做符要求屬性名知足標識符的命名規範。對象

在對象中,屬性名永遠都是字符串。若是你使用 string(字面量)之外的其餘值做爲屬性名,那它首先會被轉換爲一個字符串。索引

var myObject = { };
let arr = [2,3];
myObject[true] = "foo"; 
myObject[3] = "bar"; 
myObject[myObject] = "baz";
myObject[arr] =4;
myObject["true"]; // "foo"
myObject["3"]; // "bar"
myObject["[object Object]"]; // 「baz」
myObject["2,3"]; // 4

爲數組添加命名屬性,但數組的length值不會變ip

4 複製

對於 JSON 安全(也就是說能夠被序列化爲一個 JSON 字符串而且能夠根據這個字符串解析出一個結構和值徹底同樣的對象)的對象來講,有一種巧妙的複製方法:

var newObj = JSON.parse( JSON.stringify( someObj ) );
Object.assign(..) 方法的第一個參數是目標對象,以後還能夠跟一個或多個源對象。它會遍歷一個或多個源對象的全部可枚舉(enumerable,參見下面的代碼)的自有鍵(owned key,很快會介紹)並把它們複製(使用 = 操做符賦值)到目標對象,最後返回目標對象。

5 屬性描述符

var myObject = { a:2};
Object.getOwnPropertyDescriptor( myObject, "a" );
// {
// value: 2,
// writable: true,
// enumerable: true,
// configurable: true 
// }
// writable(可寫)、 enumerable(可枚舉)和 configurable(可配置)

不論是不是處於嚴格模式,嘗試修改一個不可配置的屬性描述符都會出錯,也不能夠刪除該屬性。注意:如你所見,把 configurable 修改爲false 是單向操做,沒法撤銷!要注意有一個小小的例外:即使屬性是 configurable:false,咱們仍是能夠把 writable 的狀態由 true 改成 false,可是沒法由 false 改成 true。

enumerable描述符控制的是屬性是否會出如今對象的屬性枚舉中,好比說for..in 循環。若是把 enumerable 設置成 false,這個屬性就不會出如今枚舉中,雖然仍然能夠正常訪問它。

6 不變性

1 結合 writable:false 和 configurable:false 就能夠建立一個真正的常量屬性

2 若是你想禁止一個對象添加新屬性而且保留已有屬性,可使用 Object.preventExtensions(..)

3 Object.seal(..) 會建立一個「密封」的對象,這個方法實際上會在一個現有對象上調用Object.preventExtensions(..) 並把全部現有屬性標記爲 configurable:false。因此,密封以後不只不能添加新屬性,也不能從新配置或者刪除任何現有屬性(雖然能夠修改屬性的值)。

4 Object.freeze(..) 會建立一個凍結對象,這個方法實際上會在一個現有對象上調用Object.seal(..) 並把全部「數據訪問」屬性標記爲 writable:false,這樣就沒法修改它們的值。你能夠「深度凍結」一個對象,具體方法爲,首先在這個對象上調用 Object.freeze(..),而後遍歷它引用的全部對象並在這些對象上調用 Object.freeze(..)。可是必定要當心,由於這樣作有可能會在無心中凍結其餘(共享)對象。

7 [[Get]]和[[Put]]

在語言規範中,myObject.a 在 myObject 上其實是實現了 [[Get]] 操做(有點像函數調用:[[Get]]())。對象默認的內置 [[Get]] 操做首先在對象中查找是否有名稱相同的屬性,若是找到就會返回這個屬性的值。若是沒有找到名稱相同的屬性,會遍歷可能存在的 [[Prototype]] 鏈,也就是原型鏈。若在原型鏈上也沒有找到,那就返回undefined。

[[Put]] 被觸發時,若是已經存在這個屬性,[[Put]] 算法大體會檢查下面這些內容。

  1. 屬性是不是訪問描述符(參見3.3.9節)?若是是而且存在setter就調用setter。
  2. 屬性的數據描述符中writable是不是false?若是是,在非嚴格模式下靜默失敗,在嚴格模式下拋出 TypeError 異常。
  3. 若是都不是,將該值設置爲屬性的值。

若是對象中不存在這個屬性,[[Put]] 操做會更加複雜。

8 存在性

in 操做符會檢查屬性是否在對象及其 [[Prototype]] 原型鏈中。

hasOwnProperty(..) 只會檢查屬性是否在 myObject 對象中,不會檢查 [[Prototype]] 鏈。

全部的普通對象均可以經過對於 Object.prototype 的委託來訪問hasOwnProperty(..), 但 是 有 的 對 象 可 能 沒 有 連 接 到 Object.prototype( 通 過Object.create(null) 來建立)。在這種狀況下,形如 myObejct.hasOwnProperty(..)就會失敗。這時可使用Object.prototype.hasOwnProperty.
call(myObject,"a")。

9 遍歷

for..in 循環能夠用來遍歷對象的可枚舉屬性列表(包括 [[Prototype]] 鏈)。

對於數值索引的數組來講,可使用標準的 for 循環來遍歷值,或者使用for...of循環,for..of 循環首先會向被訪問對象請求一個迭代器對象,而後經過調用迭代器對象的next() 方法來遍歷全部返回值。

相關文章
相關標籤/搜索