js物件導向程式設計之建構函式

2022-02-27 17:28:35 字數 4159 閱讀 1133

工廠模式是乙個比較廣為人知的模式,這種模式將細節抽象出來。**如下

function

createperson(name,age,job)

returno;}

var person1=createperson("ds",12,"dada");

var person2=createperson("ds2",122,"dada2");

給他所需要的材料,他就會返回乙個物件。解決了大量重複**的問題。可是又有乙個問題,就是每個返回的物件都是object。每個物件的的型別部分卻別開來。所以有個新的模式來解決這個問題。

廢話不多說,還是先上**吧。

function

person(name,age,job)

}var person1=new person("ds",12,"dada");

var person2=new person("ds2",122,"dada2");

第二種的使用了new的關鍵字。實際上經歷了4步。1,建立了乙個新物件。2,將建構函式的作用域賦給建立的變數。3,執行**。4,返回新的物件。

person1和person2是不同的例項。兩個對像有乙個constructor(建構函式)指向person的函式本身。而constructor就是用來表示物件的型別。這也是建構函式模式和工廠模式的不同。而且想object和array的就是js中原生的建構函式。建立自定義的建構函式意味著可以為他的例項標識為一種特定的型別。

其實建構函式也是函式知識呼叫的方式不同而已。建構函式也可以普通的方式呼叫。

var p=new

object();

person.call(p,"sss",22,"222");

但是建構函式並不是沒有問題,比如說上面的那個sayname(),其實person1和person2的sayname其實並不是同乙個funcition的例項。也就是說每new乙個物件,sayname本身的方法也被new了一次。所有例項的sayname都是獨立的並沒有指向同乙個方法。解決的方法也有可以將方法提取到全域性變數。

function

person(name,age,job)

function

sayname()

但是問題又來了,sayname作為全域性變數的話卻只能被person呼叫,有點不太符合全域性變數的定義。重要的是如果方法很多的話又要在全域性變數中新增許許多多的方法。好在這些問題都可以通過原型模式來解決

在說原型模型的時候,應該先說明一下prototype(原型)是什麼?其實它就是乙個指標,指向乙個物件。這個物件就是可以給特定型別的所有例項共享的屬性和方法。還是看**吧。

上**釋了物件,例項,原型和建構函式之間的關係。

在js中,只要建立乙個新函式就會為該函式建立乙個prototype的屬性。指向函式的原型物件。原型物件有都會有個constructor的指標,指向原函式。每個例項也有個指標[[prototype]],指向原型。其實每個例項和建構函式是沒有直接關係的,是通過原型將例項和建構函式關聯起來。

其實建構函式還有個更簡單的寫法。

function

person()

person.prototype=

}

但這樣又有個問題,這樣就相當與重寫了整個prototype,js本身是不會給它生成constructor的。也就是說這個原型物件中沒有指向person的指標。但可以給它顯示的給它賦值。

function

person()

person.prototype=

}

但還有個小問題,就是當這樣顯示的給原型指定建構函式的話,它的[[enumerable]]會預設為true,原生的constructor是不能被列舉的。如果一定要相容ecmascript5的話可以改寫成下面**

function

person()

person.prototype=

}object.defineproperty(perosn.prototype,"constructor",)

defineproperty這個方法的話在上一遍中有提到過。用來給屬性顯示的賦值特性的方法。

原型模式還有個動態性,應為本身在例項中它是已指標的形式存在的。可以動態的給原型新增方法和屬性。可以動態的新增到例項上面。當然原型物件也不是完美的,也是存在問題的。下面來看一段**。

function

person()

person.prototype=

}var person1=new

person();

var person2=new

person();

person1.friends.push("44");

alert(person1.friends);

alert(person2.friends);

問題就在於所有的例項(person1,person2)的指標都指向了乙個陣列。person1對陣列操作之後,會改變原型中的資料,那麼person2的friend也就變了。實際例項一般都是要有屬於自己的全部屬性的。所以這才是很少有人單獨使用原型模式的原因。

其實看到這裡,我們會發現原型模式和構造模式的一些問題。建構函式模式是所有的屬性都是為每乙個例項重新的初始化乙個出來。而原型模式則是為所有的例項公用乙個屬性或者方法。其實兩種方法都有點極端,在乙個物件中,其實情況是多樣的,有些屬性需要獨立,有些需要共享。所有就有了這種組合模式的出現。可謂是取了兩種模式之長。

function

person(name,age,job)

person.prototype=

}

將需要獨立出來屬性放在建構函式裡面進行初始化,然後類似方法的屬性則通過原型的方式進行賦值。

這是在ecmascript5中使用最廣泛的建立自定義型別方式。

其實在物件語言中如c#中是沒有原型一說的,只有乙個建構函式。為了盡量的消除這點差異便又來動態原型模式。它就是將所有的資訊都封裝到了建構函式中。

function

person(name,age,job)}}

不同之處就是在建構函式中有個判斷。這個判斷保證裡面的**只在初始化的時候執行一遍。這樣就可用同乙個建構函式來完成組合模式的作用了。

這是乙個比較少用的模式。其實他和工廠方式沒什麼太大的區別。看個例子。

function

person(name,age,job)

returno;}

var person1=new person("dd",12,"dd");

是不是和工廠模式一毛一樣??其實唯一的區別就在於呼叫的時候,寄生模式使用了new的方法進行初始化。這種模式一般使用在什麼場景呢?

假設我們想在原生的array的基礎上改造一下便可以這樣

function

specialarray()

return

value;

}var colors=new specialarray("11","2","33");

alert(colors.topopedstring());

在原有的型別上進行改造,可以用到寄生模式,有點類似於c#中的擴充套件。但是這樣產生的例項和建構函式,原型是沒有任何關係的。所以建議在可以使用它模式的前提下就不要用這種模式了。

js 物件導向 建構函式

面向過程的時候我們寫 的方式是獲取元素 定義訊號量 定義鎖都是遇見需求就定義乙個變數 但是 無法復用 並且主要就是定義的 是變數 物件導向就是操作的是物件 把寫 的風格從面向過程改為物件導向 把變數封裝成物件即可 面向過程 var username 王老五 var age 13 var 男 cons...

物件導向程式設計之成員函式

1.成員函式 1 類內實現成員函式 inline函式 示例 2 類外實現成員函式 示例 main.cpp include include test.h usingnamespace std intmain test.cpp include test.h includeusingnamespace s...

JS物件導向 建構函式 繼承

繼承 子類繼承父類的屬性和方法 好處 減少 量,公共的父類可以復用.降低耦合度.js裡實現繼承的方法 1.通過改變構造建構函式中物件的指向實現繼承 2.通過原型鏈實現繼承.function animal function cat var cat new cat new出乙個例項改變呼叫物件的方法 1...