摘要:原型模式就是通過(guò)調(diào)用構(gòu)造函數(shù)而創(chuàng)建的那個(gè)對(duì)象實(shí)例的原型對(duì)象。我們來(lái)看下面一個(gè)例子來(lái)理解這句話與構(gòu)造函數(shù)模式不同的是,新對(duì)象的這些屬性和方法是由所有實(shí)例共享的。原型對(duì)象的問(wèn)題首先,它省略了為構(gòu)造函數(shù)傳遞初始化參數(shù)這一環(huán)節(jié)。
最近因?yàn)樵诮o一個(gè)小同學(xué)做學(xué)習(xí)計(jì)劃,所以也記錄一些知識(shí)點(diǎn),便于后面的同學(xué)的學(xué)習(xí)交流。這篇文章是關(guān)于Javascript的面向?qū)ο蟮某绦蛟O(shè)計(jì),主要從三個(gè)方面來(lái)介紹,1. 理解對(duì)象屬性; 2. 理解并創(chuàng)建對(duì)象; 3. 理解繼承
一、理解對(duì)象屬性
首先我們來(lái)理解Javascript對(duì)象是什么?在Javascript中,萬(wàn)物皆對(duì)象。其中創(chuàng)建自定義對(duì)象的最簡(jiǎn)單的方式就是創(chuàng)建一個(gè)Object的實(shí)例,如下:
var person = new Object(); person.age = 29; // 對(duì)象字面量的形式: var person = { age: 29 };
ECMAScript中有兩種屬性:數(shù)據(jù)屬性和訪問(wèn)器屬性。
數(shù)據(jù)屬性:
其中數(shù)據(jù)屬性有四個(gè)描述其行為的特性:
Configurable: 表示能都通過(guò)delete刪除屬性從而重新定義屬性。
Enumerable: 表示能否通過(guò)for in 循環(huán)返回屬性。
Writable: 表示能否修改屬性的值。
Value: 包含這個(gè)屬性的數(shù)據(jù)值。
要修改屬性默認(rèn)的配置,必須使用Object.defineProperty(), 這個(gè)方法接收三個(gè)參數(shù):屬性所在的對(duì)象,屬性的名字和一個(gè)描述性對(duì)象。
比如:
var person = {}; Object.defineProperty(person, ’name’, { writable: false, value: ’Nicholas" }); alert(person.name); //Nicholas person.name = ‘Greg’; alert(person.name); //Nicholas
訪問(wèn)器屬性:
訪問(wèn)器屬性包含一對(duì)setter和getter函數(shù)。包含如下4個(gè)特性:
Configurable:能否被delete刪除屬性重新定義。默認(rèn)值:true
Enumerable:能否被for-in枚舉。默認(rèn)值:true
Get:讀取屬性值。默認(rèn)值:undefined
Set:寫(xiě)入屬性值。默認(rèn)值:undefined
var dog = { _age: 2, weight: 10 } Object.defineProperty(dog, "age", { get: function () { return this._age }, set: function (newVal) { this._age = newVal this.weight += 1 } })
知道了對(duì)象的屬性,那么我們創(chuàng)建對(duì)象的方式是什么呢?
二、創(chuàng)建對(duì)象的方式
創(chuàng)建對(duì)象的方式通常有下面幾種方式:
1、工廠模式
我們舉個(gè)例子:
function createPerson(name, age, job) { var o = new Object(); o.name = name; o.age = age; o.job = job; o.sayName = function () { alert(this.name); }; Return o; } var person = createPerson(‘Greg’, 27, ‘Doctor’);
工廠模式雖然解決了創(chuàng)建多個(gè)相似對(duì)象的問(wèn)題,但卻沒(méi)有解決問(wèn)題識(shí)別的問(wèn)題(即怎樣知道一個(gè)對(duì)象的類(lèi)型)
2、構(gòu)造函數(shù)模式
我們舉個(gè)例子:
**function Person(name, age, job) {
this.name = name; this.age = age; this.job = job; this.sayName = function () { alert(this.name);
};
}
var person = new Person(‘Greg’, 27, ‘Doctor’);**
構(gòu)造函數(shù)始終都應(yīng)該以一個(gè)大寫(xiě)字母開(kāi)頭,而非構(gòu)造函數(shù)則應(yīng)該以一個(gè)小寫(xiě)字母開(kāi)頭。這里要提的一個(gè)屬性是Constructor, 每個(gè)new 出來(lái)的實(shí)例都有一個(gè)Constructor(構(gòu)造函數(shù))屬性,該屬性指向構(gòu)造函數(shù)。
對(duì)象的Constructor屬性最初是用來(lái)標(biāo)識(shí)對(duì)象類(lèi)型的。但是,提到檢測(cè)對(duì)象類(lèi)型,還是instanceof操作符更好可靠一些。
alert(person1 instanceof Object); //true
構(gòu)造函數(shù)的問(wèn)題問(wèn)題就是,每個(gè)方法都要在每個(gè)實(shí)例上重新創(chuàng)建一遍,當(dāng)然,可以把函數(shù)定義轉(zhuǎn)移到構(gòu)造函數(shù)外部來(lái)解決這個(gè)問(wèn)題,如下實(shí)例:
**function Person(name, age, job) {
this.name = name; this.age = age; this.job = job; this.sayName = sayName;
}
function sayName() {
alert(this.name);
}
var person = new Person(‘Greg’, 27, ‘Doctor’);**
那么這里的問(wèn)題就是:在全局作用域中定義的函數(shù)實(shí)際上被只能被某個(gè)對(duì)象調(diào)用,這讓全局作用域有點(diǎn)名不副實(shí)。而更讓人無(wú)法接受的是:如果獨(dú)享需要定義很多方法,那么就要定義很多個(gè)全局函數(shù)。下面我們來(lái)看看原型模式是不能解決這個(gè)問(wèn)題。
3、原型模式
prototype就是通過(guò)調(diào)用構(gòu)造函數(shù)而創(chuàng)建的那個(gè)對(duì)象實(shí)例的原型對(duì)象。我們來(lái)看下面一個(gè)例子來(lái)理解這句話:
function Person() { } Person.prototype.name = “Nicholas”; Person.prototype.age = 29; Person.prototype.job = “Software Engineer”; Person.prototype.sayName = function() { alert(this.name); }; var person1 = new Person(); person1.sayName(); // “Nicholas”
與構(gòu)造函數(shù)模式不同的是,新對(duì)象的這些屬性和方法是由所有實(shí)例共享的。
針對(duì)這個(gè)特性,我們要注意的幾個(gè)點(diǎn)就是。
第一,如果實(shí)例的屬性與方法與原型的屬性和方法同名,那誰(shuí)的優(yōu)先級(jí)高呢?
當(dāng)然是創(chuàng)建出來(lái)的實(shí)例的屬性和方法的優(yōu)先級(jí)高。
第二,實(shí)例的屬性與方法的修改會(huì)影響原型同名的屬性和方法嗎?
不會(huì)
這里提一下hasOwnProperty(), 使用hasOwnProperty()方法可以檢測(cè)一個(gè)屬性是存在于實(shí)例中,還是存在原型中。
第三,如何判斷某個(gè)屬性是存在原型中?
function hasPrototypeProperty(object, name) { return !Object.hasOwnProperty(name) && (name in object); }
hasOwnProperty()只在屬性存在于實(shí)例中才返回true, 因此只要in操作符返回true而hasOwnProperty()返回false, 就可以確定屬性是原型中的屬性、這里說(shuō)下Constructor, 每創(chuàng)建一個(gè)函數(shù),就會(huì)同時(shí)創(chuàng)建它的Prototype對(duì)象,這個(gè)對(duì)象也會(huì)自動(dòng)獲得Constructor屬性。
我們來(lái)看一個(gè)例子:
function Person() { } Person.prototype = { constructor: Person, name: “Nichloas”, age: 29, job: “Software Engineer”, sayName: function () { alert(this.name); } };
以上代碼特意包含了一個(gè)Constructor屬性,并將它的值設(shè)置為Person, 從而確保了通過(guò)該屬性能夠訪問(wèn)到適當(dāng)?shù)闹怠5?,以這種方式重設(shè)Constructor屬性會(huì)導(dǎo)致它的Enumerable特性被設(shè)置為true, 默認(rèn)情況下原生的Constructor屬性是不可枚舉的。
Object.defineProperty(Person.prototype, “Constructor”, { enumerable: false, value: Person });
原型對(duì)象的問(wèn)題:
首先,它省略了為構(gòu)造函數(shù)傳遞初始化參數(shù)這一環(huán)節(jié)。
然后,原型中所有屬性是被很多實(shí)例共享的,對(duì)于包含引用類(lèi)型值的屬性來(lái)說(shuō),問(wèn)題比較突出。所以,使用最多的方式使用構(gòu)造函數(shù)和原型模式
4、組合使用構(gòu)造函數(shù)模式和原型模式
function Person(name, age, job) { this.name = name; this.age = age; this.job = job; this.friends = [“Shelby”, “Court”]; } Person.prototype = { constructor: Person, sayName: function () { alert(this.name); } }; var person = new Person(‘Greg’, 27, ‘Doctor’);
知道了創(chuàng)建對(duì)象的方式,那么在Javascript中我們?nèi)绾蝸?lái)繼承對(duì)象呢?
三、繼承
1、原型鏈
構(gòu)造函數(shù),原型和實(shí)例的關(guān)系:每一個(gè)構(gòu)造函數(shù)都也有一個(gè)原型對(duì)象,原型對(duì)象都包含一個(gè)指向構(gòu)造函數(shù)的指針,而實(shí)例都包含一個(gè)指向原型對(duì)象的內(nèi)部指針。那么,假如我們讓原型對(duì)象等于另一個(gè)類(lèi)型的實(shí)例,結(jié)果會(huì)怎么樣呢?顯然,此時(shí)的原型對(duì)象將包含一個(gè)指向另一個(gè)原型的指針,相應(yīng)的,另一個(gè)原型中也包含也包含著一個(gè)指向一個(gè)構(gòu)造函數(shù)的指針,假如另一個(gè)原型又是另一個(gè)類(lèi)型的實(shí)例,那么上訴關(guān)系依然成立,我們來(lái)看下面一個(gè)例子.
function SuperType() { this.property = true; } SuerType.prototype.getSuperValue = function () { return this.property; }; function SubType() { This.subProperty = false; } // 繼承了SuperType SubType.prototype = new SuperType(); SubType.prototype.getSubValue = function () { return this.subProperty(); };
var instance = new SubType();
alert(instance.getSuperValue); // true
這個(gè)例子中,SubType繼承了SuperType,而SuperType繼承了Object。如果要確定原型和實(shí)例的關(guān)系,可以用instanceOf操作符與isPropertyOF()方法。
如 instance instanceOf object; // true
Object.prototype isPropertype(instance); // true
但是通過(guò)原型鏈實(shí)現(xiàn)繼承時(shí),不能使用對(duì)象字面量創(chuàng)建原型方法。
function SuperType() { this.property = true; } SuerType.prototype.getSuperValue = function () { return this.property; }; function SubType() { This.subProperty = false; } // 繼承了SuperType SubType.prototype = new SuperType(); // 使用字面量添加新方法,會(huì)導(dǎo)致上一行代碼無(wú)效 SubType.prototype = { getSubValue: function () { return this.subproperty; }, someOtherMethod: function () { return false; } }; var instance = new SubType(); alert(instance.getSuperValue); // error
接下來(lái),我們來(lái)說(shuō)下原型鏈繼承的問(wèn)題:
第一,最主要的問(wèn)題來(lái)自包含引用類(lèi)型值的原型。包含引用類(lèi)型值的原型屬性會(huì)被所有實(shí)例共享,而這也正是為什么要在構(gòu)造函數(shù)中,而不是在原型對(duì)象中定義屬性的原因。
第二,在創(chuàng)建子類(lèi)型的實(shí)例時(shí)候,不能向超類(lèi)型的構(gòu)造函數(shù)中傳遞參數(shù)。
2、借用構(gòu)造函數(shù)
function SuperType(name) { this.name = name; } function SubType() { // 繼承了SuperType, 同時(shí)還傳遞了參數(shù) SuperType.call(this, “Nicholas”); this.age = 29; } var instance = new SubType(); alert(instance.name); // “Nicholas”
借用構(gòu)造函數(shù)的問(wèn)題,方法都在構(gòu)造函數(shù)中定義,因此函數(shù)復(fù)用就無(wú)從談起了。而且,在超類(lèi)型的原型中定義的方法,對(duì)于子類(lèi)型而言也是不可見(jiàn)的,結(jié)果所有類(lèi)型都只能使用構(gòu)造函數(shù)模式,考慮到這些問(wèn)題,借用構(gòu)造函數(shù)的技術(shù)也是很少多帶帶使用的。
3、組合繼承
組合繼承,指的是將原型鏈和借用構(gòu)造函數(shù)的技術(shù)組合到一塊,從而發(fā)揮二者之長(zhǎng)的一種繼承模式。其背后的思路是使用原型鏈實(shí)現(xiàn)對(duì)原型屬性和放大的績(jī)效,而通過(guò)借用構(gòu)造函數(shù)來(lái)實(shí)現(xiàn)對(duì)實(shí)例屬性的繼承。
function SuperType(name) { this.name = name; this.colors = [“red”, “blue”, “green"] } SuperType.prototype.sayName = function () { alert[this.name]; }; function SubType(name, age) { // 繼承屬性 SuperType.call(this, name); this.age = age; } // 繼承方法 SubType.prototype = new SuperType(); SubType.prototype.sayAge = function () { alert(this.age); }; var instance = new SubType(“Nicholas”, 29); instance.colors.push(“black”); alert(instance.colors); // red, blue, green, black
組合繼承避免了原型鏈和借用構(gòu)造函數(shù)的缺陷,融合了它們的優(yōu)點(diǎn),成為Javascript中最常見(jiàn)的繼承模式。
4、原型式繼承
function object(o) { function F() {} F.prototype = o; return new F(); ] var person = { Name: “Nicholas”, friends: [“Shelby”, “Court”, “Van"] }; var anotherPerson = object(person); anotherPerson.name = “Greg”;
ECMAScipt5通過(guò)新增Object.create()方法規(guī)范化了原型式繼承。
接著上面的例子:
var anotherPerson = Object.create(person); anotherPerson.name = “Greg”;
5、寄生式繼承
寄生式繼承是與原型式繼承緊密相關(guān)的一種思路,它與工廠模式類(lèi)似,即創(chuàng)建一個(gè)僅用于封裝過(guò)程的函數(shù),該函數(shù)在內(nèi)部以某種方法來(lái)增強(qiáng)對(duì)象,最后再像真地是它做了所有工作一樣返回對(duì)象。
例如:
function createAnother(original) { var clone = object(original); clone.sayHi = function () { alert(‘hi’); }; return clone; } var person = { name: ’Nochplas’, friends: [’Shelby’, ‘Court’, ‘Van"] }; var anotherPerson = createAnother(person);
6、組合寄生式繼承
組合繼承是Javascript最常用的繼承模式,不過(guò),組合繼承最大的問(wèn)題就是無(wú)論什么情況下,都會(huì)調(diào)用兩次超類(lèi)型構(gòu)建函數(shù):一次是在創(chuàng)建子類(lèi)型原型的時(shí)候,另一次是在子類(lèi)型構(gòu)造函數(shù)內(nèi)部。
function SuperType(name) { this.name = name; this.colors = [“red”, “blue”, “green"] } SuperType.prototype.sayName = function () { alert[this.name]; }; function SubType(name, age) {. // 繼承屬性 SuperType.call(this, name); // 第二次調(diào)用 SuperType() this.age = age; } // 繼承方法 SubType.prototype = new SuperType(); // 第一次調(diào)用 SuperType() SubType.prototype.sayAge = function () { alert(this.age); };
所謂寄生組合式繼承,即通過(guò)借用構(gòu)造函數(shù)來(lái)繼承屬性,通過(guò)原型鏈的混成形式來(lái)繼承方法。不必為了制定子類(lèi)型的原型而調(diào)用超類(lèi)型的構(gòu)造函數(shù),我們所需要的無(wú)非就是超類(lèi)型原型的一個(gè)副本而已。本質(zhì)上,就是使用寄生式繼承來(lái)繼承超類(lèi)型的原型,然后再將結(jié)果制定給子類(lèi)型的原型。如下:
function inheritPrototype (subType, superType) { var prototype = object (superType.prototype); // 前面的原型式繼承object方法 prototype.constructor = subtype; subtype.prototype = prototype; } function SuperType(name) { this.name = name; this.colors = [“red”, “blue”, “green"] } SuperType.prototype.sayName = function () { alert[this.name]; }; function SubType(name, age) {. // 繼承屬性 SuperType.call(this, name); this.age = age; } inheritPrototype(SubType, SuperType); SubType.prototype.sayAge = function () { alert(this.age); };
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/109243.html
摘要:很多情況下,通常一個(gè)人類(lèi),即創(chuàng)建了一個(gè)具體的對(duì)象。對(duì)象就是數(shù)據(jù),對(duì)象本身不包含方法。類(lèi)是相似對(duì)象的描述,稱(chēng)為類(lèi)的定義,是該類(lèi)對(duì)象的藍(lán)圖或原型。在中,對(duì)象通過(guò)對(duì)類(lèi)的實(shí)體化形成的對(duì)象。一類(lèi)的對(duì)象抽取出來(lái)。注意中,對(duì)象一定是通過(guò)類(lèi)的實(shí)例化來(lái)的。 showImg(https://segmentfault.com/img/bVTJ3H?w=900&h=385); 馬上就要到七夕了,離年底老媽老爸...
摘要:很多情況下,通常一個(gè)人類(lèi),即創(chuàng)建了一個(gè)具體的對(duì)象。對(duì)象就是數(shù)據(jù),對(duì)象本身不包含方法。類(lèi)是相似對(duì)象的描述,稱(chēng)為類(lèi)的定義,是該類(lèi)對(duì)象的藍(lán)圖或原型。在中,對(duì)象通過(guò)對(duì)類(lèi)的實(shí)體化形成的對(duì)象。一類(lèi)的對(duì)象抽取出來(lái)。注意中,對(duì)象一定是通過(guò)類(lèi)的實(shí)例化來(lái)的。 showImg(https://segmentfault.com/img/bVTJ3H?w=900&h=385); 馬上就要到七夕了,離年底老媽老爸...
摘要:很多情況下,通常一個(gè)人類(lèi),即創(chuàng)建了一個(gè)具體的對(duì)象。對(duì)象就是數(shù)據(jù),對(duì)象本身不包含方法。類(lèi)是相似對(duì)象的描述,稱(chēng)為類(lèi)的定義,是該類(lèi)對(duì)象的藍(lán)圖或原型。在中,對(duì)象通過(guò)對(duì)類(lèi)的實(shí)體化形成的對(duì)象。一類(lèi)的對(duì)象抽取出來(lái)。注意中,對(duì)象一定是通過(guò)類(lèi)的實(shí)例化來(lái)的。 showImg(https://segmentfault.com/img/bVTJ3H?w=900&h=385); 馬上就要到七夕了,離年底老媽老爸...
摘要:是完全的面向?qū)ο笳Z(yǔ)言,它們通過(guò)類(lèi)的形式組織函數(shù)和變量,使之不能脫離對(duì)象存在。而在基于原型的面向?qū)ο蠓绞街?,?duì)象則是依靠構(gòu)造器利用原型構(gòu)造出來(lái)的。 JavaScript 函數(shù)式腳本語(yǔ)言特性以及其看似隨意的編寫(xiě)風(fēng)格,導(dǎo)致長(zhǎng)期以來(lái)人們對(duì)這一門(mén)語(yǔ)言的誤解,即認(rèn)為 JavaScript 不是一門(mén)面向?qū)ο蟮恼Z(yǔ)言,或者只是部分具備一些面向?qū)ο蟮奶卣?。本文將回歸面向?qū)ο蟊疽?,從?duì)語(yǔ)言感悟的角度闡述為什...
摘要:用代碼可以這樣描述安全到達(dá)國(guó)外面向過(guò)程既然說(shuō)了面向?qū)ο?,那么與之對(duì)應(yīng)的就是面向過(guò)程。小結(jié)在這篇文章中,介紹了什么是面向?qū)ο蠛兔嫦蜻^(guò)程,以及中對(duì)象的含義。 這是 javascript 面向?qū)ο蟀鎵K的第一篇文章,主要講解對(duì)面向?qū)ο笏枷氲囊粋€(gè)理解。先說(shuō)說(shuō)什么是對(duì)象,其實(shí)這個(gè)還真的不好說(shuō)。我們可以把自己當(dāng)成一個(gè)對(duì)象,或者過(guò)年的時(shí)候相親,找對(duì)象,那么你未來(lái)的老婆也是一個(gè)對(duì)象。我們就要一些屬性,比...
摘要:對(duì)象重新認(rèn)識(shí)面向?qū)ο竺嫦驅(qū)ο髲脑O(shè)計(jì)模式上看,對(duì)象是計(jì)算機(jī)抽象現(xiàn)實(shí)世界的一種方式。除了字面式聲明方式之外,允許通過(guò)構(gòu)造器創(chuàng)建對(duì)象。每個(gè)構(gòu)造器實(shí)際上是一個(gè)函數(shù)對(duì)象該函數(shù)對(duì)象含有一個(gè)屬性用于實(shí)現(xiàn)基于原型的繼承和共享屬性。 title: JS對(duì)象(1)重新認(rèn)識(shí)面向?qū)ο? date: 2016-10-05 tags: JavaScript 0x00 面向?qū)ο?從設(shè)計(jì)模式上看,對(duì)象是...
閱讀 3807·2021-11-12 10:36
閱讀 3893·2021-09-22 15:48
閱讀 3599·2019-08-30 15:54
閱讀 2670·2019-08-29 16:44
閱讀 2420·2019-08-29 16:08
閱讀 2490·2019-08-29 16:06
閱讀 1368·2019-08-29 15:21
閱讀 3295·2019-08-29 12:39