JavaScript淺嚐紀錄No.5-呈現真實世界的物件該如何運用?

物件(Object)

MDN中如此介紹:

物件是一批相關的數據以及/或者功能,可裝載相關的資料與程式碼,資料部分是你塑造某個模型的資訊,而程式碼部分則用是操作行為(Method)實現。Object data – 函式部分通常也使用 —可工整地儲存 (正式一點應該是封裝 Encapsulated) 在物件包裹(這個包裹有特定的稱呼方式,有時候即所謂的命名空間 Namespace) ,使其能輕鬆地建構性存取。物件也常作為「資料儲存 (Datastore),促成簡易實現跨網傳送。。

物件表示法

在物件中,屬性代表靜態的資料,用於描述物件的狀態;**方法(函式)**代表物件的功能,或說物件的行為。

擷取自Alpha Camp學期2-1物件和函式

物件實字

  • 利用{}創建物件。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    let person = {} //空物件
    let person = {
    name: 'Bob',
    age: 32,
    gender: 'male',
    interests: ['music', 'skiing'],
    greeting: function () {
    console.log('Hi! I\'m ' + this.name[0] + '.');
    }
    } //直接在{}中寫下key-value pair的值
  • 可以透過**點記法(Dot notation)或是括弧記法(Bracket notation)**存取物件的屬性與函式。

    以上面的person物件來當例子:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    //點記法
    //括弧記法,記得使用['key']取值時,key一定要加''
    console.log(person.name) //取得姓名值 "Bob"
    console.log(person['name']) //取得姓名值 "Bob"
    person.age = 45 //更改年齡值為 45
    person['age'] = 45 //更改年齡值為 45
    console.log(person.name) //取得年齡值 45
    console.log(person['age']) //取得年齡值 45

    //物件中包含物件,如何取值
    let person = {
    name: {
    first: 'Bob',
    last: 'Smith'
    },
    }
    console.log(person.name.last) //取得姓名last值'Smith'
    console.log(person['name']['last']) //取得姓名last值'Smith'
    person.name.first = 'Cratchit' //更改姓名first值'Cratchit'
    person['name']['first'] = 'Cratchit'//更改姓名first值'Cratchit'
    console.log(person.name.first) //取得姓名first值'Cratchit'
    console.log(person['name']['first']) //取得姓名first值'Cratchit'

建構函式(constructor function)

高效率的建構擁有相同屬性或方法的物件,即是用多個物件類別建置相同功能,並且使用`new`關鍵字來呼叫建構函式。

建構函式名稱往往以大寫字母起頭,如此可方便在程式碼中找出建構函式。

寫法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//利用function創建物件基本架構
function ConstructorName(parameter) {
this.propertyName = value;//可以帶入參數
this.methodName= function() {
console.log('Hi! I\'m ' + this.name + '.');
};
}
//範例
function Person(name) {
this.name = name;
this.greeting = function() {
console.log('Hi! I\'m ' + this.name + '.');
};
}

在上面程式碼中的this代表著物件擁有者,誰使用了這個建構函式,那麼這個this就指向他。

看一下下面的程式碼,先利用關鍵字new及建構函式來創建新的物件,就能明白this指向誰了。

1
2
3
4
5
6
7
8
9
10
11
12
let Bob = new Person('Bob')
console.log(Bob)
//創建出了變數名為Bob的物件,類似下方程式碼(但在程式碼中並不會顯示,可用console.log()顯示)
let Bob = {
name : 'Bob',
greeting : function () {
console.log('Hi! I\'m ' + this.name + '.') //這時候的this指向的就是Bob
},
}

let Sarah = new Person('Sarah')
console.log(Sarah) //這時候的this指向的就是Sarah

點記法(Dot notation)v.s括弧記法(Bracket notation)

  1. 括弧記法可以利用變數作為屬姓名取值,點記法不行,並且會出現undefined
1
2
3
4
5
6
7
8
9
10
let obj = {}
let tall= "height"
let tallVal = 160

////括弧記法
obj[tall] = tallVal
console.log(obj[tall]) //160

