---
title: 'JS 核心 23 - 原始型別的包裹物件與原型的關聯、課後練習'
tags: JS 核心 ,JS , JavaScript
description: 2021/02/19
---
JS 核心 -- 原始型別的包裹物件與原型的關聯
===
## 原型 與 純值的關係
### 宣告純值的方法一 : 使用包裹物件把字串a變大寫
定義純值 : 先宣告一個變數,並把他指向純值
> toUpperCase() 的方法源自於 String 的原型
```
var a = 'a';
console.log(a); // a
console.log(a.toUpperCase()); // A (使用包裹物件的方式把字串變大寫)
```
### 宣告純值的方法二 : 在 String 上新增新的原型方法
(第 1 行) String 本身是一個函式,必須搭配 new 運算子才能轉為建構式使用
> 以建構式建立一個看似純值的東西,但其實建立出來的是一個物件,非純值
> 不建議以建構式方式建立純值,浪費效能
```typescript=
var b = new String('bcde'); // 此方式定義的是物件型別 (可看到包裹物件的所有方法),非純值
console.log(b); // (如下左圖) b 有一個原型,裡面有所有方法
console.dir(String); // (如下右圖) String 本身是一個函式,有屬於自己的 prototype
console.dir(String.prototype === b.__proto__); // true
// 在 String 這個建構函式上新增新的原型方法
String.prototype.lastText = function() { // 修改包裹物件的原型方法
return this[this.length - 1]; // e ( 取出最後一個字元 )
}
console.log(b.lastText()); // 取用 String 的原型方法
```

<span class="green">**在 String 這個建構函式上新增新的原型方法**</span>

### 原型 與 純值
* 純值會有一個包裹物件,包裹物件就是他的原始型別
* 以數字來說,包裹物件就是 number
* 以字串來說,包裹物件就是 string
* 原型是共用的,當原型加入其他方法後,此純值的原型也會跟著套用
> 在純值對應的包裹物件新增方法,則純值就可以使用我們新增的方法
```
// var num = 5;
var num = new Number(5);
Number.prototype.secondPower = function() {
return this * this; // 新增平方的方法
}
console.log(num);
console.dir(Number);
console.log(num.secondPower()); // 25 (num 可套用上面所新增的 secondPower 方法)
```

### 建構式 : 日期 - 嘗試在 Date 原型新增方法
new Date() 是建構式,Date 本身也是函式
```typescript=
var date = new Date(); // new Date() 是建構式,Date 本身也是函式
console.log(date); // Fri Feb 19 2021 11:07:50 GMT+0800 (GMT+08:00)
console.dir(Date); // Date 本身是函式,有許多原型方法供使用
```
可以直接在原型上新增一個方法,用來取得所有時間
```typescript=4
Date.prototype.getFullDate = function() { // 在 Date 函式的 prototype 新增方法
var dd = String(this.getDate());
var mm = String(this.getMonth() + 1);
var yyyy = this.getFullYear();
var today = yyyy + '/' + mm + '/' + dd; // 組裝日期
return today;
}
console.log(date.getFullDate()); // 2021/02/19
```
**Q : yyyy 也是 number 型態,為什麼不用使用 String(),轉換成字串 ?**
A : + 這個符號除了數值相加以外,另外具有字串串接的功能,相加過程中,如果數值遇到了 '字串' 型別,就會一律轉為字串型別做串接,因此不需要另外轉型勒。
---
## :pencil2: 繼承與原型鍊 - 章節作業
練習必須透過 Object.create 方式實作多層繼承的原型,可以自行思考一個多層級的主題撰寫。
```
// 底層是冰箱、電視,有各自的方法(可以冷藏 xxx 、可以觀看 xxx)
// 上一層是家電,會耗電
// 最頂層是物件
Refrigerator <
|- HomeAppliance < Object
Television <
```
* 條件:
* 必須使用 Object.create
* 結構必須正確
* 每個原型需有獨立的方法
```
function HomeAppliance(callName){ // 建構函式
this.callName = callName || '家電';
}
function Refrigerator(name, color, use){
HomeAppliance.call(this, '冰箱');
this.name = name;
this.color = color || '白色';
this.use = use || '可能壞掉了';
}
Refrigerator.prototype = Object.create(HomeAppliance.prototype);
Refrigerator.prototype.constructor = Refrigerator;
function Television(name, color, use){
HomeAppliance.call(this, '電視');
this.name = name;
this.color = color || '黑色';;
this.use = use || '可能壞掉了'
}
Television.prototype = Object.create(HomeAppliance.prototype);
Television.prototype.constructor = Television;
Television.prototype.ok = function () {
return this.name + this.callName + '要修理了';
}
var ref = new Refrigerator('國際牌', '白色', '可以冷藏')
var tv = new Television('東元', '黑色', '可以觀看')
console.log(ref);
// Refrigerator {callName: "冰箱", name: "國際牌", color: "白色", use: "可以冷藏"}
console.log(tv);
// Television {callName: "電視", name: "東元", color: "黑色", use: "可以觀看"}
console.log(tv.ok()); // 東元電視要修理了
```
## :pencil2: 繼承與原型鍊 - 課後練習
以下範例需貼至「開發人員工具」的 "console" 才可執行。
```
function sayHi () {
var name = 'Casper';
return name;
}
sayHi.name = 'Mark';
sayHi.__proto__.hello = function() {
return this.name;
}
console.dir(sayHi); // (如下圖) 來看一下 sayHi 的函式內容
console.log(sayHi.hello()); // sayHi
```
1. 透過 function 所建立的函式,會帶上一個 name 的屬性,因此 console.dir(sayHi) 可以看到 name: "sayHi"。
2. 這個 name 屬性有點特別,他是不可被變更的,可以使用以下方法檢視 Object.getOwnPropertyDescriptor(sayHi, 'name') 得到結果會是不可寫入。

## :memo: 學習回顧
:::info
* 純值會有一個包裹物件,包裹物件就是他的原始型別
* 以數字來說,包裹物件就是 number
* 以字串來說,包裹物件就是 string
* 原型是共用的,當原型加入其他方法後,此純值的原型也會跟著套用
* **" 加 "** 運算子功能
* 數值相加
* 字串串接
* 相加過程中,如果數值遇到了 '字串' 型別,就會一律轉為字串型別做串接
* function 會自動帶上一個 name 的屬性,此屬性不可寫入。
:::
<style>
.red {
color: red;
}
.green {
color: green;
}
</style>