# Objects

```
let user = new Object(); // "object constructor" syntax
let user = {};  // "object literal" syntax
```

## Literals and properties

```javascript
let user = {     // an object
  name: "John",  // by key "name" store value "John"
  age: 30,        // by key "age" store value 30
  "likes birds": true,  // multiword property name must be quoted 最後一個加上,
};

// get fields of the object:
alert( user.name ); // John
alert( user.age ); // 30

// 刪除物件資料
delete user.age;
```

## Square brackets

```javascript
let user = {};

// this would give a syntax error
user.likes birds = true

// set
user["likes birds"] = true;

// get
alert(user["likes birds"]); // true

// delete
delete user["likes birds"];

let key = "likes birds";

// same as user["likes birds"] = true;
user[key] = true;

// key obtain property name as a result of expression
let user = {
  name: "John",
  age: 30
};

let key = prompt("What do you want to know about the user?", "name");

// access by variable
alert( user[key] ); // John (if enter "name")
```

### Computed properties

```javascript
let fruit = prompt("Which fruit to buy?", "apple");

let bag = {
  [fruit]: 5, // the name of the property is taken from the variable fruit
};

alert( bag.apple ); // 5 if fruit="apple"

// same
let fruit = prompt("Which fruit to buy?", "apple");
let bag = {};

// take property name from the fruit variable
bag[fruit] = 5;

// more complex expression
let fruit = 'apple';
let bag = {
  [fruit + 'Computers']: 5 // bag.appleComputers = 5
};
```

### Reserved words are allowed as property names

任意的名稱都可以作為屬性名稱，只有 \_proto\_ 不行。

```javascript
let obj = {
  for: 1,
  let: 2,
  return: 3
};

alert( obj.for + obj.let + obj.return );  // 6

let obj = {};
obj.__proto__ = 5;
alert(obj.__proto__); // [object Object], didn't work as intended
```

## Property value shorthand

通常會使用現存變數的名稱作為 key，可以簡寫為一個值，如下範例。

```javascript
function makeUser(name, age) {
  return {
    name: name,
    age: age
    // ...other properties
  };
}

let user = makeUser("John", 30);
alert(user.name); // John

// shorthand
function makeUser(name, age) {
  return {
    name, // same as name: name
    age   // same as age: age
    // ...
  };
}

// both use normal and shorthands
let user = {
  name,  // same as name:name
  age: 30
};
```

## Existence check

要取得物件不存在的屬性不會出現錯誤，會返回 undefined，可以用來檢測屬性是否存在；也可以用 in 檢查。

```javascript
let user = {};

alert( user.noSuchProperty === undefined ); // true means "no such property"

// special operator in
let user = { name: "John", age: 30 };

alert( "age" in user ); // true, user.age exists
alert( "blabla" in user ); // false, user.blabla doesn't exist

// omit ""
let user = { age: 30 };

let key = "age";
alert( key in user ); // true, takes the name from key and checks for such property

// special condition if value = undefined
let obj = {
  test: undefined
};

alert( obj.test ); // it's undefined, so - no such property?

alert( "test" in obj ); // true, the property does exist!
```

## The “for…in” loop

物件的迴圈不適用 `for { ; ; }` 而是 `for { in }` ，

```javascript
for (key in object) {
  // executes the body for each key among object properties
}

let user = {
  name: "John",
  age: 30,
  isAdmin: true
};

for (let key in user) {
  // keys
  alert( key );  // name, age, isAdmin
  // values for the keys
  alert( user[key] ); // John, 30, true
}
```

### Ordered like an object

整數的屬性依照大小排列，其他的屬性依寫得先後順序排列。

```javascript
let codes = {
  "49": "Germany",
  "41": "Switzerland",
  "44": "Great Britain",
  // ..,
  "1": "USA"
};

for (let code in codes) {
  alert(code); // 1, 41, 44, 49
}

// Math.trunc is a built-in function that removes the decimal part
alert( String(Math.trunc(Number("49"))) ); // "49", same, integer property
alert( String(Math.trunc(Number("+49"))) ); // "49", not same "+49" ⇒ not integer property
alert( String(Math.trunc(Number("1.2"))) ); // "1", not same "1.2" ⇒ not integer property

let codes = {
  "+49": "Germany",
  "+41": "Switzerland",
  "+44": "Great Britain",
  // ..,
  "+1": "USA"
};

for (let code in codes) {
  alert( +code ); // 49, 41, 44, 1
}

let user = {
  name: "John",
  surname: "Smith"
};
user.age = 25; // add one more

// non-integer properties are listed in the creation order
for (let prop in user) {
  alert( prop ); // name, surname, age
}
```

## Copying by reference

原始值會複製一樣的值進去，物件會指到相同的記憶體，只要有一個物件的值改變，所有指向相同記憶體的物件都會改變

```javascript
let message = "Hello!";
let phrase = message;

let user = { name: "John" };
let admin = user; // copy the reference
admin.name = 'Pete'; // changed by the "admin" reference
alert(user.name); // 'Pete', changes are seen from the "user" reference
```

### Comparison by reference

\== 跟 === 對物件來說是一樣的，只有當 2 個變數都只到相同記憶體時才相同。

```javascript
let a = {};
let b = a; // copy the reference
alert( a == b ); // true, both variables reference the same object
alert( a === b ); // true

// different reference
let a = {};
let b = {}; // two independent objects
alert( a == b ); // false
```

### Const object

`const` 在同個記憶體內改變物件不會出現錯誤，除非將變數指向另一個記憶體才會出現錯誤。

```javascript
const user = {
  name: "John"
};

user.age = 25; // (*)

alert(user.age); // 25

// change reference
const user = {
  name: "John"
};

// Error (can't reassign user)
user = {
  name: "Pete"
};
```

## Cloning and merging, Object.assign

通常會使用變數指到相同的記憶體，但若想要複製獨立一樣的物件，也是可行的。

```javascript
let user = {
  name: "John",
  age: 30
};

let clone = {}; // the new empty object

// let's copy all user properties into it
for (let key in user) {
  clone[key] = user[key];
}

// now clone is a fully independent clone
clone.name = "Pete"; // changed the data in it

alert( user.name ); // still John in the original object

// 或是使用 Object.assign
Object.assign(dest, [src1, src2, src3...])

let user = { name: "John" };

let permissions1 = { canView: true };
let permissions2 = { canEdit: true };

// copies all properties from permissions1 and permissions2 into user
Object.assign(user, permissions1, permissions2);

// now user = { name: "John", canView: true, canEdit: true }

// use Object.assign
let user = {
  name: "John",
  age: 30
};

let clone = Object.assign({}, user);

// 以上方法是用在物件的屬性為原始值，若屬性包含物件會指向相同記憶體。
let user = {
  name: "John",
  sizes: {
    height: 182,
    width: 50
  }
};

let clone = Object.assign({}, user);

alert( user.sizes === clone.sizes ); // true, same object

// user and clone share sizes
user.sizes.width++;       // change a property from one place
alert(clone.sizes.width); // 51, see the result from the other one

// 為了解決屬性也是物件的問題，可以使用函式庫 lodash 的函式 .cloneDeep(obj)
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://mistborn.gitbook.io/til-coding/javascript/objects.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