//點記法
console.log(obj.tall) //undefined
  1. 括弧記法可以利用數字做為屬姓名,點記法不行,會出現Uncaught SyntaxError: Unexpected numbe
1
2
3
4
5
6
7
8
let obj = {}

//括弧記法
obj[2] = 2
console.log(obj[2]) //2

//點記法
obj.2 = 2 //Uncaught SyntaxError: Unexpected number
  1. 括弧記法可以動態(如加減)的設定變數名,點記法不行,會出現Uncaught SyntaxError: Unexpected template string
1
2
3
4
5
6
7
8
9
10
11
12
13
14
let obj = {}
let nation = ['USA', 'UK', 'Thailand', 'Netherlands']

//括弧記法
for (let i = 0; i < nation.length; i++) {
obj[`nation ${i+1}`] = nation[i]
}
console.log(obj) // {nation 1: "USA", nation 2: "UK", nation 3: "Thailand", nation 4: "Netherlands"}

//點記法
for (let i = 0; i < nation.length; i++) {
obj.`nation ${i+1}` = nation[i]
}
console.log(obj) // Uncaught SyntaxError: Unexpected template string

物件方法應用

Object.assign() 複製物件
寫法Object.assign(target, ...sources)target需要複製的物件,sources複製的來源(被複製的物件)。

  • 基本款

    1
    2
    3
    4
    5
    6
    7
    8
    9
    const obj = {
    a: 1,
    b: 2,
    c: 3
    }
    const copyObj = Object.assign({}, obj) //把obj複製給空物件{}
    console.log(obj) //{a: 1, b: 2, c: 3}
    console.log(copyObj)//{a: 1, b: 2, c: 3}
    console.log(obj===copyObj)//false
  • 複雜款

    • 複製來源(sources)有許多個,並且source裡有相同的key值,那麼複製時,後面來源會將前面來源的value值覆蓋掉。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      const obj1 = {
      a: 1,
      b: 2,
      c: 3
      }
      const obj2 = {
      b: 4,
      c: 5
      }
      const copyObj = Object.assign({}, obj1, obj2) //將obj1, obj2複製給空物件{}
      console.log(obj1) //{a: 1, b: 2, c: 3}
      console.log(obj2) //{b: 4, c: 5}
      console.log(copyObj) //{a: 1, b: 4, c: 5} 複製時obj2會將obj1中相同key的value值覆蓋掉,所以b跟c會是obj2的值
    • 複製來源(sources)物件值是物件包裹子物件的話,Object.assign()只會複製該子物件的參照位址,如果要讓相同內容的物件(有子物件)有新的參照位址可以參考JSON.parse(JSON.stringify())的作法。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      let a = {
      b: {
      c: 4
      },
      d: {
      e: {
      f: 1
      }
      }
      }
      let g = Object.assign({}, a) // 淺層複製
      let h = JSON.parse(JSON.stringify(a)); // 深層複製
      console.log(a=== g) //false,a、g指向不同參照位址,但裡面的子物件指向相同的位址。
      console.log(a=== h)//false,a、h(及裡面的子物件)指向不同參照位址。
      console.log(g.d.e === a.d.e) // true,淺層複製,b、d、e都是複製參照位址所以值為相同。
      console.log(h.d.e === a.d.e) // false,深層複製,b、d、e指向不同的參照位址。
    • 複製的target會被sources影響。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      const obj1 = {
      a: 1,
      b: 2,
      c: 3
      }
      const obj2 = {
      b: 4,
      c: 5
      }
      const copyObj = Object.assign(obj1, obj2)//這時的obj1與copyObj是相同的
      console.log(obj1) //{a:1,b:4,c:5}
      console.log(copyObj) //{a:1,b:4,c:5}
      console.log(obj1===copyObj) //true

參考資料:

MDN-JavaScript 物件基礎概念
MDN-初學者應知道的物件導向 JavaScript
JavaScript中物件屬性通過點(.)和方括號([])取值的不同之處
w3school-JavaScript this 关键词
MDN-Object