對象是js中的基礎以及核心,在js中有六種主要類型:string number boolean null undefined objectjavascript
除了oject類型覺得其餘五種自己並不是對象,null自己被劃爲object類型自己是js中的一個bug,即便它的typeof類型是 object,實際上null自己仍是基本類型。vue
常見的錯誤說法是:js中萬物皆是對象,這顯然是錯誤的。java
實際上,js中有許多特殊的對象子類型。咱們稱之爲複雜基本類型。數組
js中有一些對象子類型被稱爲內置對象,如:框架
• String函數
• Numberthis
• Booleanes5
• Objectprototype
• Function指針
• Array
• Date
• RegExp
• Error
原理是這樣的,不一樣的對象在底層都表示爲二進制,在 JavaScript 中二進制前三位都爲 0 的話會被判 斷爲 object 類型,null 的二進制表示是全 0,天然前三位也是 0,因此執行 typeof 時會返回「object」。
在 JavaScript 中,它們實際上只是一些內置函數。這些內置函數能夠看成構造函數來使用,從而能夠構造一個對應子類型的新對象。舉例來講:
var strPrimitive = "I am a string"; typeof strPrimitive; // "string" strPrimitive instanceof String; // false var strObject = new String( "I am a string" ); typeof strObject; // "object" strObject instanceof String; // true // 檢查 sub-type 對象 Object.prototype.toString.call( strObject ); // [object String]
數組也是對象,因此雖然每一個下標都是整數,你仍然能夠給數組添加屬性:
var myArray = [ "foo", 42, "bar" ]; myArray.baz = "baz"; myArray.length; // 3 myArray.baz; // "baz"
能夠看到雖然添加了命名屬性,數組的 length 值並未發 生變化。
若是你試圖向數組添加一個屬性,可是屬性名「看起來」像一個數字,那它會變成 一個數值下標(所以會修改數組的內容而不是添加一個屬性):
var myArray = [ "foo", 42, "bar" ]; myArray["3"] = "baz"; myArray.length; // 4 myArray[3]; // "baz"
接着有必要介紹行對象的三個屬性:writable(可寫)、 enumerable(可枚舉)和 configurable(可配置)。
var myObject = {}; Object.defineProperty( myObject, "a", { value: 2, writable: true, configurable: true, enumerable: true } )
writable 決定是否能夠修改屬性的值。
configurable 禁止修改以及刪除屬性。delete也很差使。
enumerable 決定對象的屬性是否能夠被枚舉,如for in
Object.seal(..) 會建立一個「密封」的對象,這個方法實際上會在一個現有對象上調用 Object.preventExtensions(..) 並把全部現有屬性標記爲 configurable:false。
Object.freeze(..) 會建立一個凍結對象,這個方法實際上會在一個現有對象上調用 Object.seal(..) 並把全部「數據訪問」屬性標記爲 writable:false,這樣就沒法修改它們 的值。
對象的defineproperty以及set,get,在vue等框架中是核心原理。這裏就不展開說了,因此vue只能兼容到IE8,由於必須的得支持對象的es5對象中的一系列方法才行。
對於上面提到的for in 能夠聯想到for of,還有重要的iterator數組的迭代器。如何手動調試循環 next()啓動,以及返回值是什麼,看下面的例子。
var myObject = { a: 2, b: 3 }; Object.defineProperty( myObject, Symbol.iterator, { enumerable: false, writable: false, configurable: true, value: function() { var o = this; var idx = 0; var ks = Object.keys( o ); return { next: function() { return { value: o[ks[idx++]], done: (idx > ks.length) }; } }; } } ); // 手動遍歷 myObject var it = myObject[Symbol.iterator](); it.next(); // { value:2, done:false } it.next(); // { value:3, done:false } it.next(); // { value:undefined, done:true } // 用 for..of 遍歷 myObject for (var v of myObject) { console.log( v ); } // 2 // 3
調用迭代器的 next() 方法會返回形式爲 { value: .. , done: .. } 的值, value 是當前的遍歷值,done 是一個布爾值,表示是否還有能夠遍歷的值。
最後的調用一次 next() 才能獲得 done:true,從而肯定完成遍歷。
和數組不一樣,普通的對象沒有內置的 @@iterator,因此沒法自動完成 for..of 遍歷。之所 以要這樣作,有許多很是複雜的緣由,不過簡單來講,這樣作是爲了不影響將來的對象 類型。
for..of 循環每次調用 myObject 迭代器對象的 next() 方法時,內部的指針都會向前移動並 返回對象屬性列表的下一個值(再次提醒,須要注意遍歷對象屬性 / 值時的順序)。