定義
?使用原型實體指定創建物件的種類,并且通過拷貝這些原型創建新的物件,原型模式是一種物件創建型模式---百科,
?通俗的說就是原型模式是一種創建型設計模式,指定某個物件(通過某種方式)得到一個新的物件,在記憶體中擁有新的地址,得到的物件與原物件是是相互獨立的,即得到跟原物件一樣的物件
?當我們需要兩個一模一樣的實體時,使用原型模式非常方便,如果不使用原型模式,按照建構式的方式初始化物件,我們需要傳兩次一模一樣的引數如:
const dog = new BydCard('byd', '漢', '30w', '2023款')
const dog_copy = new BydCard('byd', '漢', '30w', '2023款')
// 使用原型模式
const dog_copy1 = Object.create(dog)
實作思路
??通過目標物件得到一個全新的新物件,使新物件也具備跟目標物件一樣的能力,這種一般思路有兩種
- 深拷貝
- 指標參考:自身物件找不到,通過內部屬性參考到目標物件上去找類似鏈表結構的
next指標
其中大多數后臺語言如java 有相關克隆介面規范,javaScript 是通過第二種方式來實作的,
javaScript 中的原型模式
??在原型模式下,當我們想要創建一個物件時,會先找到一個物件作為原型,然后通過克隆原型的方式來創建出一個與原型一樣(共享一套資料/方法)的物件,在 JavaScript 里,Object.create方法就是原型模式的天然實作——準確地說,只要我們還在借助Prototype來實作物件的創建和原型的繼承,那么我們就是在應用原型模式,
??有的設計模式資料中會強調,原型模式就是拷貝出一個新物件,認為在 JavaScript 類里實作了深拷貝方法才算是應用了原型模式,事實上在 JavaScript 中,通過指標的方式也可以得到目標物件、屬性、方法的共享,克隆(深度拷貝)是實作這個目的的方法,但不是唯一的方法,也不是javaScript 的目的,
通過指標來參考,然后動態執行的時候系結背景關系 this,這樣就不會造成實體之間的錯亂,我覺得這也是this 被設計成動態系結的原因之一,
原型模式-編程范式
??原型模式不僅是一種設計模式,它還是一種編程范式(programming paradigm),是 JavaScript 面向物件系統實作的根基,原型編程范式的體現就是基于原型鏈的繼承,即便現在es6+ 推出了class 關鍵字,支持了類的寫法,引入的 JavaScript 類本質上還是基于原型的繼承的語法糖(class 只是一個語法糖),類語法不會為 JavaScript 引入新的面向物件的繼承模型, 當我們嘗試用 class 去定義一個 Dog 類時:
class Dog {
constructor(name ,age) {
this.name = name
this.age = age
}
eat() {
console.log('肉骨頭真好吃')
}
}
其實完全等價于寫了這么一個建構式:
function Dog(name, age) {
this.name = name
this.age = age
}
Dog.prototype.eat = function() {
console.log('肉骨頭真好吃')
}
原型鏈核心點
??每個建構式都擁有一個prototype屬性,它指向建構式的原型物件,這個原型物件中有一個 constructor 屬性指回建構式;每個實體都有一個內部屬性__proto__屬性,當我們使用建構式去創建實體時,實體的__proto__屬性就會指向建構式的原型物件,
// 輸出"肉骨頭真好吃"
dog.eat()
// 輸出"[object Object]"
dog.toString()
明明沒有在 dog 實體里手動定義 eat 方法和 toString 方法,它們還是被成功地呼叫了,這是因為當我試圖訪問一個 JavaScript 實體的屬性、方法時,它首先搜索這個實體本身;當發現實體沒有定義對應的屬性、方法時,它會轉而去搜索實體的原型物件;如果原型物件中也搜索不到,它就去搜索原型物件的原型物件,這個搜索的鏈表就叫做原型鏈,

Object 是所有的基類,其中Object.prototype指向null,這樣原型鏈就有終點了,而不是無腦的一直下去,
原型鏈其他關鍵點:
- 所有函式(普通函式,建構式,內置的函式)都是內置函式(類)
Function的實體,所以存在函式.__proto__=== Function.prototype所有函式都可以直接呼叫Function原型上的方法(call / apply /bind) - Function 確實很厲害,他不僅是函式的類,還是自己的類,函式是Function 的實體,Function 也是Function 的實體
Object.__proto__ === Function.prototype,Function.__proto__===Function.prototype - 物件的原型鏈最終指向
Object.prototype,object.prototype._proto_指向null
如下代碼驗證了這些結論:
function sayHi () {
// console.log('hello joel')
}
// 所有函式都是Function 的實體即函式也是物件,
// 所以存在函式.__proto__ === Function.prototype
console.log(sayHi.__proto__ === Function.prototype) // true
console.log(Object.__proto__ === Function.prototype) // true
console.log(String.__proto__ === Function.prototype) // true
console.log(Array.__proto__ === Function.prototype) // true
console.log(Number.__proto__ === Function.prototype) // true
console.log(Symbol.__proto__ === Function.prototype) // true
// Function.prototype 內部屬性又指向Object的原型物件
console.log(Function.prototype.__proto__ === Object.prototype) // true
// Function 也是Function 的實體
console.log(Function.__proto__ === Function.prototype)
// 物件最終指向object的原型
console.log(new sayHi().__proto__ instanceof Object) // true
console.log(new sayHi().__proto__ === sayHi.prototype) // true
console.log(Array.prototype.__proto__ === Object.prototype) // true
console.log(Object.__proto__.__proto__ === Object.prototype) // true
// 內置的array,string,number,object 等都是建構式,同時也是物件
console.log(typeof Array) // function
console.log(typeof Object) // function
// 通過原型鏈找到object.prototype 上的方法
sayHi.valueOf()
小結
- 原型是 JavaScript 面向物件系統實作的根基,在這里更像是一種編程范式
- 在JavaScript 中原型模式無處不在,只要使用原型的模型創建物件就是在使用原型模式
Object.__proto__ === Function.prototype
Function.__proto__=== Function.prototype
Function.prototype.__proto__ === Object.prototype
Object.prototype.__prto__ === null
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/546360.html
標籤:其他
上一篇:前端設計模式——中介者模式
