摘要:相關名詞概念原型的所有對象中都包含了一個內部屬性,這個屬性所對應的就是該對象的原型的函數對象,除了原型之外,還預置了屬性當函數對象作為構造函數創建實例時,該屬性值將被作為實例對象的原型。
1 寫在前面
JavaScript中除了基本類型外的數據類型,都是對象。但是由于其沒有 類(class,ES6引入了class,但只是語法糖)的概念,如何將所有對象聯系起來就成了一個問題,于是就有了原型和原型鏈的概念。
2 為什么會有原型和原型鏈
1994年,網景公司(Netscape)發布了Navigator瀏覽器0.9版,但是剛開始的Js沒有繼承機制,更別提像同時期興盛的C++和Java這樣擁有面向對象的概念。在實際的開發過程中,工程師們發現沒有繼承機制很難解決一些問題,必須有一種機制能將所有的對象關聯起來。Brendan Eich鑒于以上情況,但不想把Js設計得過為復雜,于是引入了new關鍵詞和constructor構造函數來簡化對象的設計,引入了prototype函數對象來包含所有實例對象的構造函數的屬性和方法,引入了proto和原型鏈的概念解決繼承的問題。
JavaScript的所有對象中都包含了一個 [proto] 內部屬性,這個屬性所對應的就是該對象的原型
JavaScript的函數對象,除了原型 [proto] 之外,還預置了 prototype 屬性
當函數對象作為構造函數創建實例時,該 prototype 屬性值將被作為實例對象的原型 [proto]。
原型鏈當一個對象調用的屬性/方法自身不存在時,就會去自己 [proto] 關聯的前輩 prototype 對象上去找
如果沒找到,就會去該 prototype 原型 [proto] 關聯的前輩 prototype 去找。依次類推,直到找到屬性/方法或 undefined 為止。從而形成了所謂的“原型鏈”
也就是說JavaScript中的對象,都有一個內置屬性[[Prototype]],指向這個對象的原型對象。當查找一個屬性或方法時,如果在當前對象中找不到定義,會繼續在當前對象的原型對象中查找;如果原型對象中依然沒有找到,會繼續在原型對象的原型中查找(原型也是對象,也有它自己的原型);如此繼續,直到找到為止,或者查找到最頂層的原型對象中也沒有找到,就結束查找,返回undefined。可以看出,這個查找過程是一個鏈式的查找,每個對象都有一個到它自身原型對象的鏈接,這些鏈接組件的整個鏈條就是原型鏈。擁有相同原型的多個對象,他們的共同特征正是通過這種查找模式體現出來的。
在上面的查找過程,我們提到了最頂層的原型對象,這個對象就是Object.prototype,這個對象中保存了最常用的方法,如toString、valueOf、hasOwnProperty等,因此我們才能在任何對象中使用這些方法。
當通過字面量方式創建對象時,它的原型就是Object.prototype。雖然我們無法直接訪問內置屬性[[Prototype]],但我們可以通過Object.getPrototypeOf()或對象的__proto__獲取對象的原型。
var obj = {}; Object.getPrototypeOf(obj) === Object.prototype; // true obj.__proto__ === Object.prototype; // true2、構造函數的調用
通過函數的構造調用(注意,我們不把它叫做構造函數,因為JavaScript中同樣沒有構造函數的概念,所有的函數都是平等的,只不過用來創建對象時,函數的調用方式不同而已)也是一種常用的創建對象的方式。基于同一個函數創建出來的對象,理應可以共享一些相同的屬性或方法,但這些屬性或方法如果放在Object.prototype里,那么所有的對象都可以使用它們了,作用域太大,顯然不合適。于是,JavaScript在定義一個函數時,同時為這個函數定義了一個 默認的prototype屬性,所有共享的屬性或方法,都放到這個屬性所指向的對象中。由此看出,通過一個函數的構造調用創建的對象,它的原型就是這個函數的prototype指向的對象。
var f = function(name) { this.name = name }; f.prototype.getName = function() { return this.name; } //在prototype下存放所有對象的共享方法 var obj = new f("JavaScript"); obj.getName(); // JavaScript obj.__proto__ === f.prototype; // true3、Object.create()
第三種常用的創建對象的方式是使用Object.create()。這個方法會以你傳入的對象作為創建出來的對象的原型。
var obj = {}; var obj2 = Object.create(obj); obj2.__proto__ === obj; // true
這種方式還可以模擬對象的“繼承”行為。
function Foo(name) { this.name = name; } Foo.prototype.myName = function() { return this.name; }; function Bar(name,label) { Foo.call( this, name ); // this.label = label; } // temp對象的原型是Foo.prototype var temp = Object.create( Foo.prototype ); // 通過new Bar() 創建的對象,其原型是temp, 而temp的原型是Foo.prototype, // 從而兩個原型對象Bar.prototype和Foo.prototype 有了"繼承"關系 Bar.prototype = temp; Bar.prototype.myLabel = function() { return this.label; }; var a = new Bar( "a", "obj a" ); a.myName(); // "a" a.myLabel(); // "obj a" a.__proto__.__proto__ === Foo.prototype; //true5 __proto__和prototype
這是容易混淆的兩個屬性。__proto__指向當前對象的原型,prototype是函數才具有的屬性,默認情況下,new 一個函數創建出的對象,其原型都指向這個函數的prototype屬性。
每個實例對象(object )都有一個私有屬性(稱之為 __proto__)指向它的原型對象(prototype)。該原型對象也有一個自己的原型對象 ,層層向上直到一個對象的原型對象為 null。根據定義,null 沒有原型,并作為這個原型鏈中的最后一個環節。
6 Javascript如何實現繼承?1.構造函數綁定:使用 call 或 apply 方法,將父對象的構造函數綁定在子對象上
function Cat(name,color){ Animal.apply(this, arguments); this.name = name; this.color = color; }
實例繼承:將子對象的 prototype 指向父對象的一個實例
Cat.prototype = new Animal(); Cat.prototype.constructor = Cat;
拷貝繼承:如果把父對象的所有屬性和方法,拷貝進子對象
function extend(Child, Parent) { var p = Parent.prototype; var c = Child.prototype; for (var i in p) { c[i] = p[i]; } c.uber = p; }
原型繼承:將子對象的 prototype 指向父對象的 prototype
function extend(Child, Parent) { var F = function(){}; F.prototype = Parent.prototype; Child.prototype = new F(); Child.prototype.constructor = Child; Child.uber = Parent.prototype; }
ES6 語法糖 extends:class ColorPoint extends Point {}
class ColorPoint extends Point { constructor(x, y, color) { super(x, y); // 調用父類的constructor(x, y) this.color = color; } toString() { return this.color + " " + super.toString(); // 調用父類的toString() } }
如有侵權,請聯系刪除
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/105228.html
摘要:從今天起我們開始討論的面向對象面向對象概念理解面向對象語言有個標志它們都具有類的概念,通過類可以創建任意多個具有相同屬性和方法的對象。 從今天起我們開始討論javascript的面向對象 面向對象概念理解 面向對象語言有個標志=>它們都具有類的概念,通過類可以創建任意多個具有相同屬性和方法的對象。面向對象有三大特性 封裝 繼承 多態 但JS中對象與純面向對象語言中的對象是不同的 J...
摘要:學習,總繞不開原型,原型鏈,繼承等等這些知識。對象那么好,怎么才能找一個呸,其實是創建創建對象的方法對象字面量工廠模式構造函數模式原型模式等。原型鏈有什么用來談談繼承,繼承可以利用構造函數,使用屬性等來實現。 初學者學習javascript可能會感覺很困擾,但是你一旦真正了解了它,我相信你會愛上它。學習ECMAScript,總繞不開原型,原型鏈,繼承等等這些知識。今天把它們放在一塊兒,...
摘要:之前,本質上不能算是一門面向對象的編程語言,因為它對于封裝繼承多態這些面向對象語言的特點并沒有在語言層面上提供原生的支持。所以在中出現了等關鍵字,解決了面向對象中出現了問題。 ES6之前,javascript本質上不能算是一門面向對象的編程語言,因為它對于封裝、繼承、多態這些面向對象語言的特點并沒有在語言層面上提供原生的支持。但是,它引入了原型(prototype)的概念,可以讓我們以...
摘要:設計模式是以面向對象編程為基礎的,的面向對象編程和傳統的的面向對象編程有些差別,這讓我一開始接觸的時候感到十分痛苦,但是這只能靠自己慢慢積累慢慢思考。想繼續了解設計模式必須要先搞懂面向對象編程,否則只會讓你自己更痛苦。 JavaScript 中的構造函數 學習總結。知識只有分享才有存在的意義。 是時候替換你的 for 循環大法了~ 《小分享》JavaScript中數組的那些迭代方法~ ...
摘要:不必在構造函數中定義對象實例的信息。其次,按照一切事物皆對象的這餓極本的面向對象的法則來說,類本身并不是一個對象,然而原型方式的構造函數和原型本身也是個對象。第二個問題就是在創建子類型的實例時,不能向超類型的構造函數中傳遞參數。 前言 對象(Object)應該算是js中最為重要的部分,也是js中非常難懂晦澀的一部分。更是面試以及框架設計中各出沒。寫這篇文章,主要參考與JavaScrip...
閱讀 5264·2021-09-22 15:59
閱讀 1855·2021-08-23 09:42
閱讀 2560·2019-08-29 18:42
閱讀 3443·2019-08-29 10:55
閱讀 2057·2019-08-27 10:57
閱讀 1759·2019-08-26 18:27
閱讀 2722·2019-08-23 18:26
閱讀 2911·2019-08-23 14:40