摘要:使用調用構造函數,將構造函數的作用域賦給新對象指向新對象構造函數模式的特點使用構造函數創建的對象實例有特定的類型。說明是的原型屬性。
這是兩年前寫的筆記,自己都有遺忘,相信也會有人不明白,貼在這里。
都是紅寶書上的內容,在比較難理解的地方加了一些示例和說明。
es中定義對象為:無需屬性的集合、其屬性可以包含基本值、對象或者函數。
創建對象 Object實例創建對象最簡單的方法是創建一個Object的實例。
var person =new Object(); person.name="Mike"; person.age=12; person.job="student"; person.sayName=function(){ };對象字面量
var person={ name:"mike", age:10, job:"student", sayName:function(){ alert(this.name); } };
Object實例和對象字面量都可以用來創建單個對象,
但是當要創建多個對象就會產生大量重復的代碼,由此產生了工廠模式。
工廠模式的特點是用函數來封裝創建對象的細節,對外以接口的方式調用。
function createPerson(name,age,job){ var obj = new Object(); obj.name=name; obj.age=age; obj.job=job; obj.sayName=function(){ alert(this.name); } return obj; } var person1=createPerson("Mike",12,"student");
工廠模式雖然解決了創建相似對象重復代碼的問題,
但同時還存在一個問題:如何知道對象的類別?由此產生構造函數模式
function CreatePerson(name,age,job){ this.name=name; this.age=age; this.job=job; this.sayName=function(){ alert(this.name); } } var person1= new CreatePerson("Mi",13,"student"); var person2= new CreatePerson("Mike",12,"student"); alert(person2.constructor==CreatePerson);//true alert(person1 instanceof CreatePerson);//true alert(person2 instanceof CreatePerson);//true alert(person2 instanceof Object);//true 使用instanceof來檢測對象的類型
構造函數沒有返回值,沒有顯示地創建對象。
使用new調用構造函數,將構造函數的作用域賦給新對象(this指向新對象)
構造函數模式的特點:使用構造函數創建的對象(實例)有特定的類型。這也是構造函數模式勝過工廠模式的地方
構造函數模式的問題:構造函數中方法,在不同的實例中是不同的funciton實例,也就是說不同實例中有不同function(雖然他們的功能相同),
但是這并不是我們希望看到的,更何況function中還有this(指向實例的作用域),所以完全沒有必要把功能相同function綁定到特定的實例上。
由此產生了原型模式!
大boss來了,接著說下去
關于原型的定義,摘自紅寶書:每個函數都有一個prototype(原型)屬性,這個屬性是一個指針,指向一個對象,而這個對象的用途是包含可以由特定類型的所有實例共享的屬性和方法。
好長一句話!有點暈?直接上代碼:
function Person(){ } Person.prototype.name="mike"; Person.prototype.age=12; Person.prototype.job="Software Engneer"; Person.prototype.sayName=function(){ alert(this.name); } var person1=new Person(); alert(Person1.prototype.isPrototypeOf(person5));//true檢驗實例與原型之間的關系 person1.sayName();//mike var person2=new Person(); alert(person1.sayName()==person2.sayName());//true var person6=new Person(); person6.name="ssss"; alert(person6.hasOwnProperty("ssss"));//true原型鏈查找屬性或方法:
首先查找實例屬性:即定義在子類構造函數中或直接添加在實例上的屬性
然后查找子類原型屬性:包括子類自有的原型屬性和,父類的實例屬性(子類的原型是父類的實例)(這也就是原型鏈繼承的缺點,父類的實例屬性全變成子類的原型屬性,那就是所有子類實例共享的,如果又是引用類型,就出大事了。所以很少多帶帶使用原型鏈)
最后查找父類的原型屬性
function SuperType(){ this.name="super"; this.job="student"; } SuperType.prototype.getSuperValue=function(){ alert(this.name); } SuperType.prototype.sex="man"; function SubType(){ this.age=12; } SubType.prototype=new SuperType(); SubType.prototype.getSubValue=function(){ alert(this.age); } //var person=new SubType(); var instance1=new SubType alert(instance1 instanceof SubType);//true alert(instance1 instanceof SuperType);//true alert(SubType.prototype.isPrototypeOf(instance1));//true alert(SuperType.prototype.isPrototypeOf(instance1));//true person.getSuperValue(); alert(person.constructor==SubType);//false子類的實例的原型對象沒有constructor屬性 alert(person instanceof SubType); alert(person instanceof SuperType); alert(person.job); alert(person.constructor);//sub的原型指向super的原型,super的原型的constuctor是superType,所以person的 alert(person.hasOwnProperty("name"));//false alert("name" in person);//true 說明name是sub的原型屬性。 alert(person.hasOwnProperty("sex"));//false alert("sex" in person);//true 說明name是sub的原型屬性。,父類中的全部屬性都是子類的原型屬性 var person1=new SuperType();; alert(person1.constructor);//
解決原型鏈缺點的方法:借用構造函數
借用構造函數function SuperType(name){ this.colors=["red","yellow","green"]; this.name=name; } function SubType(){ SuperType.call(this,"Mike"); this.age=10; } var instance1=new SubType(); instance1.colors.push("aa"); alert(instance1.colors); alert(instance1 instanceof SubType);//true alert(instance1 instanceof SuperType);//false alert(SubType.prototype.isPrototypeOf(instance1));//true alert(SuperType.prototype.isPrototypeOf(instance1));//false var instance2=new SubType(); alert(instance2.colors);//["red","yellow","green"];
在新實例的環境中調用Super構造函數
var instance3=new SubType(); alert(instance3.hasOwnProperty("name")); alert(instance3.hasOwnProperty("age"));
在子類中call(借調)父類的構造函數實際上就是為子類添加了實例屬性(原來在父類中的實例屬性)
即父類的實例屬性變成了子類的實例屬性(原型鏈繼承中,父類的實例屬性變成了子類的原型屬性)
function SuperType(name){ this.colors=["red","yellow","green"]; this.name=name; } SuperType.prototype.sayName=function(){ alert(this.name); } function SubType(name,age){ SuperType.call(this,"Kiko"); this.age=age; } SubType.prototype=new SuperType(); SubType.prototype.constructor=SubType; SubType.prototype.sayAge=function(){ alert(this.age); } var instance1=new SubType("Kiko",12); //instance1.sayName(); //instance1.colors.push("ss"); //alert("colors" in instance1);//有屬性 //alert(instance1.hasOwnProperty("colors")) //實例屬性 沒有這句話的時候//SuperType.call(this,"Kiko");,,是原型屬性 //有了這句話變成了實例屬性 //alert(instance1.colors); //instance1.sayAge(); alert(instance1 instanceof SubType);//true alert(instance1 instanceof SuperType);//true alert(SubType.prototype.isPrototypeOf(instance1));//true alert(SuperType.prototype.isPrototypeOf(instance1));//true alert(Object.keys(SubType.prototype));//colors,name,constructor,sayAge alert(Object.keys(instance1));//colors,name,age
這兩句說明第一:SubType.prototype=new SuperType();父類的所有屬性都變成了子類的原型屬性
第二:SuperType.call(this,"Kiko");,在子類的構造函數中重寫了父類的實例屬性,即父類的實例屬性變成了子類的實例屬性
第三:p149:每當代碼讀取對象中的某個屬性時,都會執行一次搜索,先查找實例屬性,再查找原型屬性
第四:因此,組合繼承中父類中的實例屬性既是子類的實例屬性也是子類的原型屬性,但是在每次使用對象時,查找到實例屬性就截止了,
所以表現為父類中的實例屬性變成了子類中的實例屬性(實例屬性覆蓋了原型對象上的同名屬性)
var instance2=new SubType("hihi",13);
//alert(instance2.colors);
function object(o){ function F(){} F.prototype=o; return new F(); } var person={ name:"Mike", friends:["kiko","Court","Van"] }; var anotherPerson=object(person); alert(anotherPerson.name);// anotherPerson.friends.push("ss"); var yetAnotherPerson=object(person); alert(yetAnotherPerson.friends);//["kiko","Court","Van","ss"]寄生式繼承
function createAnother(original){ var clone=object(original); clone.sayHi=function(){ alert("hi"); } return clone; } var anotherPerson1=createAnother(person); anotherPerson.sayHi();//hi
使用寄生式繼承來為對象添加函數,會由于不能復用而降低效率,這一點與構造函數模式很類似(同名的方法是不同的function實例)
寄生組合式繼承組合式的缺點是兩次調用超類的構造函數:
一,SubType.prototype=new SuperType();父類的所有屬性都變成了子類的原型屬性
二:SuperType.call(this,"Kiko");,在子類的構造函數中重寫了父類的實例屬性,即父類的實例屬性變成了子類的實例屬性
寄生組合式目的是為了省掉第一步多繼承的實例屬性,在第一步時只繼承父類的原型屬性,第二步繼承實例屬性
function object(o){ function F(){} F.prototype=o; return new F(); } function inheritPrototype(SubType,SuperType){ var prototype=object(SuperType.prototype); prototype.constructor=SubType; SubType.prototype=prototype; } function SuperType(name){ this.name=name; this.colors=["red","blue","yellow"]; } SuperType.prototype.sayName=function(){ alert(this.name); } SuperType.prototype.job="student"; function SubType(name,age){ SuperType.call(this,name);//(2)繼承實例屬性 this.age=age; } inheritPrototype(SubType,SuperType);//(3)繼承原型屬性 SubType.prototype=new SuperType();//(1)把父類的原型屬性和實例屬性都繼承為原型屬性了 SubType.prototype.sayAge=function(){ alert(this.age); } var instance1=new SubType(); alert("name" in instance1);//有屬性true alert(instance1.hasOwnProperty("name"));//false不是實例屬性
這兩句話檢驗是否是原型屬性,1true,2false,原型屬性,1ture,2true實例屬性
寄生組合式,name會是實例屬性
組合式,把(3)換成(1)name確實也是實例屬性,那是因為(2)重新調用了SuperType,覆蓋了原型中的同名屬性。
可以把(2)去掉,發現name變成了原型屬性。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/100766.html
摘要:一些額外的全局函數命名空間對象接口和構造函數與沒有典型的關聯,但卻是有效的。最后有幾點需要說明的是每個構造函數都有一個原型對象,原型對象都包含一個指向構造函數的指針,而實例都包含一個指向原型對象的內部指針。 文章來源:小青年原創發布時間:2016-07-03關鍵詞:JavaScript,原型鏈,jQuery類庫轉載需標注本文原始地址: http://zhaomenghuan.githu...
摘要:原文地址詳解的類博主博客地址的個人博客從當初的一個彈窗語言,一步步發展成為現在前后端通吃的龐然大物。那么,的類又該怎么定義呢在面向對象編程中,類是對象的模板,定義了同一組對象又稱實例共有的屬性和方法。這個等同于的屬性現已棄用。。 前言 生活有度,人生添壽。 原文地址:詳解javascript的類 博主博客地址:Damonare的個人博客 ??Javascript從當初的一個彈窗語言,一...
摘要:原文地址詳解的類博主博客地址的個人博客從當初的一個彈窗語言,一步步發展成為現在前后端通吃的龐然大物。那么,的類又該怎么定義呢在面向對象編程中,類是對象的模板,定義了同一組對象又稱實例共有的屬性和方法。這個等同于的屬性現已棄用。。 前言 生活有度,人生添壽。 原文地址:詳解javascript的類 博主博客地址:Damonare的個人博客 ??Javascript從當初的一個彈窗語言,一...
摘要:這樣每個實例獨享自己的屬性,并和其他同類型的實例共享方法構造函數原型以上這種方式定義的類型,可以通過來判斷一個實例是否是類型的實際上是通過實例的原型鏈來判斷一個對象是否某個類型的實例的,具體的細節后面會詳細介紹。 JavaScript面向對象編程 如何定義自定義類型 首先需要明確,JavaScript并不是傳統意義上的OO語言,它并沒有class的概念, 而是包含了另一套異常強大的...
閱讀 2578·2021-09-06 15:02
閱讀 3207·2021-09-02 10:18
閱讀 2829·2019-08-30 15:44
閱讀 691·2019-08-30 15:43
閱讀 1956·2019-08-30 14:08
閱讀 2764·2019-08-30 13:16
閱讀 1406·2019-08-26 13:52
閱讀 936·2019-08-26 12:21