Javascript之创建对象(原型模式)
生活随笔
收集整理的這篇文章主要介紹了
Javascript之创建对象(原型模式)
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
? ??我們創(chuàng)建的每個函數(shù)都有一個prototype(原型)屬性,這個屬性是一個指針,指向一個對象,它的用途是包含可以有特定類型的所有實例共享的屬性和方法。
? ??prototype就是通過構(gòu)造函數(shù)而創(chuàng)建的那個對象的原型對象。使用原型的好處就是可以讓所有對象實例共享它所包含的屬性和方法 。
function Person() { } Person.prototype.name = "zxj"; Person.prototype.age = 29; Person.prototype.job = "Software Engineer"; Person.prototype.sayName = function () {alert(this.name); } var person1 = new Person(); person1.sayName(); //zxj var person2 = new Person(); person2.sayName(); //zxj1、理解原型對象
? ? 無論什么時候,只要創(chuàng)建了一個新函數(shù),ECMAScript就會根據(jù)一組特定的規(guī)則為該函數(shù)創(chuàng)建一個prototype屬性,這個屬性指向函數(shù)的原型對象。在默認(rèn)情況下,所有原型對象都會自動獲得一個constructor(構(gòu)造函數(shù))屬性,這個屬性包含一個指向prototype屬性所在函數(shù)的指針。就拿前面的例子,Person.prototype.constructor指向Person。而通過這個構(gòu)造函數(shù),我們還可以繼續(xù)為原型對象添加其他屬性和方法。 ? ? 創(chuàng)建了自定義指針之后,其原型對象默認(rèn)只會取得constructor屬性;至于其它方法,都會從Object對象繼承而來。當(dāng)調(diào)用構(gòu)造函數(shù)創(chuàng)建一個新實例之后,該實例的內(nèi)部將包括一個指針(內(nèi)部屬性),指向構(gòu)造函數(shù)的原型對象。ECMA-262第5版中管這個叫[[Prototype]]。 ? ? 要明確一點的就是,這個連接存在于實例和構(gòu)造函數(shù)的原型對象之間,而不是存在于實例和構(gòu)造函數(shù)之間。 ? ? 以前面使用的Person構(gòu)造函數(shù)和Person.prototype創(chuàng)建實例的代碼為例,如下圖: ? ? 上圖展示了Person構(gòu)造函數(shù)、Person的原型屬性以及Person現(xiàn)有的兩個實例之間的關(guān)系。在此,Person.prototype指向了原型對象,而Person.prototype.constructor又指回了Person。原型對象中除了包含constructor屬性之外,還包括后來添加的其他屬性。Person的每一個實例——person1和person2都包含一個內(nèi)部屬性,該屬性僅僅指向Person.prototype。換句話說,它們與構(gòu)造函數(shù)沒有直接的聯(lián)系。此外,要格外注意的是,雖然這兩個實例都不包含屬性和方法,但我們卻可以調(diào)用person1.sayName()。這是通過查找對象屬性的過程來實現(xiàn)的。 ? ? 雖然我們無法訪問到[[Prototype]],但可以通過isPrototypeOf()方法來確定對象之間是否存在這種關(guān)系。從本質(zhì)上講,如果[[Prototype]]指向調(diào)用isPrototypeOf()方法的對象(Person.prototype),那么這個方法就會返回true。 alert(Person.prorotype.isPrototypeOf(person1)); //true alert(Person.prorotype.isPrototypeOf(person2)); //true ? ? 每當(dāng)代碼要讀取某個對象的屬性時,都會進(jìn)行一次搜索,搜索目標(biāo)是具有給定名稱的屬性。搜索當(dāng)然先從對象實例的本身開始,如果找到了,就可以返回該值了;如果找不到,則會去指針?biāo)赶虻脑蛯ο笾腥ゲ檎?#xff0c;在原型對象中找到了,就可以順利返回該值。而這正是多個對象實例共享原型所保存的屬性和方法的基本原理。 ? ??雖然可以通過對象實例訪問到保存在原型中的值,但不能通過對象實例重寫原型中的值。根據(jù)查找原理,如果找到了實例中的值,就不會再去查找原型對象中的值。,代碼如下所示: function Person() { } Person.prototype.name = "zxj"; Person.prototype.age = 29; Person.prototype.job = "Software Engineer"; Person.sayName = function () {alert(this.name); } var person1 = new Person(); var person2 = new Person(); person1.name = "Greg"; alert(person1.name); //Greg 來自實例 alert(person2.name); //zxj 來自原型 delete person1.name; //刪除實例中的name屬性 alert(person1.name); //zxj 來自原型 使用hasOwnPeoperty()方法可以檢測一個屬性是否存在于實例中,還是存在原型中,這個方法(它是從Object繼承來的)只在給定屬性存在域?qū)ο髮嵗袝r,才返回true。 function Person() { } Person.prototype.name = "zxj"; Person.prototype.age = 29; Person.prototype.job = "Software Engineer"; Person.sayName = function () {alert(this.name); } var person1 = new Person(); var person2 = new Person(); alert(person1.hasOwnProperty("name")); //false person1.name = "Greg"; alert(person1.name); //Greg 來自實例 alert(person1.hasOwnProperty("name")); //true alert(person2.name); //zxj 來自原型 alert(person2.hasOwnProperty("name")); //false delete person1.name; alert(person1.name); //zxj 來自原型 alert(person1.hasOwnProperty("name")); //false?
2、原型與in操作符
? ??有兩種方式使用in操作符:一、單獨使用;二、for-in中使用。 ? ??功能:會在通過對象能夠訪問給定屬性時返回true,無論是在對象實例中或是原型中。 function Person() { } Person.prototype.name = "zxj"; Person.prototype.age = 29; Person.prototype.job = "Software Engineer"; Person.sayName = function () {alert(this.name); } var person1 = new Person(); var person2 = new Person();alert(person1.hasOwnProperty("name")); //false alert("name" in person1); //true person1.name = "Greg";alert(person1.name); //Greg 來自實例 alert(person1.hasOwnProperty("name")); //true alert("name" in person1); //true alert(person2.name); //zxj 來自原型 alert(person2.hasOwnProperty("name")); //false alert("name" in person2); //truedelete person1.name; alert(person1.name); //zxj 來自原型 alert(person1.hasOwnProperty("name")); //false alert("name" in person1); //true alert(person1.hasOwnProperty("qqqq")); //false alert("qqqq" in person1); //false ? ??同時使用hasOwnProperty()和in操作符可以判斷出該屬性到底是存在對象實例中還是存在與原型中。 ? ??使用for-in循環(huán)時,返回的是所有能夠通過對象訪問的,可枚舉(enumerated)屬性,其中即包括存在與實例中的屬性,也包括存在與原型中的屬性。根據(jù)規(guī)定,開發(fā)人員定義的屬性都是可枚舉的——IE8及更早版本除。 var o = {toString: function () {return "My Object";} } for (var prop in o) {if (prop == "toString") {alert("Found toString"); //在IE中不會顯示(IE9(未測試)和IE10(已測試)可用) } }?
3、更簡單的原型語法
? ? 我們可以用一個包含屬性和方法的對象字面量重寫整個原型對象。 function Person(){ }Person.peototype={name:"zxj",age:29,job:"Software Engineer",sayName:function(){alert(this.name);} }; ? ??結(jié)果是與先前的相同,但有一個是不同的:contrcutor屬性不再指向Person了。我們曾經(jīng)介紹過,沒創(chuàng)建一個函數(shù),就會同時創(chuàng)建它的prototype對象,這個對象也會自動獲得constructor屬性。而我們這樣寫,本質(zhì)上是完全重寫了默認(rèn)的prototype對象,因此constructor屬性也就變成了新對象的constructor屬性(指向Object構(gòu)造函數(shù)),不再指向Person函數(shù)。 ? ??當(dāng)然我可以將它特意設(shè)置成適當(dāng)?shù)闹?#xff1a; function Person() { }Person.prototype = {constructor: Person,name: "zxj",age: 29,sayName: function () {alert(this.name);} }; ? ? 以上代碼特意包含了一個constructor屬性,并將它的值設(shè)置為Person,從而確保了通過該屬性能夠訪問到適當(dāng)?shù)闹怠?/span> ? ? 注意,以這種方式重設(shè)constructor屬性會導(dǎo)致它的[[Enumerable]]特性被設(shè)置為true。默認(rèn)情況下,constructor屬性是不可枚舉的。因此如果你使用兼容ECMASCript5的JavaScript引擎,可以試一試Object.definePropety()。 function Person() { }Person.prototype = {constructor: Person,name: "zxj",age: 29,sayName: function () {alert(this.name);} };Object.defineProperty(Person.prototype,"constructor",{enumerable:false,value:Person });4、原型的動態(tài)性
? ? 由于在原型中查找值的過程是一次搜索,因此我們對原型對象所做的任何修改都能夠立即從實例上反映出來——即使是先創(chuàng)建了實例后修改原型也照樣可以,如下所示: function Person() { }var friend = new Person();Person.prototype.sayHi = function () {alert("hi"); }friend.sayHi(); //"hi" ? ? 盡管可以隨時為原型添加屬性和方法,但如果我們重寫了整個原型對象,那么情況就不一樣了。我們知道,調(diào)用構(gòu)造函數(shù)時會為實例添加一個指向最初原型的[[Prototype]]指針,而把原型修改為另一個對象就等于切斷了構(gòu)造函數(shù)與最初原型之間的聯(lián)系。一定要記住:實例中的指針僅僅指向原型,而不是構(gòu)造函數(shù)。如下例子: function Person() { }var friend = new Person();Person.prototype = {constructor: Person,name: "zxj",age: 29,job: "Software Engineer",sayName: function () {alert(this.name);} };friend.sayName(); //error 找不到該方法 、5、原生對象的原型
? ? 原型模式的重要性不僅體現(xiàn)在創(chuàng)建自定義類型方面,就連所有原生的引用類型,都是采用這種模式創(chuàng)建的。所有引用類型(Object、Array、String,等等)都在構(gòu)造函數(shù)的原型上定義了方法。例如,在Array.prototype中可以找到sort()方法,而在String.prototype中可以找到substring()方法,如下所示: alert(typeof Array.prototype.sort); //"function" alert(typeof String.prototype.substring); //"function" ? ? 通過原生對象的原型,不僅可以取得所有默認(rèn)方法的引用,而且也可以定義新方法。如下所示: String.prototype.startWith = function (text) {return this.indexOf(text) == 0; }var msg = "Hello World";alert(msg.startWith("Hello")); //true6、原型對象的問題
? ? 原型模式的缺點。首先,它省略了為構(gòu)造函數(shù)傳遞初始化參數(shù)這一環(huán)節(jié),結(jié)果所有的實例在默認(rèn)情況下都取得了相同的值。原型模式最大的問題是由其共享的本性所導(dǎo)致的。 Person.prototype = {constructor: Person,name: "zxj",age: 29,job: "Software Engineer",friends: ["saly", "geil"],sayName: function () {alert(this.name);} };var person1 = new Person(); var person2 = new Person();person1.friends.push("van");alert(person1.friends); //"saly","geil","van" alert(person2.friends); //"saly","geil","van" alert(person1.friends === person2.friends) //問題出來了,person1結(jié)交了新朋友意味著person2也必須結(jié)交這個朋友 ? ? 我們可以看到,當(dāng)一個對象想獲取獨有的操作時,原型模式的共享就是最大的阻礙。 ??
?
?
轉(zhuǎn)載于:https://www.cnblogs.com/zxj159/archive/2013/05/20/3089513.html
總結(jié)
以上是生活随笔為你收集整理的Javascript之创建对象(原型模式)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 北京环球影城年票多少钱一张
- 下一篇: 两种方法将Android NDK sam