摘要:構造函數模式這種方法創建自定義的構造函數,從而自定義對象類型的屬性和方法。借用構造函數在子類型構造函數的內部調用超類型構造函數,通過和方法來實現。
JavaScript中沒有類的概念,它不是嚴格意義上的面向對象語言,而是基于對象(Object-based)的編程語言。下面是讀《JavaScript高級程序設計(第三版)》的學習筆記,總結一些常用的創建對象和繼承的方法。
一、創建對象 1. 對象字面量創建對象最簡單的方式就是創建一個Object的實例。通過先創建一個對象,再為它添加屬性和方法。此方法用對象字面量方式更為直觀:
var animal = { name : "mimi", sayName : function(){ console.log(this.name); } //... }
★ 這種方法在創建多個對象時會產生大量重復的代碼,在創建單個對象時的首選模式。
2. 工廠模式這種方法用函數來封裝以特定接口創建對象的細節:
function animal(name) { var o = new Object();//創建新對象 o.name = "mimi";//給這個對象添加屬性 //... return o;//返回這個對象 }
★ 這種方法沒有解決對象識別的方法,一定程度上解決創建多個相似對象的問題吧,不常使用。
3. 構造函數模式這種方法創建自定義的構造函數,從而自定義對象類型的屬性和方法。
function Animal(name) { this.name = name;//將屬性和方法賦給this對象 this.sayName = function(){ console.log(this.name); } //... }
它沒有顯式的創建對象也沒有返回語句,但在使用new操作符調用后經歷了四個步驟:
(1)創建一個對象
(2)將函數的作用域賦給新對象(this指向了新對象)
(3)執行函數中代碼
(4)返回新對象
所有對象都有一個constructor屬性,指向其構造函數。constructor可以用來標識對象類型,但是,要檢測對象類型,instanceof操作符更可靠。
★ 這種方法的問題在于,每個方法都會在每個實例上重新創建一次。
4. 原型模式function Animal() { } Animal.prototype.name = "mimi";//將方法屬性添加到Animal的prototype屬性中 Animal.prototype.sayName = function(){ console.log(this.name); }; //...
無論何時,創建一個函數,都會自動創建一個prototype屬性,指向其原型對象,正如前面所說,每個對象都有一個constructor屬性,指向其構造函數。所以Animal.prototype.constructor指向Animal。判斷原型對象與實例間關系可用isPrototypeOf()方法:
Animal.prototype.isPrototypeOf(animal1);
判斷屬性存在于實例中,還是存在與原型中:
屬性存在于實例中時:
animal1.hasOwnProperty(name);//true
屬性能通過對象訪問:
name in animal1;//true
在實例中添加了與原型中同名的屬性
我們將在實例中創建該屬性,而屏蔽原型中的屬性。當然,我們可以通過delete操作符完全刪除實例中的該屬性而讓我們重新訪問到原型中的屬性(*  ̄︿ ̄)。
用字面量來實現更簡單的原型語法
function Animal() { } Animal.prototype = { constructor : Animal,//必須必須!因為這樣相當于創建了一個新對象并賦值給Animal.prototype, //此時這個新對象的constructor為默認的構造函數Object啊盆友們( ?Д?)? name : "mimi", sayName : function(){ console.log(this.name); } }
另外,很重要的一點:調用構造函數是會為實例添加一個指向最初原型的[[prototype]]指針,這個連接存在與實例和構造函數的原型對象之間,而不是實例與構造函數間。
我們將上面將上面的代碼稍加修改:
function Animal(name) { } animal1 = new Animal()//創建實例1 console.log(animal1.smell);//undefined;此時原型中還未添加smell屬性,理所當然。 Animal.prototype.smell = "good";//添加原型屬性 console.log(animal1.smell);//可以訪問smell屬性。
然而,當用對象字面量來添加原型屬性時:
function Animal(name) { } animal1 = new Animal()//創建實例1 console.log(animal1.smell);//undefined;此時原型中還未添加smell屬性,理所當然。 Animal.prototype = {//添加原型屬性 smell : "good"; } console.log(animal1.smell);//undefined; //因為animal1在創建時[[prototype]]指針指向的是最初的原型,而字面量法添加原型屬性時將對象原型改變了,但[[prototype]]沒有跟著一起變化,所以無法訪問。
★ 這個方法的問題在于:1.它沒辦法傳遞初始化參數 2.對于引用類型值的屬性(A)來說,改變一個實例的A屬性會直接引起所有實例中的A屬性的變化,因為實例中的A屬性只是其原型中A屬性的一個引用。
5. 組合使用構造函數模式和原型模式構造函數模式用于定義實例屬性,原型模式用于定義方法和共享屬性。
function Animal(name) {//添加實例屬性 this.name = name; this.color = ["yellow", "black"]; //... } Animal.prototype = {//添加方法和共享屬性 constructor : Animal, sayName : function(){ console.log(this.name); } //... }
★ 這個方法就是使用最廣泛、認同度最高的創建自定義類型的方法啦。
小總結:第一種和最后一種是比較常用的方法了,書中還有提到一些方法,是在前面這些方法都不適用時可以選擇使用的,不過我還沒碰上啦,所以等以后碰上了再來補充。
二、繼承JavaScript中不支持接口繼承(繼承方法簽名),都是支持實現繼承(繼承實際的方法),主要依賴原型鏈來實現。
1. 原型鏈將父類的實例賦值給子類的原型,此時,父類的實例中包含一個指向父類原型的指針。子類的原型通過這個指針訪問到父類原型中的屬性。
function Animal(name) {//父類 this.name = name; } Animal.prototype = {//將屬性添加到父類原型 constructor : Animal, sayName : function(){ console.log(this.name); } } function Cat() {//子類 } Cat.prototype = new Animal();//將父類實例賦值給子類原型。 Cat.prototype.constructor = Cat;//prototype被換成另一個對象,所以constructor屬性要重寫,否則會指向Animal. var cat1 = new Cat();
其中的原型鏈:
用instanceof操作符判定可得出cat1是Cat、Animal、Object的實例。
★ 此方法存在問題前面已有提及,就是包含引用類型值的原型屬性會被所有實例共享,且不能傳參。
2. 借用構造函數在子類型構造函數的內部調用超類型構造函數,通過apply()和call()方法來實現。
function Animal(name) {//父類 this.name = name; } function Cat(name) {//子類 Animal.call(this, name);//執行了一遍父類型構造函數代碼 } var cat1 = new Cat();
★ 此方法問題在于:1.方法都在構造函數中定義,函數復用無從談起。2.在超類的原型中定義的方法對子類型也不可見。而且用instanceof也無法判定cat1與Animal的聯系。
3. 組合繼承使用原型鏈實現對原型屬性和方法的繼承,使用借用構造函數實現對實例屬性的繼承。
function Animal(name) {//父類添加實例屬性 this.name = name; } Animal.prototype = {//父類原型添加方法和屬性 constructor : Animal, sayName : function(){ console.log(this.name); } } function Cat(name) {//子類 Animal.call(this, name);//繼承屬性 } Cat.prototype = new Animal();//繼承方法 Cat.prototype.constructor = Cat;//將constructor指回子類
★ 此方法是JS中最常用的繼承模式。而且用instanceof 和isPrototypeOf() 也能識別。
目前有實際用的就這些了,總結的比較基礎,希望也總結清楚了。
參考文獻:《JavaScript高級程序設計(第三版)》
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/80355.html
摘要:很多情況下,通常一個人類,即創建了一個具體的對象。對象就是數據,對象本身不包含方法。類是相似對象的描述,稱為類的定義,是該類對象的藍圖或原型。在中,對象通過對類的實體化形成的對象。一類的對象抽取出來。注意中,對象一定是通過類的實例化來的。 showImg(https://segmentfault.com/img/bVTJ3H?w=900&h=385); 馬上就要到七夕了,離年底老媽老爸...
摘要:很多情況下,通常一個人類,即創建了一個具體的對象。對象就是數據,對象本身不包含方法。類是相似對象的描述,稱為類的定義,是該類對象的藍圖或原型。在中,對象通過對類的實體化形成的對象。一類的對象抽取出來。注意中,對象一定是通過類的實例化來的。 showImg(https://segmentfault.com/img/bVTJ3H?w=900&h=385); 馬上就要到七夕了,離年底老媽老爸...
摘要:很多情況下,通常一個人類,即創建了一個具體的對象。對象就是數據,對象本身不包含方法。類是相似對象的描述,稱為類的定義,是該類對象的藍圖或原型。在中,對象通過對類的實體化形成的對象。一類的對象抽取出來。注意中,對象一定是通過類的實例化來的。 showImg(https://segmentfault.com/img/bVTJ3H?w=900&h=385); 馬上就要到七夕了,離年底老媽老爸...
摘要:是完全的面向對象語言,它們通過類的形式組織函數和變量,使之不能脫離對象存在。而在基于原型的面向對象方式中,對象則是依靠構造器利用原型構造出來的。 JavaScript 函數式腳本語言特性以及其看似隨意的編寫風格,導致長期以來人們對這一門語言的誤解,即認為 JavaScript 不是一門面向對象的語言,或者只是部分具備一些面向對象的特征。本文將回歸面向對象本意,從對語言感悟的角度闡述為什...
摘要:用代碼可以這樣描述安全到達國外面向過程既然說了面向對象,那么與之對應的就是面向過程。小結在這篇文章中,介紹了什么是面向對象和面向過程,以及中對象的含義。 這是 javascript 面向對象版塊的第一篇文章,主要講解對面向對象思想的一個理解。先說說什么是對象,其實這個還真的不好說。我們可以把自己當成一個對象,或者過年的時候相親,找對象,那么你未來的老婆也是一個對象。我們就要一些屬性,比...
摘要:對象重新認識面向對象面向對象從設計模式上看,對象是計算機抽象現實世界的一種方式。除了字面式聲明方式之外,允許通過構造器創建對象。每個構造器實際上是一個函數對象該函數對象含有一個屬性用于實現基于原型的繼承和共享屬性。 title: JS對象(1)重新認識面向對象 date: 2016-10-05 tags: JavaScript 0x00 面向對象 從設計模式上看,對象是...
閱讀 3677·2021-09-22 15:34
閱讀 1186·2019-08-29 17:25
閱讀 3399·2019-08-29 11:18
閱讀 1371·2019-08-26 17:15
閱讀 1740·2019-08-23 17:19
閱讀 1228·2019-08-23 16:15
閱讀 718·2019-08-23 16:02
閱讀 1335·2019-08-23 15:19