摘要:在基于原型的面向?qū)ο蠓绞街?,對象則是依靠構(gòu)造函數(shù)和原型構(gòu)造出來的。來看下面的例子優(yōu)點(diǎn)與單純使用構(gòu)造函數(shù)不一樣,原型對象中的方法不會在實(shí)例中重新創(chuàng)建一次,節(jié)約內(nèi)存。
我們所熟知的面向?qū)ο笳Z言如 C++、Java 都有類的的概念,類是實(shí)例的類型模板,比如Student表示學(xué)生這種類型,而不表示任何具體的某個學(xué)生,而實(shí)例就是根據(jù)這個類型創(chuàng)建的一個具體的對象,比如zhangsan、lisi,由類生成對象體現(xiàn)了抽象模板到具體化的過程,這叫做基于類的面向?qū)ο蠓绞?/strong>,而 JavaScript 沒有類的概念,是基于原型的面向?qū)ο蠓绞?/strong>(雖然 Es6 增加了 class,實(shí)質(zhì)是對原型方式的封裝)??偨Y(jié)起來就是以下兩點(diǎn):
在基于類的面向?qū)ο蠓绞街?,對象(object)依靠類(class)來產(chǎn)生。
在基于原型的面向?qū)ο蠓绞街?,對象(object)則是依靠構(gòu)造函數(shù)(constructor)和原型(prototype)構(gòu)造出來的。
面向?qū)ο笳Z言的第一個特性毫無疑問是封裝,在 JS 中,封裝的過程就是把一些屬性和方法放到對象中“包裹”起來,那么我們要怎么去封裝屬性和方法,或者說怎么去創(chuàng)建對象呢(后文統(tǒng)一說創(chuàng)建對象)?下面用逐步推進(jìn)的方式闡述:
對象字面量 --> 工廠模式 --> 構(gòu)造函數(shù) --> 原型模式 --> 構(gòu)造函數(shù)+原型模式對象字面量
JS中創(chuàng)建對象最原始的方式有兩種:
對象字面量
var person = { name: "leon", age: "20", greeting: function() { alert("Hi!"); } }
為Object實(shí)例添加屬性方法
var person = new Object(); person.name = "leon"; person.age = "20"; person.greeting = function() { alert("Hi!"); };
優(yōu)點(diǎn):代碼簡單
缺點(diǎn): 創(chuàng)建多個對象會產(chǎn)生大量的代碼,編寫麻煩,且并沒有實(shí)例與原型的概念。
解決辦法:工廠模式。
工廠模式工廠模式是編程領(lǐng)域一種廣為人知的設(shè)計模式,它抽象了創(chuàng)建具體對象的過程。JS 中創(chuàng)建一個函數(shù),把創(chuàng)建新對象、添加對象屬性、返回對象的過程放到這個函數(shù)中,用戶只需調(diào)用函數(shù)來生成對象而無需關(guān)注對象創(chuàng)建細(xì)節(jié),這叫工廠模式:
function createPerson(name, age) { var person = new Object(); person.name = name; person.age = age; person.greeting = function() { alert("Hi!"); }; return person; } var person1 = createPerson("leon", "20");
優(yōu)點(diǎn):工廠模式解決了對象字面量創(chuàng)建對象代碼重復(fù)問題,創(chuàng)建相似對象可以使用同一API。
缺點(diǎn):因?yàn)槭钦{(diào)用函創(chuàng)建對象,無法識別對象的類型。
解決辦法:構(gòu)造函數(shù)
構(gòu)造函數(shù)JS 中構(gòu)造函數(shù)與其他函數(shù)的唯一區(qū)別,就在于調(diào)用它的方式不同。任何函數(shù),只要通過new 操作符來調(diào)用,那它就可以作為構(gòu)造函數(shù)。來看下面的例子:
function Person(name, age) { this.name = name; this.age = age; this.greeting = function() { alert("Hi!"); }; // return this; } var person1 = new Person("leon", "20"); var person2 = new Person("jack", "21");
通過構(gòu)造函數(shù)new一個實(shí)例經(jīng)歷了四步:
創(chuàng)建一個新對象;
將構(gòu)造函數(shù)內(nèi)的this綁定到新對象上;
為新對象添加屬性和方法;
返回新對象(JS 引擎會默認(rèn)添加 return this;)。
而通過構(gòu)造函數(shù)創(chuàng)建的對象都有一個constructor屬性,它是一個指向構(gòu)造函數(shù)本身的指針,因此就可以檢測對象的類型啦。:
alert(person1.constructor === Person) //true alert(person1 instanceof Person) // true
但是仍然存在問題:
alert(person1.greeting == person2.greeting) //false
同一個構(gòu)造函數(shù)中定義了greeting(),而不同實(shí)例上的同名函數(shù)卻是不相等的,意味著這兩個同名函數(shù)的內(nèi)存空間不一致,也就是構(gòu)造函數(shù)中的方法要在每個實(shí)例上重新創(chuàng)建一次。這顯然是不劃算的。
優(yōu)點(diǎn):解決了類似對象創(chuàng)建問題,且可以檢測對象類型。
缺點(diǎn):構(gòu)造函數(shù)方法要在每個實(shí)例上新建一次。
解決辦法:原型模式。
原型模式終于講到了原型模式,JS 中每個構(gòu)造函數(shù)都有一個prototype屬性,這個屬性是一個指針,指向原型對象,而這個原型對象包含了這個構(gòu)造函數(shù)所有實(shí)例共享的屬性和方法。而實(shí)例對象中有一個proto屬性,它指向原型對象,也就是構(gòu)造函數(shù).prototype == 原型對象 == 對象._proto_,那么對象就可以獲取到原型對象中的屬性和方法啦。同時,所有對象中都有一個constructor屬性,原型對象的constructor指向其對應(yīng)的構(gòu)造函數(shù)。
使用原型,就意味著我們可以把希望實(shí)例共享的屬性和方法放到原型對象中去,而不是放在構(gòu)造函數(shù)中,這樣每一次通過構(gòu)造函數(shù)new一個實(shí)例,原型對象中定義的方法都不會重新創(chuàng)建一次。來看下面的例子:
function Person() { } Person.prototype.name = "leon"; Person.prototype.age = "20"; Person.prototype.greeting = function() { alert("Hi!"); }; var person1 = new Person(); var person2 = new Person(); alert(person1.name); //"leon" alert(person2.name); //"leon" alert(person1.greeting == person2.greeting); //true
優(yōu)點(diǎn):與單純使用構(gòu)造函數(shù)不一樣,原型對象中的方法不會在實(shí)例中重新創(chuàng)建一次,節(jié)約內(nèi)存。
缺點(diǎn):使用空構(gòu)造函數(shù),實(shí)例 person1 和 person2 的 name都一樣了,我們顯然不希望所有實(shí)例屬性方法都一樣,它們還是要有自己獨(dú)有的屬性方法。并且如果原型中對象中有引用類型值,實(shí)例中獲得的都是該值的引用,意味著一個實(shí)例修改了這個值,其他實(shí)例中的值都會相應(yīng)改變。
解決辦法:構(gòu)造函數(shù)+原型模式組合使用。
另外 JS 中還定義了一些與原型相關(guān)的屬性,這里羅列一下:
Object.getPrototypeOf(),取得實(shí)例的原型對象。
Object.getPrototypeOf(person1);
isPrototypeOf(),判斷是不是一個實(shí)例的原型對象。
Person.prototype.isPrototypeOf(person1);
hasOwnProperty(),檢測一個屬性是否存在于實(shí)例中
person1.hasOwnProperty("name");
in,判斷一個屬性是否存在于實(shí)例和原型中。
"name" in person1;構(gòu)造函數(shù)+原型模式
最后一種方式就是組合使用構(gòu)造函數(shù)和原型模式,構(gòu)造函數(shù)用于定義實(shí)例屬性,而共享屬性和方法定義在原型對象中。這樣每個實(shí)例都有自己獨(dú)有的屬性,同時又有對共享方法的引用,節(jié)省內(nèi)存。
function Person(name, age) { this.name = name; this.age = age; } Person.prototype = { constructor: Person, nationality: "China", greeting: function() { alert(this.name); } } var person1 = new Person("leon", "20"); var person2 = new Person("jack", "21"); alert(person1.greeting == person2.greeting) //true
上面代碼中用對象字面量的形式重寫了原型對象,這樣相當(dāng)于創(chuàng)建了一個新的對象,那么它的constructor屬性就會指向Object,這里為了讓它繼續(xù)指向構(gòu)造函數(shù),顯示的寫上了constructor: Person
這種構(gòu)造函數(shù)與原型模式混成的模式,是目前在 JS 中使用最為廣泛的一種創(chuàng)建對象的方法。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/96489.html
摘要:很多情況下,通常一個人類,即創(chuàng)建了一個具體的對象。對象就是數(shù)據(jù),對象本身不包含方法。類是相似對象的描述,稱為類的定義,是該類對象的藍(lán)圖或原型。在中,對象通過對類的實(shí)體化形成的對象。一類的對象抽取出來。注意中,對象一定是通過類的實(shí)例化來的。 showImg(https://segmentfault.com/img/bVTJ3H?w=900&h=385); 馬上就要到七夕了,離年底老媽老爸...
摘要:很多情況下,通常一個人類,即創(chuàng)建了一個具體的對象。對象就是數(shù)據(jù),對象本身不包含方法。類是相似對象的描述,稱為類的定義,是該類對象的藍(lán)圖或原型。在中,對象通過對類的實(shí)體化形成的對象。一類的對象抽取出來。注意中,對象一定是通過類的實(shí)例化來的。 showImg(https://segmentfault.com/img/bVTJ3H?w=900&h=385); 馬上就要到七夕了,離年底老媽老爸...
摘要:很多情況下,通常一個人類,即創(chuàng)建了一個具體的對象。對象就是數(shù)據(jù),對象本身不包含方法。類是相似對象的描述,稱為類的定義,是該類對象的藍(lán)圖或原型。在中,對象通過對類的實(shí)體化形成的對象。一類的對象抽取出來。注意中,對象一定是通過類的實(shí)例化來的。 showImg(https://segmentfault.com/img/bVTJ3H?w=900&h=385); 馬上就要到七夕了,離年底老媽老爸...
摘要:更形象的我們還可以將面向?qū)ο罄斫鉃橐环N宗教信仰。這就導(dǎo)致面向?qū)ο蠼痰某绦騿T們在寫時就很難受。所以為了滿足信仰面向?qū)ο蠼痰男枨笸ㄟ^構(gòu)造函數(shù)的形式模擬了偽類。這個套路的核心就是類那么里沒有類所以其實(shí)是通過構(gòu)造函數(shù)來模擬的偽類。 JS面向?qū)ο笾?【概述】 在學(xué)習(xí)JS的面向?qū)ο笾?我們應(yīng)該先自問這樣幾個問題: 面向?qū)ο笫鞘裁匆馑? 學(xué)習(xí)面向?qū)ο蟮暮诵氖鞘裁? 為什么要學(xué)習(xí)面向?qū)ο?(它的...
摘要:為什么要面向?qū)ο竽阈枰赖拿嫦驅(qū)ο竺嫦驅(qū)ο蟛⒉皇轻槍σ环N特定的語言,而是一種編程范式。后端傳遞過來顯示工人完成狀態(tài)的字段代表未完成,代表已完成。其實(shí)這就是如何消除代碼副作用的問題將副作用隔離。 為什么要面向?qū)ο螅?你需要知道的面向?qū)ο?面向?qū)ο蟛⒉皇轻槍σ环N特定的語言,而是一種編程范式。但是每種語言在設(shè)計之初,都會強(qiáng)烈地支持某種編程范式,比如面向?qū)ο蟮腏ava,而Javascript...
閱讀 2320·2021-09-28 09:45
閱讀 3600·2021-09-24 09:48
閱讀 2266·2021-09-22 15:49
閱讀 3101·2021-09-08 16:10
閱讀 1595·2019-08-30 15:54
閱讀 2328·2019-08-30 15:53
閱讀 3024·2019-08-29 18:42
閱讀 2875·2019-08-29 16:19