首頁  >  文章  >  web前端  >  在JavaScript中實作類別的方式探討_javascript技巧

在JavaScript中實作類別的方式探討_javascript技巧

WBOY
WBOY原創
2016-05-16 17:24:13858瀏覽

在 javascript 中有很多方式來創建對象,所以創建對象的方式使用起來非常靈活。那麼,到底哪一種方式是最恰當的物件創建方式呢?建構模式,原型模式還是物件原意模式(Object literal)呢?

但這些模式具體又是怎麼回事呢?

在開始講解之前,讓我們先清楚地介紹一下關於 javascript 基本知識。

有沒有可能在 javascript 中實現物件導向程式設計的方式呢?

答案是可能的,javascript 是可以創建物件的!這種物件可以包含資料及能夠操作資料的方法,甚至可以包含其他物件。它沒有類別但擁有建構函數;它沒有類別繼承機制,但是可以透過原型(prototype)實現繼承。

現在看起來,我們已經了解了在 javascript 中建立物件及實作基於物件程式設計時所必須的組成部分。

我們都知道 javascript 擁有私有變數。一個透過「var」關鍵字定義的變量,只能在函數體中被訪問,而不能在函數外被訪問。那麼,如果我們不透過使用「var」關鍵字來定義變數會怎麼樣呢?我們現在不對這個問題進行深入探討,可能是透過「this」進行訪問的,我會在另外的時間來詳細講述這個問題。

現在回到之前的問題。到底哪一種方式是最恰當的物件創建方式呢?
讓我們用已經知道的知識,透過創建Person的物件是來試驗一下。

複製程式碼 程式碼如下:

var Person = { firstName : 'John' ,
lastName : 'Cody',
fullName : '',
message : '',

createFullName : function () {
fullName = this.firstName ' this. lastName;
},

changeMes​​sage : function (msg) {
this.message = msg;
},

getMessage : function (>},

getMessage : function () {this
.createFullName();
return this.message ' ' fullName;
}
}

Person.firstName = 'Eli';
Person.lastName = 'Flowers' Person.changeMes​​sage('welcome');
var message = Person.getMessage(); // welcome Eli Flowers
alert(message);


這是物件原意模式( literal pattern)。這非常接近我們經常創建物件的方式。如果你不需要關心私有/包裝的成員,並且你知道不將創建這個物件的實例。那麼,這種方式將會很適合你。公有的成員可以做所有私有成員的事情,不是嗎?但是,這不是一個類,而是一個物件而已,不能被建立實例並且不能被繼承。

讓我們嘗試下其他的方面: 代碼如下:


var Person = {
firstName : 'John',
lastName : 'Cody',
fullName : '',
message : '',

createFullName : function ) {
fullName = this.firstName ' ' this.lastName;
},

changeMes​​sage : function (msg) {
this.message = msg; >
getMessage : function () {
this.createFullName();
return this.message ' ' fullName;
} }

Person.firstName = 'Eli>
Person.firstName = 'Eli ';
Person.lastName = 'Flowers'
Person.changeMes​​sage('welcome');
var message = Person.getMessage(); // welcome Eli Flowers
alert(message);


這是一種建構模式的實例(Constructor Pattern)。那麼,這是類別還是物件呢?應該 兩種都算是吧。我們能夠在當請求時把它當作物件Person來使用。它畢竟也只是一個函數而已。然而,它可以透過使用“new”關鍵字來實現創建新的實例功能。

在使用這種方式時,我們需要時刻記住以下要點:

1. 無論什麼時候這個函數被調用時,它擁有一個特別的變量叫做“this”並且可以在全域範圍內使用。全域範圍依賴這個函數本身的作用範圍。

2. 無論何時透過「new」關鍵字建立這個函數的實例,「this」變數指向這個函數本身,而這個「new」操作將會影響到函數體內的程式碼被執行。這也正是建構模式。

3. 任何附加到「this」變數下的變數都會成為公有屬性並且任何透過「var」關鍵字定義的變數都將是屬於私有屬性。

4. 一個附加到「this」下的函數叫做特權函數,它可以存取所有的私有變數以及被附加到「this」下的函數及變數。

5. 私有函數可以存取到其他私有變數及私有函數。

6. 私有函數不能直接存取被附加到「this」變數和函數。我們可以透過創建一個私有變數「_that」並且將它賦值為「this」的方式來實現。

7. 任何私有變數及函數對於其他私有函數及其他被附加到「this」的函數是可用的。這完全是可能的再javascript的作用範圍下。

8. 一個變數:不是透過「var」關鍵字,也不是附加到「this」變數上以獲得全域作用範圍的。例如,對於一個自訂函數的作用範圍。需要再一次了解作用域及群聚的知識。

這已經實現了我們想要的大部分要求了,但是,有時「this」和「that」這兩個入口變數很容易造成給人帶來疑惑。尤其對於那些一直堅持要求純粹私有的人來說,更容易迷惑。

讓我們再稍微修改下試試看。
複製程式碼 程式碼如下:

