# JavaScript Object 操作方法

ES5 之前 Object 的 key 只能是字串的形式，但到了ES6 之後支援其他的格式，`Symbol` 定義的這種特殊單一的格式，並且不允許轉型。

### 迭代物件 Object property 的方法

1. **for-in**，會遍歷每個 **enumerable** (可列舉的) property，但不為 Symbol 的 property。
    

跟 `Object.key()` 差別在於 for-in 會迭代到繼承的 property。

> 不可列舉的意思：使用 for-in 或是 Object.keys 會找不到該屬性。

```jsx
// for in

let rectangle = { width: 20, height: 5 };

let customRectangle = Object.create(rectangle);
customRectangle.color = 'purple';
customRectangle.name = 'myCustom';

for (const key in customRectangle) {
  console.log(key, customRectangle[key]);
}
// color purple
// name myCustom
// width 16
// height 9
```

怎麼把屬性設定成不可列舉？ 使用 **Object.defineProperty**。

```jsx
'use strict'

// enumerable: true
let obj = {}
objec['key'] = 'value'

// enumerable: false
Object.defineProperty(obj, 'key', { enumerable: false })

// enumerable: true
Object.defineProperty(obj, 'key', { enumerable: true })
console.log(obj)

// Output:
//   { key: 'value' }
//   {}
//   { key: 'value' }
```

Object.hasOwnProperty() 確認 property 是否存在的方法，只會拿到 own property，不會拿到繼承的屬性。

```jsx

let rectangle = { width: 16, height: 9 };

let customRectangle = Object.create(rectangle);
customRectangle.color = 'blue';
customRectangle.name = 'myCustom';

for (const key in customRectangle) {
  console.log(key, customRectangle[key]);
}
// color blue
// name myCustom
// width 16
// height 9

// Object.prototype.hasOwnProperty()

for (const key in customRectangle) {
  if (customRectangle.hasOwnProperty(key)) {
    console.log(key, customRectangle[key]);
  }
}
// color blue
// name myCustom
```

1. **Object.keys()**
    

可以取得所有的 property name，並且以陣列的方式回傳。

```jsx
let object = {a: 1, b: 2, c: 3};

console.log(Object.keys(object));  // ["a", "b", "c"]
```

這個方法會忽略繼承而來的 property，也就是 Object.hasOwnProperty 為 false 的 property。

```jsx
let rectangle = {width: 16, height: 9};

let customRectangle = Object.create(rectangle);
customRectangle.color = 'blue';
customRectangle.name = 'myCustom';

Object.keys(customRectangle).forEach(key => {
  console.log(key, customRectangle[key]);
});
// color blue
// name myCustom
```

1. [**Array.property**](http://Array.property)**.forEach()** ...竟然也可以，要先拿到 property 組成的陣列
    

```jsx
let object = {a: 1, b: 2, c: 3};

Object.keys(object).forEach(key=> {
	console.log(key）})

// a
// b
// c
```

### 迭代物件 Object value 的方法

1. **Object.values()** 取得物件的所有值並且以陣列的方式回傳。
    

```jsx
let object = {a: 1, b: 2, c: 3};

console.log(Object.values(object));  // [1, 2, 3]
```

1. **Object.entries()** 一起取得 key 和 value，也以陣列的方式回傳。（有點像是 Python 的 tuple? )
    

```jsx
let object = {a: 1, b: 2, c: 3};

console.log(Object.entries(object));
// [
//   ["a", 1],
//   ["b", 2],
//   ["c", 3]
// ]
```

**Object.values()** 和 **Object.entries()** 跟 **Object.keys()** 一樣，都不會迭代到繼承的 property：

轉成陣列之後再使用 Array 的各種 Method 都很方便，`sort`, `reduce`, `join` 等等...，就是很讚！

```jsx
let fruitBasket = Object.entries(fruits)
  .map(([fruitName, fruitCount]) => {
    return {name: fruitName, count: fruitCount}
  });

console.log(fruitBasket);
// [
//   {name: "apple", count: 2},
//   {name: "banana", count: 3},
//   {name: "orange", count: 1}
// ]
```

### 將 Object 轉成 Map 物件的方法

使用 Object.entries() 取得 key 和 value 之後，丟到 new Map 的方法中。

```javascript
let fruits = {
  apple: 2,
  banana: 3,
  orange: 1
};

let fruitMap = new Map(Object.entries(fruits));

console.log(fruitMap);
// Map(3) {"apple" => 2, "banana" => 3, "orange" => 1}

console.log(fruitMap.get('orange'));  // 1
```
