成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

如何用原型鏈的方式實現一個 JS 繼承?

開發 前端
JavaScript 中,每當創建一個對象,都會給這個對象提供一個內置對象 [[Prototype]] 。這個對象就是原型對象,[[Prototype]] 的層層嵌套就形成了原型鏈。

大家好,我是前端西瓜哥。今天講一道經典的原型鏈面試題。

原型鏈是什么?

JavaScript 中,每當創建一個對象,都會給這個對象提供一個內置對象 [[Prototype]] 。這個對象就是原型對象,[[Prototype]] 的層層嵌套就形成了原型鏈。

當我們訪問一個對象的屬性時,如果自身沒有,就會通過原型鏈向上追溯,找到第一個存在該屬性原型對象,取出對應值。

當然原型鏈不是無止境的,和單鏈表一樣,最后一個原型對象的值是 null,原型鏈的所有對象都找不到指定的屬性時,我們會拿到 undefined。

[[Prototype]] 雖然無法通過腳本進行訪問,但大多數瀏覽器提供了 __proto__ 屬性來訪問這個內置對象,但它并不是標準,無法兼容所有瀏覽器。

下面來舉幾個例子,讓讀者對原型鏈有一個直觀的認識:

  • 通過對象字面量聲明 a = {} 時, a 的 [[prototype]] 就是 Object.prototype。此時的原型鏈是:a -> Object.prototype -> null。這里有個易錯點,就是以為 a 的上一個原型對象是 Object,其實并不對,Object 其實只是一個構造函數。
  • 聲明數組 arr = [1, 2, 4],它的原型鏈則是 arr -> Array.prototype -> Object.prototype -> null。
  • Object.create(null) 甚至能夠創建一個連 [[prototype]] 都沒有的真正的空對象,一般用于做字符串哈希表,比如 vue 源碼里就能經??吹?。

通過構造函數創建實例對象

在 JavaScript 中,一個函數會在 new 關鍵字的配合下成為構造函數。也就是說,任何一個函數都可以成為構造函數。

當聲明一個構造函數時,它會有一個屬性名為 prototype 的對象(和 [[prototype]] 是不同的東西),這個對象就是 原型對象。這個對象的 constructor 又反過來指向構造函數。

當我們對使用 new 關鍵字創建對象,被創建的對象的 [[prototype]] 會指向這個 prototype。

function Rect() {}
const rect = new Rect()
rect.__proto__ === Rect.prototype // true
Rect.prototype.constructor === Rect // true

只要是通過 new Rect() 創建的對象,無論多少次,它的 [[prototype]] 都是指向 Rect.prototype。另外,Rect.prototype.prototype 指向的是 Object.prototype。

這樣,通過給構造函數的原型對象(Rect.prototype)添加一些方法(如 Rect.prototype.draw),就能讓創建的多個實例對象共享同一個方法,減少內存的使用。

用原型鏈的方式實現繼承

理解了構造函數如何影響創建的實例的原型鏈后,我們來探討一下核心問題,如何使用原型鏈來實現繼承。

假設我們有一個 Shape 構造函數(父類)和 Rect 構造函數(子類)。代碼如下:

// 父類
function Shape() {}
Shape.prototype.draw = function() {
console.log('Shape Draw')
}
Shape.prototype.clear = function() {
console.log('Shape Clear')
}
// 子類
function Rect() {}
/**
實現繼承的代碼放這里
**/
Rect.prototype.draw = function() {
console.log('Rect Draw')
}

通過前面的學習,我們知道,正常情況下使用 new Rect 創建的實例對象,它的原型鏈是這樣的:

rect -> Rect.prototype -> Object.protoype -> null

現在我們要實現的繼承,其實就是在原型鏈中間再加一個原型對象 Shape.prototype。對此我們需要對 Rect.prototype 進行特殊的處理。

方法1:Object.create

Rect.prototype = Object.create(Shape.prototype)
Rect.prototype.constructor = Rect // 選用,如果要用到 constructor

Rect.prototype.constructor = Rect // 選用,如果要用到 constructor

Object.create(proto) 是個神奇的方法,它能夠創建一個空對象,并設置它的 [[prototype]] 為傳入的對象。

因為我們無法通過代碼的方式給 [[prototype]] 屬性賦值,所以使用了 Object.create 方法作為替代。

因為 Rect.prototype 指向了另一個新的對象,所以把 constructor 給丟失了,可以考慮把它放回來,如果你要用到的話。

缺點是替換掉了原來的對象。

