摘要:子類型最終回報寒潮類型對象的全部實例屬性,但是我們不得不在調用子類型構造函數時重寫這些屬性處理引用類型共用問題組合式繼承代碼如下第二次調用第一次調用寄生組合式繼承代碼如下
面向對象語言都有類的概念,但是ECMAScript沒有類的概念,所以它的對象與基于類的語言中的對象有所不同。
一、創建對象的幾種方式及對比 1.對象字面量與創建Object實例方式var person = { name:"Zhangsan", age:20, gender: "male", sayName: function(){ console.log(this.name); } }
var person = new Object(); person.name = "Zhangsan"; person.age = 20; person.gender = "male"; person.sayName = function(){ console.log(this.name); }
缺點:使用同一個接口創建很多對象,會產生大量的重復代碼
2.工廠模式因為ECMAScript沒有類的概念,所以用函數來封裝創建對象的細節
function createPerson(name,age,gender){ var o = new Object(); o.name = name; o.age = age; o.gender = gender; o.sayName = function(){ console.log(this.name); } return o; } var person1 = createPerson("Zhangsan",20,"male"); var person2 = createPerson("Lisi",24,"male"); console.log(person1 instanceof Object); //true
缺點:工廠模式解決了創建多個相似對象的重復代碼問題,但沒有解決對象類型識別的問題
3.構造函數模式function Person(name, age, gender){ this.name = name; this.age = age; this.gender = gender; this.sayName = function(){ console.log(this.name); } } var person1 = new Person("Zhangsan",20,"male"); var person2 = new Person("Lisi",24,"male"); console.log(person1 instanceof Person); //true console.log(person1 instanceof Object); //true console.log(person1.constructor == Person); //true console.log(person1.sayName == person2.sayName); //false
以這種方式調用構造函數會經歷以下四步:
創建一個新對象
將構造函數的作用域賦給新對象
執行構造函數中的代碼
返回新對象
任何函數,只要通過new操作符來調用,那它就可以作為構造函數;如果不通過new操作符來調用,那它就是普通函數
var person = new Person("Zhangsan",20,"male"); person.sayName(); //"Zhangsan" Person("Lisi",24,"male"); window.sayName(); //"Lisi" var o = new Object(); Person.call(o,"Wangwu",22,"female"); o.sayName(); //"Wangwu"
缺點:每個方法都要在每個實例上重新創建一遍,上述例子中的sayName方法就會在每個實例中重新創建一遍
function Person(name, age, gender){ this.name = name; this.age = age; this.gender = gender; this.sayName = sayName; } function sayName(){ console.log(this.name); } var person1 = new Person("Zhangsan",20,"male"); var person2 = new Person("Lisi",24,"male");
上述代碼將sayName()函數的定義轉移到構造函數外部,這樣構造函數中的的sayName是一個指向函數的指針,因此person1、person2就共享了在全局作用域定義的同一個sayName()函數。這么做雖然解決了問題但卻帶來了新問題:如果對象需要定義很多方法那么就需要定義很多全局函數,那么自定義的引用類型就絲毫沒有封裝性可言了
4.原型模式 4.1原型對象每個函數都有一個prototype屬性,這個屬性是一個指針指向一個對象,而這個對象包含可以由特定類型的所有實例共享的屬性和方法。使用原型對象的好處就是讓所有對象實例共享它所包含的屬性和方法
function Person(){ } Person.prototype.name = "Nicholas"; Person.prototype.age = 29; Person.prototype.gender = "male"; Person.prototype.sayName = function(){ console.log(this.name); }; var person1 = new Person(); person1.sayName(); //Nicholas var person2 = new Person(); person2.sayName(); //Nicholas console.log(Person.prototype.isPrototypeOf(person1));//true console.log(Person.prototype.isPrototypeOf(person2));//true console.log(Object.getPrototypeOf(person1) == Person.prototype);//true console.log(Object.getPrototypeOf(person1).name);//Nicholas
當代碼讀取某個對象的某個屬性時,先從對象實例本身開始搜索,如果找到給定名稱的屬性則返回該屬性的值;如果沒找到則搜索其指針指向的原型。當為對象實例添加一個屬性時,則這個屬性就會屏蔽原型對象中保存的同名屬性
person1.name = "Zhangsan"; console.log(person1.name); //Zhangsan console.log(person1.hasOwnProperty("name")); //true console.log(person2.hasOwnProperty("name")); //false delete person1.name; console.log(person1.name); //Nicholas4.2原型對象賦值
function Person(){ } Person.prototype = { name:"Nicholas", age:29, gender:"male", sayName:function(){ console.log(this.name); } } var person = new Person(); console.log(person instanceof Object); //true console.log(person instanceof Person); //true console.log(person.constructor == Person); //false console.log(person.constructor == Object); //true Person.prototype.constructor = Person; console.log(person.constructor == Person); //true
使用原型對象賦值操作是會覆蓋原型對象中的constructor屬性,就會切斷原型與構造函數之間的關聯
function Person(){ } var person = new Person(); Person.prototype = { name:"Nicholas", age:29, gender:"male", sayName:function(){ console.log(this.name); } } person.sayName(); //error
缺點:由于原型中的所有屬性和方法都是共享的,所以對于引用類型屬性問題就比較突出
function Person(){ } Person.prototype = { constructor:Person, name:"Nicholas", age:29, gender:"male", love:["swimming","running"], sayName:function(){ console.log(this.name); } } var person1 = new Person(); var person2 = new Person(); person1.love.push("playing games"); console.log(person1.love); //["swimming", "running", "playing games"] console.log(person2.love); //["swimming", "running", "playing games"] console.log(person1.love == person2.love); //true5.組合使用構造函數和原型模式
function Person(name,age,gender){ this.name = name; this.age = age; this.gender = gender; this.love = ["swimming","running"]; } Person.prototype = { constructor:Person, sayName:function(){ console.log(this.name); } } var person1 = new Person("Zhangsan",20,"male"); var person2 = new Person("Lisi",24,"male"); person1.love.push("playing games"); console.log(person1.love); //["swimming", "running", "playing games"] console.log(person2.love); //["swimming", "running"] console.log(person1.love == person2.love); //false
這種模式是使用最廣泛、認同度最高的一種創建自定義類型的方法
6.寄生構造函數模式function SpecialArray(name,age,gender){ var array = new Array(); array.push.apply(array,arguments); array.toPipedString = function(){ return this.join("|"); } return array; }
這種模式可以用來為原生引用類型做擴展,寄生構造函數模式返回的對象與構造函數或者與構造函數原型之間沒有關系,因此不能依賴instanceof操作符來確定對象類型
二、繼承 1.原型鏈function SuperType(){ this.property = true; } SuperType.prototype.getSuperValue = function (){ return this.property; } function SubType(){ this.subproperty = false; } SubType.prototype = new SuperType(); SubType.prototype.getSubValue = function (){ return this.subproperty; } var instance = new SubType(); console.log(instance.getSuperValue()); //true
原型鏈雖然很強大,可以用它來實現繼承,但它也存在一些問題,其中,最主要的問題來自包含引用類型值的原型;第二個問題是創建子類型的實例時不能向超類的構造函數中傳遞參數。
function SuperType(){ this.colors = ["red","yellow","blue"]; } function SubType(){ } SubType.prototype = new SuperType(); var instance1 = new SubType(); instance1.colors.push("green"); console.log(instance1.colors); //["red", "yellow", "blue", "green"] var instance2 = new SubType(); console.log(instance2.colors); //["red", "yellow", "blue", "green"]2.借用構造函數
借用構造函數用于解決原型鏈中包含引用類型值所帶來的問題
function SuperType(){ this.colors = ["red","yellow","blue"]; } function SubType(){ SuperType.call(this); } var instance1 = new SubType(); instance1.colors.push("green"); console.log(instance1.colors); //["red", "yellow", "blue", "green"] var instance2 = new SubType(); console.log(instance2.colors); //["red", "yellow", "blue"]
問題:方法都在構造函數中定義,因此函數復用無從談起,而且在超類原型中定義的方法對子類而言也是不可見的,結果所有類型都只能使用構造函數模式
3.組合繼承function SuperType(name){ this.name = name; this.colors = ["red", "yellow", "blue"]; } SuperType.prototype.sayName = function(){ console.log(this.name); } function SubType(name, age){ SuperType.call(this,name); this.age = age; } SubType.prototype = new SuperType(); SubType.prototype.constructor = SubType; SubType.prototype.sayAge = function(){ console.log(this.age); } var instance1 = new SubType("Zhangsan",20); instance1.colors.push("green"); console.log(instance1.colors); //["red", "yellow", "blue", "green"] instance1.sayName(); //Zhangsan instance1.sayAge(); //20 var instance2 = new SubType("Lisi", 24); console.log(instance2.colors); //["red", "yellow", "blue"] instance2.sayName(); //Lisi instance2.sayAge(); //24
組合繼承避免了原型鏈和借用構造函數的缺陷,融合了他們的優點,成為JavaScript中最常用的繼承模式
4.原型式繼承var person = { name : "Zhangsan", colors : ["red", "yellow", "blue"] } var anotherPerson = Object.create(person); anotherPerson.name = "Lisi"; anotherPerson.colors.push("green"); var otherPerson = Object.create(person); otherPerson.name = "Wangwu"; otherPerson.colors.push("black"); console.log(person.colors); //["red", "yellow", "blue", "green", "black"] console.log(person.name); //Zhangsan
這種繼承方式在想讓一個對象與另一個對象保持類似的情況下是完全可以勝任的
5.寄生式繼承var person = { name : "Zhangsan", colors : ["red", "yellow", "blue"] } var anotherPerson = Object.create(person); anotherPerson.sayHi = function(){ console.log("hi"); } anotherPerson.sayHi();
使用寄生式繼承不能做到函數復用而降低效率
6.寄生組合式繼承組合繼承最大的問題就在于無論什么情況下都會調用兩次超類型構造函數:一次是在創建子類型原型的時候,另一次是在子類型構造函數內部。子類型最終回報寒潮類型對象的全部實例屬性,但是我們不得不在調用子類型構造函數時重寫這些屬性(處理引用類型共用問題)
組合式繼承代碼如下:
function SuperType(name){ this.name = name; this.colors = ["red", "yellow", "blue"]; } SuperType.prototype.sayName = function(){ console.log(this.name); } function SubType(name, age){ SuperType.call(this,name); //第二次調用 this.age = age; } SubType.prototype = new SuperType(); //第一次調用 SubType.prototype.constructor = SubType; SubType.prototype.sayAge = function(){ console.log(this.age); }
寄生組合式繼承代碼如下:
function SuperType(name){ this.name = name; this.colors = ["red", "yellow", "blue"]; } SuperType.prototype.sayName = function(){ console.log(this.name); } function SubType(name, age){ SuperType.call(this,name); this.age = age; } SubType.prototype = Object.create(SuperType.prototype); SubType.prototype.constructor = SubType; SubType.prototype.sayAge = function(){ console.log(this.age); }
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/98460.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); 馬上就要到七夕了,離年底老媽老爸...
摘要:請記住,這些書中的一些可能不是最新的,但概念和基礎仍應適用。是最好的老師之一。的秘密由部分組成。在你完成這些書后,查看書籍和最好的本土書籍。 我看過三本,第1本,第二本,第四本。第一本買的的實體書,其他兩本看的是電子書。第一本是大名鼎鼎老道寫的,書很薄,但是非常經典。javascirpt忍者秘籍是jquery的作者寫的,也是非常經典。you dont kown js系列也是非常好。看了...
摘要:學編程真的不是一件容易的事不管你多喜歡或是多會編程,在學習和解決問題上總會碰到障礙。熟練掌握核心內容,特別是和多線程初步具備面向對象設計和編程的能力掌握基本的優化策略。 學Java編程真的不是一件容易的事,不管你多喜歡或是多會Java編程,在學習和解決問題上總會碰到障礙。工作的時間越久就越能明白這個道理。不過這倒是一個讓人進步的機會,因為你要一直不斷的學習才能很好的解決你面前的難題...
摘要:函數式編程最后介紹一下函數式編程。函數式編程是一種歷史悠久,而又在最近頗為熱門的話題。函數式編程在面向對象一詞誕生以前就已經存在,不過它在很長一段時間里都被隱藏于過程式編程面向對象也是過程式編程的一種的概念之下。 2.1 JavaScript特點 總結以下幾個特點: 解釋型語言 類似與C和Java的語法結構 動態語言 基于原型的面向對象 字面量的表現能力 函數式編程 解釋型語言:...
閱讀 2597·2021-10-14 09:43
閱讀 3559·2021-10-13 09:39
閱讀 3289·2019-08-30 15:44
閱讀 3137·2019-08-29 16:37
閱讀 3702·2019-08-29 13:17
閱讀 2731·2019-08-26 13:57
閱讀 1825·2019-08-26 11:59
閱讀 1238·2019-08-26 11:46