JavaScript中並不是一切皆對象

對象是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() 方法時,內部的指針都會向前移動並 返回對象屬性列表的下一個值(再次提醒,須要注意遍歷對象屬性 / 值時的順序)。

相關文章
相關標籤/搜索