# Javascript第六章 物件與陣列
###### tags: `JS X Codeshiba`
## 何謂物件
所有基本型別(Primitives)以外的值都是物件
定義: An object is a collection of properties and has a single prototype object.
**物件** 可以是 **零至多種屬性的集合**
**屬性** 鍵(Key)與值(Value)之間的關聯,值可以是另一個物件,甚至可以是一個函數
不可變的基本型態只能代表一個值,物件可以代表多個或複合值,而且可以在它的生命週期中改變
```javascript=
const obj = {};
```
## 如何宣告物件
物件的內容叫做屬性(Property)或成員(Member)
1. 用大括號宣告
2. 一個(鍵)Key對應一個值(Value)
3. 值又稱為屬性(attribute)


第一種
```Example1
var person = new object();
person.name = "Kuro";
person.job = 'Front-end developer';
person.sayName = function(){
alert(this.name);
};
```
第二種 較為常見~
物件實字(Object literal),也是JSON格式的核心語法
```Example2
var person = {
name: 'Kuro',
job: 'Front-end developer',
sayName: function() {
alert(this.name);
}
}
console.log(person);
```

**請注意**
宣告物件時,內部的key和value的寫法為
key : value 中間用 , 來分隔
而不是 key = value 然後中間用 ; 來分隔
## 如何存取物件的屬性?
屬性名稱必須是有效的識別碼,如果特性名稱不是有效的識別碼,就必須使用計算成員存取(computed member access)運算子
方法一: 可以透過.的方式
```Example
var person = {
name: 'Kuro',
job: 'Front-end developer',
sayName: function() {
alert(this.name);
}
}
console.log(person);
person.name="Steven";
person.job="No job";
console.log(person);
```

方法二: 可以透過[""]或是['']的方式
```
var person = {
name: 'Kuro',
job: 'Front-end developer',
sayName: function() {
alert(this.name);
}
}
console.log(person);
person["name"]='Lukas';
person["job"]='Instructor';
console.log(person);
```

用方法一時,如果有不允許的命名方式,則會被糾錯出來

## 如何抓取變數內的資料

如果是function,則需要加上()才可以運作喔

## 如何增加屬性
可以透過'.屬性名稱'即可增加屬性
```
obj.age='13';
```

## 如何刪除屬性
可以透過delete來刪除屬性
```
delete obj.age;
```

## 物件內還有物件?
```javascript=
const sam1 = {
name: 'Sam',
age: 4,
};
const sam2 = {
name: 'Sam',
age: 4
};
//特性值可以是物件
const sam3 = {
name: 'Sam',
classification: {
kingdom: 'Anamalia',
phylum: 'Chordata',
class: 'Mamalia',
order: 'Carnivoria',
family: 'Felidae',
subfamily: 'Felinae',
genus: 'Felis',
species: 'catus',
},
};
```
```javascript=
// 如何呼叫物件內的物件屬性?
sam3.classification.family;
sam3["classification"].family;
sam3.classification["family"];
sam3["classification"]["family"];
```
## 把函式加入物件
```javascript=
sam3.speak = function(){
return "Meow!";
};
sam3.speak(); //即可呼叫函式
```
## 判斷屬性是否存在
只要是不存在的屬性,都會回傳undefined,若是想要判斷屬性是否存在,但如果剛好屬性是undefined時,就沒用了...
此時可以使用hasOwnProperty來確認屬性的狀態
```
obj.hasOwnPeroperty('name')
```