var Person = function () {


var Person = function () {
//private
var firstName = 'John';
var lastName = 'Cody';
var fullName = '';
var message = '';


var message = '';


var message = '';


var message = '';


var message = '';


var message = '';


var message = '';


var >var createFullName = function () {
fullName = firstName ' ' lastName;
}

//public setters
var setMessage = function (msg) {
message = msg;
}

var setFirstName = function (fName) {
firstName = fName;
}

var setLastName = function (lName) {
lastName = lName;
}

var getMessage = function () {
createFullName();
return message ' ' fullName;
}

//functions expos >return {
setFirstName: setFirstName,
setLastName: setLastName,
setMessage: setMessage,
getMessage: getMessage } ; person1 = new Person(); person1.setFirstName('Eli'); person1.setLastName('Flowers'); person1.setMessage('welcome');
var message = person1 .getMessage(); // welcome Eli Flowers alert(message); 這是一個顯示模式(Revealing Pattern)。非常感謝 Christian Heilmann。使用這種模式的方式就是把請求的"getters" 和 "setters" 當作屬性使用。我們很多都是從傳統的Java程式設計中找到這樣的身影並且很明顯地知道實現它其實並不復雜。這同樣是一種類似當類別繼承自一個介面的情況。 這種模式大部分方面都實現得很好,僅僅只有一個很微小的問題。每一次當一個類別的實例被創建時。這個新建立的物件獲得了一份變數和函數的拷貝。現在,拷貝變數是沒有問題的,我們希望每個物件的資料都是屬於物件自身的,那麼,成員函數呢?他們只是操作數據而已。那麼,為什麼需要拷貝他們呢? 這正是原型模式(Prototype)的優勢所在。在所有實例中,所有東西都是被創建成一個原型,並且能夠相互分享。我們僅僅需要做的就是依據原型建立共有函數。 複製程式碼 程式碼如下:

var Person = function () {

//private
varwelcomeMessage = '歡迎';
var fullName = '';
var 名字= '';
var fullName = '';
var 名字= '';
var 姓= "";
var createFullName = function () {
Person.prototype.setFirstName('asdsad');
全名= 名字' ' 姓氏;
};

//建構子
var Person = function () { }; // 每次都會建立

//public
Person.prototype = {
getFullName: function ( ) {
createFullName();
回傳welcomeMessage ' ' fullName;
},
setFirstName: function (fName) {
firstName = fName
},
}, function (lName) {
lastName = lName;
},
ChangeMes​​sage: function (mesg) {
welcomeMessage = mesg;
}
}
}
>回傳新的Person(); // 人; //新人();
};


var person1 = new Person();
person1.setFirstName('Eli' );
person1.setLastName('花');
person1.ChangeMes​​age('歡迎');
var message = person1.getFullName(); // 歡迎asdsad 花
alert (message);


原型模式存在的一個問題是它無法訪問血管電極及血管函數,正因為這個問題,我們才會介紹閉包以及組織始終好類中存在的代碼以使得創建它在全域範圍內不會變得很混亂。所有都是屬於 Person 類別的作用範圍內。

另外一個問題是每次實例建立時,所有的程式碼都會重複執行,包括繼承的綁定。對我們中的一部分人來說,這只是一個效率問題。處理好這個問題的一種方式只是在需要的共有函數不可用的情況下綁定這個原型。

這樣將會啟用綁定原型操作只是在第一個實例被建立時執行,並且之後所有其他實例都將僅進行檢查操作。不幸的是,這仍然無法解決我們上面提到的範例中的問題問題,因為我們只有再來一次建立用於產生一個閉包的函數才能達到這樣的效果。這樣的話,至少我們減少了一部分記憶體的使用。

等等,還有另一個問題是外部函數不能直接存取原型函數。

為什麼你們一定需要外部函數和外部變數?我知道你一定是想實現類別的封裝性,想確保類別中的屬性或內部的資料不會被突然修改了或被內部的其他程式所修改,或是任何其他的操作…

你應該記住你是不能將javascript 程式碼編譯成二進位的,對於這種情況,你在主機板很煩惱火吧,這樣程式碼總是可用的。所以,如果有人想搞亂程式碼的話,不管你真正沒有實物或沒有實物,不管你將程式碼給團隊中一定的其他成員或賣掉去,他們都可以攪亂程式碼。實現樹化可能有那麼一點點幫助吧。
另一個其他程式設計者使用的技巧是使用預定命名,使用底線「_」給所有你想設計成樹的任何的複製程式碼
程式碼如下:


(function () {
var Person = function () {
this._fullName = ''
; this.firstName = ''; "";
_that = this;

this._createFullName = function () {
this.ChangeMes​​​​sage('Namaste');
this.ChangeMes​​​​sage('Namaste');
this ._fullName = this.firstName ' ' this.姓;
};
}

//用於程式碼最佳化的共用函數
Person.prototype = {
constructor: Person ,
getFullName: function () {
this._createFullName();
回傳this.welcomeMessage ' ' this._fullName;
},
ChangeMes​​message: functionmessage: function (mesgage) {
this.welcomeMessage = mesg;
}
}

this.Person = Person;
})();

var person1 = new Person() ;
person1.firstName = 'Eli';
person1.lastName = '花';
person1.ChangeMes​​age('歡迎');
var message = person1.getFullName(); // Namaste Eli Flowers
alert(message);

我不是說你不應該考慮 “private” 或類似的知識。你是程式碼的設計者,所以你將知道怎麼來管理並且知道怎麼做才是最好的。根據你的需求,你可以使用任何一種設計模式或多個設計模式組合一起使用。

無論你決定採用哪種設計模式,始終記住做盡量少的事情,不要在全局作用範圍內實現閉包,盡量減少內存洩露,以及優化代碼,並且組織好代碼。所以,盡量多了解些作用域,閉包以及 “this” 的表現行為。

最後,祝程式愉快!

譯後感

經常使用 javascript,對於它的印像一直都是直接拷貝過來就可以用的。最近使用 extjs,它的類別框架非常好用。從這樣文章也明白在 javascript 中實作類別的各種方式,以及在文章最後討論了類別中私有成員的實作情況。
陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn