2018-06-09 JS裏的複雜數據類型:object對象

前言:上一遍博客介紹了JS中的五種簡單數據類型,這篇博客主要介紹JS中的複雜數據類型,object對象。注:本文參考阮一峯JS教程中關於對象的介紹,然後結合自己的理解寫成,附帶鏈接


1、概述

什麼是對象?簡單說,對象就是一組“鍵值對”(key-value)的集合,是一種無序的複合數據集合。
對象的所有鍵名都是字符串(ES6 又引入了 Symbol 值也可以作爲鍵值),所以加不加引號都可以。如果鍵名是數值的時候,會被自動轉爲字符串。所以“鍵名可以是數值”這句話是錯誤的。如下列代碼,看着鍵名是數值,但實際上它們已經被轉換成字符串了。

var obj = {
  1: 'a',
  3.2: 'b',
  1e2: true,
  1e-2: true,
  .234: true,
  0xFF: true
};

但是,當鍵名不加引號的時候,則其必須符合標識名的條件(比如第一個字符不能爲數字,或者不能含有空格或運算符),且也不是數字,否則會報錯。

2、對象的引用

如果不同的變量名指向同一個對象,那麼它們都是這個對象的引用,也就是說指向同一個內存地址。修改其中一個變量,會影響到其他所有變量。
如:

var o1 = {};"hello world"
var o2 = o1;

o1.a = 1;
o2.a // 1

o2.b = 2;
o1.b // 2

上面代碼中,o1和o2指向同一個對象,因此爲其中任何一個變量添加屬性,另一個變量都可以讀寫該屬性。

此時,如果取消某一個變量對於原對象的引用,不會影響到另一個變量。

var o1 = {};
var o2 = o1;

o1 = 1;
o2 // {}

注意:上述規律只適用於對象,如果是變量的話,即兩個變量指向同一個原始類型的值。那麼,變量這時都是值的拷貝。如:

var x = 1;
var y = x;

x = 2;
y // 1

3、表達式還是語句?

這麼一行代碼,你覺得它是語句還是對象:{ foo: 123 },很多人會說,很顯然嘛,大括號裏面的是一個”鍵值對”的形式,肯定表示對象。
但是計算機沒有那麼智能,JavaScript 引擎讀到上面這行代碼,會發現可能有兩種含義。第一種可能是,這是一個表達式,表示一個包含foo屬性的對象;第二種可能是,這是一個語句,表示一個代碼區塊,裏面有一個標籤foo,指向表達式123。

爲了避免這種歧義,JavaScript 規定,如果行首是大括號,一律解釋爲語句(即代碼塊)。如果要解釋爲表達式(即對象),必須在大括號前加上圓括號。所以,這句話{ foo: 123 } JS會將其解讀成語句。
那麼想表示對象該怎麼寫呢,舉個例子:
({ foo: 123})

4、對象中屬性的讀取

讀取對象的屬性,有兩種方法,一種是使用點運算符,如obj.p,還有一種是使用方括號運算符,如obj['p']。很明顯,我們平常使用最多的方式還是點運算符。不過還是有幾個坑容易踩(JS中總是有很多坑),下面大致介紹一下兩種方法需要注意的地方。

  • 如果使用方括號運算符,鍵名必須放在引號裏面,否則會被當作變量處理。
  • 方括號運算符內部還可以使用表達式。如obj['hello' + ' world']
    obj[3 + 3],獲取的是運算後的結果的屬性,比如obj[3 + 3]獲取的是obj[6]的屬性,哪怕它其中有一個鍵名是’3+3’,也是獲取不到的,想要獲取鍵名是’3+3’的屬性 ,得這麼寫obj['3 + 3']
  • 數字鍵可以不加引號,因爲會自動轉成字符串。
  • 數值鍵名不能使用點運算符(因爲會被當成小數點),只能使用方括號運算符。
  • 想使用點運算符,鍵名必須的符合標示符規範

所以很顯然,雖然點運算符寫代碼是時候方便,但是也容易不小心踩到坑,需要注意很多;方括號運算符不用考慮太多,只是寫起來稍微麻煩一點,怎麼取捨就要看官自己決定啦。

5、對象中屬性的賦值

點運算符和方括號運算符,不僅可以用來讀取值,還可以用來賦值。
JavaScript 允許屬性的“後綁定”,也就是說,你可以在任意時刻新增屬性,沒必要在定義對象的時候,就定義好屬性。(具體原因參看第2條)

6、操作對象的幾種命令

  • 查看一個對象本身的所有屬性,可以使用Object.keys方法。舉例說明:
var obj = {
  key1: 1,
  key2: 2
};

Object.keys(obj);
// ['key1', 'key2']
  • delete命令用於刪除對象的屬性,刪除成功後返回true。需要注意的是:刪除一個不存在的屬性,delete不報錯,而且返回true。

  • in運算符用於檢查對象是否包含某個屬性(注意,檢查的是鍵名,不是鍵值),如果包含就返回true,否則返回false。舉例說明:

var obj = { p: 1 };
'p' in obj // true
  • for…in 循環,用來遍歷一個對象的全部屬性。舉個栗子:
var obj = {a: 1, b: 2, c: 3};

for (var i in obj) {
  console.log(obj[i]);
}
// 1
// 2
// 3

當然,使用for…in循環也可以便利對象的屬性名,即鍵值:

var obj = {
  x: 1,
  y: 2
};
var props = [];
var i = 0;

for (var p in obj) {
  props[i++] = p
}

props // ['x', 'y']

不過使用for…in循環有以下兩點需要注意:
1. 它遍歷的是對象所有可遍歷(enumerable)的屬性,會跳過不可遍歷的屬性。
2. 它不僅遍歷對象自身的屬性,還遍歷繼承的屬性。

  • with語句,它的作用是操作同一個對象的多個屬性時,提供一些書寫的方便。
    舉個栗子:
with (document.links[0]){
  console.log(href);
  console.log(title);
  console.log(style);
}
// 等同於
console.log(document.links[0].href);
console.log(document.links[0].title);
console.log(document.links[0].style);

注意1:如果with區塊內部有變量的賦值操作,必須是當前對象已經存在的屬性,否則會創造一個當前作用域的全局變量。
注意 2:with語句的一個很大的弊病,就是綁定對象不明確。所以一般情況不建議使用with語句。

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