關於Object

簡單記錄了關於js object的一些觀念和操作


JavaScript有八種資料型別,其中七種是原始型別(Primitive Type),另一種是物件型別(Object Type)。與只包含單一數值的原始型別相比,物件型別用來存儲相對複雜的實體

關於Object操作

創建一個空物件的方法如下:

let foo = new Object(); // 使用construct
let foo = {}; // 使用literal

在創建對象的時候,能將屬性以key/value方式放入:

let foo = {
  name: 'Alice',
  age: 16,
};

並且在創建對象後可以任意添加、刪除和讀取

// 添加
foo.isMale = false;
 
// 刪除
delete foo.age;
 
// 讀取
console.log(foo.name); // Alice
 
console.log(foo);
//  {
//    "nname": "Alice",
//    "isMale": false
//  }

多詞屬性使用時要用方括號:

let test = {
  'foo bar': false,
};
 
test['foo bar'] = true;
 
console.log(test['foo bar']);
 
delete test['foo bar'];

計算屬性

當創建一個對象,我們能在對object的literal中動態計算屬性名(Computed property names),如下:

const Number = 3;
 
const myObject = {
  Num1: 5,
  Num2: 10,
  ['Num' + Number]: 15,
};
 
console.log(myObject.Num3); // prints 15

測試存在屬性

// "key" in object
 
let user = { name: 'John', age: 18 };
 
console.log('age' in user); // true

為何不使用一般undefined判斷,因為有些情況下是要看是否有該屬性,而不是屬性值是undefined

let obj = {
  test: undefined,
};
 
alert(obj.test === undefined); // true
alert('test' in obj); // true
 
alert(obj.test2 === undefined); // true
alert('test2' in obj); // false

遍歷object屬性值

使用"for...in"來遍歷一個object,如下:

for (key in object) {
}
 
// example
let user = {
  name: 'John',
  age: 18,
  isMale: true,
};
 
for (let key in user) {
  console.log(key); // name, age, isMale
  console.log(user[key]); // John, 18, true
}

關於object的引用

object是"通過引用"來存儲和複製,原始類型是"做為一個整體"來複製。

原始類型如下:

let test = 'hello';
let test2 = test;
 
//產生兩個獨立的variable,並且每個variable存著字串
// ------- -------
//  test  | hello
// ------- -------
//
// ------- -------
//  test2 | hello
// ------- -------

而object則是,賦予object的varaible存儲的不是object本身,而是該object在memory中的地址,也就是對該object的引用

let user = {
  name: 'John',
};
 
let test = user; // 複製引用 (複製了該物件的地址)

該object被存儲在memory中的某個位置,並且變量user保存的值,是對其的"引用",也就是該object的位址。並且"當一個object變量被複製,而該值是複製了該位址,而不是該object本身"。

let user = {
  name: 'John',
};
 
let test = user;
 
// 修改test
test.name = 'Alice';
 
console.log(user.name); // Alice

我們來對比一下:

let a = {};
let b = a; // ref object
 
console.log(a == b); // true
consoel.log(a === b); // true
 
// create new object
let c = {};
 
console.log(a == c); // false
console.log(a === c); // false

我們能看到a和b引用同一個物件,所以他們相等。並且a和c是兩個獨立的物件,所以他們並不相等,即使都是空物件。

如何複製一個Object

一般情況下,複製一個object變量會創建一個對相同object的引用。所以該如何複製出一個獨立的object?

複製簡單object

1.創立一個新object,並對已有對象的屬性遍歷,並在原始類型值的層面去複製他們。

let user = {
  name: 'John',
  age: 18,
};
 
let obj = {};
for (let key in user) {
  obj[key] = user[key];
}

2.也可以透過Object.assign來達成(如果屬性名存在,會被覆蓋):

let user = {
  name: 'John',
  age: 18,
};
 
let height = {
  height: 180,
};
let isMale = {
  isMale: true,
};
 
Object.assign(user, height, isMale);
// user = { name: "John", age: 18, height: 180, isMale: true }
 
// Or
let obj2 = Object.assign({}, user);

3.或者是使用spread來進行clone:

let obj3 = { ...uer };

但上面的方法都是因為user的所有屬性都是原始屬性,但當屬性是其他對象的引用時就會有問題。

let user = {
  name: 'John',
  info: {
    weight: 65,
    height: 180,
  },
};

如果使用先前的三個方法,會導致"新的object中的info",指向與"user中info"相同的引用。

那麼這時候我們就要使用到深拷貝(deep clone)。

複製複雜object

下面是幾種常用的方法:

  • 使用JSON.stringify(obj)以及JSON.parse(JSONString)
  • 使用lodash中的_.cloneDeep(obj)
  • 使用js原生api中的方法,structuredClone(obj)

這裡記錄了關於object的一些簡易操作,之後會在新的文章添加一些新的紀錄。