--- 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 的原型方法 ``` ![](https://i.imgur.com/RD1zaje.png) <span class="green">**在 String 這個建構函式上新增新的原型方法**</span> ![](https://i.imgur.com/I38qOTR.png) ### 原型 與 純值 * 純值會有一個包裹物件,包裹物件就是他的原始型別 * 以數字來說,包裹物件就是 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 方法) ``` ![](https://i.imgur.com/8AbaDDg.png) ### 建構式 : 日期 - 嘗試在 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') 得到結果會是不可寫入。 ![](https://i.imgur.com/HKw0uVZ.png) ## :memo: 學習回顧 :::info * 純值會有一個包裹物件,包裹物件就是他的原始型別 * 以數字來說,包裹物件就是 number * 以字串來說,包裹物件就是 string * 原型是共用的,當原型加入其他方法後,此純值的原型也會跟著套用 * **" 加 "** 運算子功能 * 數值相加 * 字串串接 * 相加過程中,如果數值遇到了 '字串' 型別,就會一律轉為字串型別做串接 * function 會自動帶上一個 name 的屬性,此屬性不可寫入。 ::: <style> .red { color: red; } .green { color: green; } </style>