摘要:此用來定義通過構造器構造出來的對象的原型,構造器內(nèi)部的代碼用來給對象初始化。
對象繼承 VS 類繼承
在 class-based 的面向?qū)ο蟮氖澜缋铮霈F(xiàn)對象,必須先有類。類之間可以繼承,類再使用 new 操作創(chuàng)建出實體,父子對象之間的繼承體現(xiàn)在父類和子類上。你不能說 對象 a 繼承了對象 b,只能說 class A 繼承了 class B,然后他們各自有一個實例a、b。
JS中實現(xiàn)的是原型繼承。在 prototype-based 的面向?qū)ο蟮氖澜缋铮^承是對象之間的事情,就像現(xiàn)實世界里,兒子繼承父親,沒必要非得整出父親類、兒子類。你有一個對象 a,通過 b = Object.create(a) (或者用類似的polyfill)創(chuàng)建出一個繼承了 a 對象的實體 b。a 對象的屬性和方法甚至后期對 a 的屬性和方法修改,b 對象都直接繼承過來。這里,我們說,a對象是b對象的原型。我們發(fā)現(xiàn),這樣的繼承方式不需要類,繼承完全在對象間完成。
原型繼承的工作機制在對象屬性查找時,如果對象本身存在這個屬性,會優(yōu)先使用它自己的(也就是概念 ownProperty);如果沒有,就會查找對象的原型上有沒有這個屬性;如果原型對象也有自己的原型,遞歸查找,直到原型的根部,沒有原型了停止查找,如果還是不存在,則返回 undefined。這就是傳說中的 原型鏈,這也是 JS 中對象繼承的體現(xiàn)方式,原型存在的意思。
這里順帶說一下如何獲取一個對象的原型。ES5 提供了 Object.getPrototypeOf(obj) 方法來獲取一個對象的原型,在 Chrome 中也可以使用非標準的 obj.__proto__。
JS 在 prototype-based 的面向?qū)ο蟮幕A上,引入了 構造器 來模擬 class-based 的模式, 配合 new 操作符使用。 構造器和 已有的 prototype 概念如何配合工作呢?
我們知道,JS 中的構造器就是一個普通函數(shù),但是這個函數(shù)有一個特殊的屬性(函數(shù)也是對象,所以也有屬性) ———— prototype。此 prototype 用來定義通過構造器構造出來的對象的原型,構造器內(nèi)部的代碼用來給對象初始化。
function Ctor() {} console.dir(Ctor.prototype); // 構造器的 prototype 屬性,默認值是 // { constructor: Ctor } Ctor.prototype.method = function() { console.log(1) } instance = new Ctor(); instance.constructor // Ctor instance.method() // console.log(1)
instance 是如何獲得 Ctor 的 prototype 屬性上的數(shù)據(jù)的呢?好,還記得 JS 中的繼承都是對象之間的繼承嗎?我們翻譯一下 new 操作符到底干了什么。
instance = new Ctor() // 等價于 instance = Object.create(Ctor.prototype) // 用 Ctor 的 prototype 作為原型來創(chuàng)建一個新對象 Ctor.apply(instance) // 執(zhí)行構造器用來初始化,構造器中的 this 指向 instance
我們稱, instance 的原型是 Ctor.prototype, instance 是 Ctor 構造出來的 (new 出來的).
為了讓 instance.constructor 能正確指向 instance 的構造器,一個構造器默認的 prototype 上已經(jīng)存在 constructor 屬性,并且指向構造器本身了。在我們覆蓋構造器的 prototype 屬性時,記得要把 prototype.constructor 屬性定義了,讓它指回到構造器,否則構造出來的 instance 的 constructor 屬性就出問題了。所以我們可以看出,instance.constructor 其實是不是 instance 自己的屬性,是原型鏈上定義的。
這里千萬不要把 Ctor.prototype 誤理解為是 Ctor 的原型。Ctor 的原型是 Object.getPrototypeOf(Ctor)(非標準寫法:Ctor.__proto__),它是 Function.prototype, 因為 Ctor 是一個函數(shù)對象,所有函數(shù)都構造自 Function,原型是 Function.prototype。Ctor.prototype 是 Ctor 構造出來的實例的原型,不是 Ctor 的原型。
Object & Function 雞生蛋蛋生雞有代碼如下:
Object instanceof Function // true Function instanceof Object // true // what???
我們來挖掘一下 instanceof 操作符底層邏輯:
instance instanceof Ctor // 等價于 function instanceOf(instance, prototype) { var proto = Object.getPrototype(instance); // 取對象原型 if( proto === null) return false; // 空 if( proto === prototype) return true; // 原型匹配 return instanceOf(proto, prototype); // 遞歸檢查原型的原型 } instance(instance, Ctor.prototype);
JS 中的繼承終歸是原型的繼承,所以 class-based 中的 instanceof 概念最終也需要映射到 prototype 上。但是 JS 中的構造器名稱有一個特殊之處,這個名稱既表示了構造器這個函數(shù),又表示了 class-based 概念中的 類 的概念, 而函數(shù)本身又是一種特殊的對象。
Object instanceof Function 之所以為 true,我們是把 Object 當做構造器看待,它是一個函數(shù),它是 Function 的實例,所以同時這里我們把 Function 當作類型來看待,它是所有 function 的類。
Function instanceof Object 之所以為 true,我們是把 Function 當作對象看待,它雖然是一個構造函數(shù),但是它也是對象,它是 Object 的實例,所以同時我們又把 Object 當作類型來看待,它是所有對象的類。
從原型角度:
// Object 是一個構造函數(shù),它的原型是 Function.prototype // Function.prototype 是所有函數(shù)的原型,call, apply 就掛在這里 Object.getPrototypeOf(Object) === Function.prototype // Function 也是一個構造函數(shù) Object.getPrototypeOf(Function) === Function.prototype // Function.prototype 本身是一個對象,所有對象的原型根部都是 Object.prototype Object.getPrototypeOf(Function.prototype) === Object.prototype
這也印證了 JS 中函數(shù)是對象的概念。
文章版權歸作者所有,未經(jīng)允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/91836.html
摘要:相當于在用原型繼承編寫復雜代碼前理解原型繼承模型十分重要。同時,還要清楚代碼中原型鏈的長度,并在必要時結束原型鏈,以避免可能存在的性能問題。 js是一門動態(tài)語言,js沒有類的概念,ES6 新增了class 關鍵字,但只是語法糖,JavaScript 仍舊是基于原型。 至于繼承,js的繼承與java這種傳統(tǒng)的繼承不一樣.js是基于原型鏈的繼承. 在javascript里面,每個對象都有一...
摘要:原型對象是由創(chuàng)建的,因此原型對象的構造函數(shù)是構造函數(shù)也可以是稱為對象,原型對象也就繼承了其生父構造函數(shù)中的數(shù)據(jù),也同時繼承了原型對象的數(shù)據(jù)。當然這條原型鏈中的數(shù)據(jù),會被還是還是這類構造函數(shù)繼承,但是不會被這些繼承,他們不處于同一個鏈條上。 js中,F(xiàn)unction的本質(zhì)是什么?Object的本質(zhì)又是什么?js中有幾條原型鏈? showImg(https://segmentfault.c...
摘要:除此之外,在超類型的原型中定義的方法,對子類型而言也是不可兼得,結果所有類型都只能用構造函數(shù)模式。創(chuàng)建對象增強對象指定對象繼承屬性這個例子的高效率體現(xiàn)在它只調(diào)用了一次構造函數(shù)。 1、原型鏈 原型鏈的基本思想是利用原型讓一個引用類型繼承另一個引用類型的屬性和方法。構造函數(shù)、原型和實例的關系:每個構造函數(shù)都有一個原型對象;原型對象都包含著一個指向構造函數(shù)的指針;實例都包含一個指向原型對象的...
摘要:原型鏈與繼承當談到繼承時,只有一種結構對象。如果對該圖不怎么理解,不要著急,繼續(xù)往下看基于原型鏈的繼承對象是動態(tài)的屬性包指其自己的屬性。當使用操作符來作用這個函數(shù)時,它就可以被稱為構造方法構造函數(shù)。 原型鏈與繼承 當談到繼承時,JavaScript 只有一種結構:對象。每個實例對象(object )都有一個私有屬性(稱之為proto)指向它的原型對象(prototype)。該原型對象也...
摘要:每一個由構造函數(shù)創(chuàng)建的對象都會默認的連接到該神秘對象上。在構造方法中也具有類似的功能,因此也稱其為類實例與對象實例一般是指某一個構造函數(shù)創(chuàng)建出來的對象,我們稱為構造函數(shù)的實例實例就是對象。表示該原型是與什么構造函數(shù)聯(lián)系起來的。 本文您將看到以下內(nèi)容: 傳統(tǒng)構造函數(shù)的問題 一些相關概念 認識原型 構造、原型、實例三角結構圖 對象的原型鏈 函數(shù)的構造函數(shù)Function 一句話說明什么...
閱讀 1080·2021-11-24 09:39
閱讀 1314·2021-11-18 13:18
閱讀 2443·2021-11-15 11:38
閱讀 1832·2021-09-26 09:47
閱讀 1632·2021-09-22 15:09
閱讀 1630·2021-09-03 10:29
閱讀 1515·2019-08-29 17:28
閱讀 2956·2019-08-29 16:30