```
<script type=text/javascript>
//建立空白物件
var point=new object();
```
```
//建立物件的成員(屬性與方法)
point.x=3;//屬性
point.y=4;
point.getPosition=function(){//方法
alert(this.x+","+this.y);
};
```
```
//使用物件
point.getPosition();
```
綜合範例:遊戲中的玩家設計
```
//物件的設計
var player=now object();
player.name="john";
player.hp=100;
player.fight=function(){
this.hp=this.hp-2;
};
player.rest=function(){
this.hp++;
};
player.report=function(){
alert(this.name+":"+this.hp);
};
```
```
//物件的使用
player.fight();
player.rest();
player.report();
</script>
```
按照上述的做法,每建立一隻角色就要重新寫一次
使用this代表新建的空白物件
可以使用該手法來方便創建新的角色
```
<script type=text/javascript>
function PlayerModel(name,hp,atk) {
this.name=name;
this.hp=hp;
this.atk=atk;
this.fight=function() {
this.hp-=2;
};
this.rest=function() {
this.hp++;
};
this.report=function() {
alert(this.name+" hp: "+this.hp+" atk: "+this.atk);
};
}
var player = new PlayerModel("Steven", 100, 20);
player.fight();
player.fight();
player.fight();
player.fight();
player.fight();
player.fight();
player.report();
</script>
```
## 數字、字串與布林物件
數字、字串與布林都有對應的物件型態(Number、String與Boolean)
這些物件有兩種目的:
1. 儲存特殊的值(e.g. Number.INFINITY)
2. 以函式的形式來提供功能
```javascript=
const s = "hello";
s.toUpperCase(); //"HELLO"
```
看起來好像s變成了一個物件,但是這只是暫時性的,並不是s真的成為一個物件
```javascript=
const s = "hello";
s.rating = 3;
s.rating; //undefined
```
## 陣列介紹
陣列,是種「特別」的物件,沒有規定只能放甚麼東西進去,同一個陣列可以是原始的資料類型、另一個陣列、物件甚至是函式等等。
與物件不同的是,陣列是有順序性的集合,且鍵(key)是數字,所以只能透過[]加上索引來存取



## 刪除陣列最後一個元素(pop)

## 陣列特性
1. 陣列大小是不固定的,可以隨時新增或移除元素
2. 陣列內容不一定是同一種型態,每一個元素都可以使用任何型態
3. 陣列是從0開始的,也就是說,陣列的第一個元素是元素0
## 新增陣列元素
可以透過new array的方式來新增
並透過length或console.log的方式來驗證
```Example
var a = new Array();
a[0] = "apple";
a[1] = "boy";
a[2] = "cat";
a.length;
console.log(a.length);
console.log(a);
```

亦可以透過陣列實字(Array Literal)的方式來進行
```Example
var a = [];
a[0] = "apple";
a[1] = "boy";
a[2] = "cat";
console.log(a.length);
console.log(a);
```

或是直接賦值的方式亦可
```Example
var a = ["apple","boy","cat"];
console.log(a.length);
console.log(a);
```

陣列的內容也可以透過length來覆寫,操作後的內容則無法回復
```Example
var a = ['apple','boy','cat'];
a.length=1;
console.log(a);
a.length=3;
console.log(a);
```

## 透過索引新增、修改與提取陣列元素
有趣的是,可以透過索引直接新增,但不用依循連續的原則來指定,中間未指定的變數會用undefined呈現
```Example
var a = ['apple','boy','cat'];
console.log(a.length);
a[7] = 'z';
console.log(a);
```


或是用push來新增元素
```Example
a.push('yoyo','girl','nana')
console.log(a);
```

## 獲取陣列索引值

## 切片的手法

## 陣列的進階手法 map()
可以透過map來修改陣列的呈現內容


## 如何透過for迴圈來修改陣列?

那如何回傳for迴圈的修改結果呢?


## 如何把陣列內所有內容讀過一遍? forEach()
forEach()的基本用法

無法直接把結果賦值給變數形成陣列,跟map不一樣

用for迴圈重現結果

## 如何列出陣列中符合條件的元素? filter()
filter()的基本用法

包含不同資料類別的陣列型態如何搜尋?

## 查找資料中的第一筆資料(VLOOKUP) find()
類似filter()的功能,但其實有些差異