方法2:直接修改 [[prototype]]

如果就是不想使用新對象,只想修改原對象,可以使用 廢棄 的 __proto__ 屬性,但不推薦。

不過另外還有一個方法 Object.setPrototypeOf() 可以修改對象的 [[prototype]],但因為性能的問題,也不推薦使用。

Object.setPrototypeOf(Rect.prototype, Shape.prototype)
//
Rect.prototype.__proto__ = Shape.prototype

都不推薦使用,但確實能用。

方法3:使用父類的實例

Rect.prototype = new Shape()

形成的原型鏈為:

rect -> shape(替代掉原來的 Rect.prototype-> Shape.prototype -> Object.prototype -> null

基本能用,缺點是會產生副作用,就是執行 new Shap() 可能會出現副作用,比如給創建的對象添加了一些屬性、發送了請求之類的,完全取決于構造函數內的代碼。

某種意義上,這個缺點是致命的。不推薦使用。

總結

用原型鏈的方式實現一個 JS 繼承,其實就是希望構造函數 Son 創建出來的對象 son,它的原型鏈上加上父類 Parent.prototype,所以最后就是要修改 Son.prototype 的 [[prototype]]。

鑒于性能、兼容性、副作用等考慮,推薦使用方法 1,即通過 Object.create(Parent.prototype) 創建一個指定了 [[prototype]] 的新對象,替換掉原來的 Son.prototype 指向的對象。

總結幾個核心知識點:

  • 任何對象都有 [[prototype]] 屬性,讀寫對象屬性發現當前對象不存在時,會訪問 [[prototype]] 指向的對象嘗試訪問屬性,于是原型鏈形成了。
  • 函數創建時,它的 prototype 屬性會拿到一個原型對象。當函數作為構造函數,通過 new 創建一個新對象時,這個新對象的 [[prototype]] 會指向這個原型對象。
  • JS 要實現 “類” 繼承,本質是通過處理構造函數的 prototype 對象來修改原型鏈。
責任編輯:姜華 來源: 今日頭條
相關推薦

2022-06-20 09:22:55

js原型鏈前端

2023-02-26 01:37:57

goORM代碼

2016-09-06 19:45:18

javascriptVue前端

2017-03-20 17:59:19

JavaScript模板引擎

2019-02-27 16:00:48

JS原型原型鏈對象

2020-09-10 07:04:30

JSJavaScript 原型鏈

2017-03-15 08:43:29

JavaScript模板引擎

2021-05-27 08:21:51

JS繼承對象

2021-09-13 06:03:42

CSS 技巧搜索引擎

2016-11-03 08:57:02

javascriptjquerynode.js

2020-10-26 08:19:53

算法隊列

2018-06-22 10:30:56

C語言虛擬機編譯器

2020-04-29 14:40:19

JavaScript繼承編程語言

2017-05-02 11:30:44

JavaScript數組惰性求值庫

2023-12-30 13:33:36

Python解析器JSON

2022-11-07 11:27:00

JS游戲開發

2022-09-13 08:01:58

短鏈服務哈希算法字符串

2020-02-20 14:00:15

JavaScript原型原型鏈

2018-03-23 10:00:34

PythonTensorFlow神經網絡

2011-08-31 14:48:33

JavaScript
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 国产剧情一区二区三区 | 麻豆天堂 | 免费一级淫片aaa片毛片a级 | 91av国产在线视频 | 毛片久久久 | 亚洲乱码一区二区三区在线观看 | 国产乱一区二区三区视频 | 国产露脸对白88av | 久久精品国产亚洲a | 欧美一级免费看 | 国产成人精品视频 | 犬夜叉在线观看 | 污片在线观看 | 福利网址 | 亚洲一区二区在线视频 | 久久99精品视频 | 日日艹夜夜艹 | 精品国产一级 | 中日av| 一级免费毛片 | 69热视频在线观看 | 久久久精品网站 | 真人女人一级毛片免费播放 | 成人国产午夜在线观看 | 国产精品久久久久久久一区探花 | 三级视频在线观看 | 中文字幕亚洲一区二区三区 | 久久婷婷国产 | 99精品欧美一区二区三区综合在线 | 在线免费看毛片 | 亚洲一区二区在线 | 99精品在线 | 久色视频在线 | 91久久精品一区二区二区 | 在线一区视频 | 国产成人黄色 | 福利片在线看 | 国产精品久久久久国产a级 欧美日韩国产免费 | 国产精品一区二区av | 特黄av| 亚洲视频免费在线观看 |