JavaScript中的對象

語法

創建一個對象有兩種形式:聲明(文字)形式構造形式
例如:

// 聲明形式
var myObject = {
  name: 'cherry',
  age: 20,
};

// 構造形式
var myObject = new Object();
myObject.name = 'cherry';
myObject.age = 20;

一般我們在開發的時候,在創建一個對象的時更喜歡用聲明(文字)形式,這種形式可以簡化創建包含有大量屬性的對象的過程。

內置對象

Object是JavaScript的基礎,它也是JavaScript語言類型中的一種。JavaScript中的語言類型包含:

  • string
  • number
  • boolean
  • null
  • undefined
  • Object
  • symbol (ES6新增)

除去object之外,其他的類型都被稱爲簡單基礎類型,在使用typeof來測試null的時候,會返回‘object’,但是null並不是object類型。造成這種情況是由於不同對象在底層會被表示爲二進制,當二進制的前三位都是0的時候會被認爲是object類型,而null的二進制表示爲全0,因此,前三位自然是0,所以在使用typeof的時候,會返回’object‘。Object類型有多衍生的子類型,函數就是Object的一個子類型,數組也是。這些子類型通常被稱爲JavaScript的內置對象。有些內置對象的名字看起來和簡單基礎類型一樣。

  • String
  • Number
  • Boolean
  • Array
  • Function
  • Date
  • Error
  • RegExp
  • Object

這些內置對象在JavaScript中實際上是內置函數,這些內置函數可以作爲構造函數來使用,從而可以構建一個對應子類型的新對象。

例如:


var str = 'I am a string';
typeof str ; // string
str instanceof String; // false

var strObj = new String('I am a string');
typeof strObj ; // object
strObj instanceof String; // true

原始值’I am a string’並不是一個對象,它只是一個字面量,並且是一個不可改變的值。當我們需要在字符串上執行一些操作的時候,比如:獲取具體的對應位置的字符,獲取字符串的長度…,需要將其轉換爲String對象,幸好,在必要的時候語言會自動將字符串字面量轉換爲String對象。也就是數,你不需要自己顯式的創建一個對象。


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

對象中的內容

對象中的內容是由一些存儲在特定命名位置的(任何類型)的值組成。雖然這麼說,但是對象並不是擁有這些內容,在引擎內部,這些值的存儲方式各種各樣,一般並不會存儲在對象容器中,存儲在對象容器中的是這些屬性的名字,這些名字就像指針一樣,指向這些值真正的存儲位置。

訪問對象中的內容

訪問對象中的內容有兩種方式:.操作符(屬性訪問)[]操作符(鍵訪問)

例如:

var myObj = {
  a: 2,
};

myObj.a ; // 2
myObj['a']; // 2

這兩種訪問方式訪問的都是同一個位置,拿到的也是同一個值,在日常開發中,我們最常用的是屬性訪問。這兩種訪問方式的區別在於,.操作符要求屬性名必須符合標識符的命名規範,而['...']操作符則可以接受任意的UTF-8/Unicode字符串。例如,如果訪問名稱爲’super-name’的屬性,就不能使用.操作符,只能使用['super-name']來訪問。

屬性描述符

從ES5開始,所有的屬性都具有屬描述符,屬性描述符用來描述該屬性是否只讀,是否可配置,以及是否可遍歷。所以屬性描述符是針對一個屬性而言的,並不是針對整個對象。

  • writable
  • configurable
  • enumerable

以上就是JavaScript中的屬性描述符。writable決定了是否可以修改屬性的值,configurable決定了是否可以配置屬性的屬性描述符,enumerable決定了屬性是否可遍歷。在我們創建一個屬性的時候,這三個屬性描述符都是默認值。

var myObj = {
  a: 2,
};

Object.getOwnPropertyDescription(myObj, 'a');
// {
//    value: 2,
//    writable: true,
//    configurable: true,
//    enumerable: true,
// }

我們可以使用Object.defineProperty(…)來添加一個新屬性或修改一個已有屬性,並對屬性操作符進行設置。

var myObj = {};
Object,defineProperty(myObj,  'a', {
  value: 2,
  wirtable: true,
  configurable: true,
  enumerable: true,
});

一般來說,你並不會使用這種方式來爲對象添加屬性,除非你想改變屬性的屬性描述符。

getter和setter

ES5中的gettersetter用來改寫默認操作,但是隻能應用於單個屬性,不能應用於整個對象上。getter是一個隱藏函數,在調用對象屬性的時候調用,setter也是一個隱藏函數,在給對象屬性賦值的時候調用。

通常來說gettersetter是成對出現的,當你給一個屬性定義了gettersetter時,這個屬性會被定義爲‘訪問描述符’,對於訪問描述符,JavaScript會忽略它的valuewritable屬性,取而代之的是隻關心它的getset以及configurableenumerable特性。

var myObj = {
   get a() {
     return this.a;
   }
   set a(val) {
     this.a = val * 2;
   }
}
myObj.a = 2;
myObj.a ; // 4
     

存在性

之前我們提到過,如果引用一個對象中不存在的屬性時,會返回undefined,但是undefined有可能是對象中的屬性存儲的值,那麼如何來區分者兩種情況?

var myObj = {
  a: undefined,
}
myObj.a; // undefined
myObj.b; // undefined;

在JavaScript中用來判定一個屬性是否存在的方法有兩個:

  • in操作符
  • hasOwnProperty(…)

繼續上面的例子:

('a' in myObj); // true
('b' in myObj); // false

myObj.hasOwnProperty('a'); // true
myObj.hasOwnProperty('b'); // false

這兩種方法的區別是。in操作符不但會在當前對象中進行查找,也會查找該對象的原型鏈,而hasOwnProperty(...)只會在當前對象中進行查找,不會查找該對象的原型鏈。

遍歷

之前介紹的enumerable描述符用來描述一個屬性是否可枚舉,而可枚舉就相當於一個屬性是否會出現在對象屬性的遍歷中。例如:

var myObject = {
  a: 2,
};
Object.definePropertyDescription(myObject, 'b', {
  value: 4,
  enumerbale: false, // 讓屬性b不可枚舉
});

myObject.b; // 3
("b" in myObject); // true 
myObject.hasOwnProperty( "b" ); // true 

for (var k in myObject) {
  console.log( k, myObject[k] ); 
} 
// "a" 2

可以看到的是,'b'確實可以訪問,並且存在於myObject當中,但是使用for...in進行遍歷的時候,確不會出現在循環中,原因就是屬性b是一個不可枚舉屬性

我們還可以使用其他的方式進行檢測一個屬性是否可枚舉,接着上面的例子:

myObjec.propertyIsEnumerable('a'); true
myObjec.propertyIsEnumerable('b'); false

Object.keys(myObject); // ['a']
Object.getOwnPropertyNames( myObject ); ['a', 'b']

propertyIsEnumerable(...)方法可以檢測一個屬性是否可以枚舉,Object.keys(..)返回的是一個數組,包含一個對象中所有可枚舉的屬性名,Object.getOwnPropertyNames(...)返回的也是一個數組,包含的是一個對象所有的屬性名,無論它們是否可枚舉。且這兩個方法都只會返回這個對象包含的直接屬性,並不會涉及到對象的原型鏈。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章