## 甚麼是Array.prototype?
Array.prototype
[MDN的資料](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/prototype)
```
表示 Array 構造函数的原型,允許向所有Array對象添加新的属性和方法。
```
## 用reduce()來計算陣列元素的加總結果

可以透過瀏覽器內建的監控視窗來增加變數來看相關的變化
重新整理後就可以持續看相關的變化

## 物件與陣列的最後一個逗號
```javascript=
const arr = [
"One",
"Two",
"Three",
];
const 0bj = {
one : 1,
two : 2,
three : 3,
}
```
使用最後的逗號代表永遠不需要在前一行程式碼加上逗號,但這並非必須
例如JavaScript物件標記法(JavaScript Object Notation,JSON)是一種常用的JavaScript式資料與法,它不容許最後的逗號。
## 日期
JavaScript的日期和時間是用內建的Date物件來表示的。
```javascript=
const now = new Date();
now;
//main.js:33 Sat Apr 03 2021 23:36:40 GMT+0800 (GMT+08:00)
```
建立一個具有特定日期的初始值
```javascript=
//注意月份是從0開始的,所以10月等於9月
const halloweenParty = new Date(2021, 9, 31);
//Sun Oct 31 2021 00:00:00 GMT+0800 (GMT+08:00)
```
建立一個具有特定日期與時間的初始值
```javascript=
const halloweenParty = new Date(2021, 9, 31, 19, 0);
console.log(halloweenParty);
//Sun Oct 31 2021 19:00:00 GMT+0800 (GMT+08:00)
```
也可以取出內部的元件
```javascript=
console.log(halloweenParty.getFullYear()); // 2021
console.log(halloweenParty.getMonth()); // 9
console.log(halloweenParty.getDay()); // 0
console.log(halloweenParty.getDate()); // 31
console.log(halloweenParty.getHours()); // 19
console.log(halloweenParty.getMinutes()); // 0
console.log(halloweenParty.getSeconds()); // 0
console.log(halloweenParty.getMilliseconds()); // 0
```
## 正規表達式
正規表達式(regular expression),簡稱regex或regexp,為JS的一種子語言,是許多程式語言會提供的擴充語言
[參考資料-email識別器](https://dezchuang.github.io/2017/07/05/022_regexp_1/)
## 資料型態轉換
### 轉換成數字
1. 使用Number物件建構式
在使用建構式時,不會不使用new關鍵字,所以這算是特殊案例
```javascript=
const numStr = "33.3";
const num = Number(numStr); //這會建立一個數字值
```
2. 使用內建的parseInt和parseFloat函式
使用parseInt時,可以指定一個radix,這是被解析的數字基數
```javascript=
const a = parseInt("16 volts" , 16);
//忽略文字,直接以基數來解析
const b = parseInt("3a", 10);
//以16進位解析,結果為58
const c = parseFloat("15.5 kph");
//一定會假設基數為10
```
Date物件可以用valueOf()來轉換成一組數字,代表從1970年1月1日午夜算起的毫秒數
```javascript=
const d2 = d.valueOf();
console.log(d2);
//1617466405820
```
### 轉換成字串
JS裡面所有物件都有toString的方法,它會回傳字串表示形式。使用toString()的方法,可以把數字轉換成文字
```javascript=
const e = 33.5;
const f = [1, true, "yoyo"];
e1 = e.toString();
f1 = f.toString();
console.log(e1); //33.5
console.log(f1); //1,true,yoyo
```
### 轉換成布林
```javascript=
const n = 0;
const b1 = !!n; //使用兩個Not運算子(!)來把任何值轉成Boolean
const b2 = !n; //使用一個Not運算子(!)也可以轉成Boolean,但結果會相反
const b3 = Boolean(n); //使用布林建構式(結果: false)
console.log(b1);
console.log(b2);
console.log(b3);
```
## 結論
1. JS內的所有數字都是雙精確度浮點數
2. 我們常用的其他資料型態(日期、map、set、正規表達式)都是特殊的物件型態
3. 掌握字串樣板與轉義,會是本章的學習重點