最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

關于JavaScript定義類和對象的幾種方式

 更新時間:2010年11月09日 09:06:55   作者:  
在說這個話題之前,我想先說幾句題外話:最近偶然碰到有朋友問我“hoisting”的問題。即在js里所有變量的聲明都是置頂?shù)?,而賦值則是在之后發(fā)生的。
可以看看這個例子:
復制代碼 代碼如下:

var a = 'global';
(function () {
alert(a);
var a = 'local';
})();


  大家第一眼看到這個例子覺得輸出結果是什么?‘global'?還是‘local'?其實都不是,輸出的是undefined,不用迷惑,我的題外話就是為了講這個東西的。
其實很簡單,看一看JavaScript運行機制就會明白。我們可以把這種現(xiàn)象看做“預聲明”。但是如果稍微深究一下,會明白得更透徹。
  這里其實涉及到對象屬性綁定機制。因為所有JavaScript函數(shù)都是一個對象。在函數(shù)里聲明的變量可以看做這個對象的“類似屬性”。對象屬性的綁定在語言里是有分“早綁定”和“晚綁定”之分的。

  【早綁定】
是指在實例化對象之前定義其屬性和方法。解析程序時可以提前轉換為機器代碼。通常的強類型語言如C++,java等,都是早綁定機制的。而JavaScript不是強類型語言。它使用的是“晚綁定”機制。
  【晚綁定】
是指在程序運行前,無需檢查對象類型,只要檢查對象是否支持特性和方法即可??梢栽诮壎ㄇ皩ο髨?zhí)行大量操作而不受任何懲罰。
上面代碼出現(xiàn)的“預聲明”現(xiàn)象,我們大可用“晚綁定”機制來解釋。在函數(shù)的作用域中,所有變量都是“晚綁定”的。 即聲明是頂級的。所以上面的代碼和下面的一致:
復制代碼 代碼如下:

var a = 'global';
(function () {
var a;
alert(a);
a = 'local';
})();

在alert(a)之前只對a作了聲明而沒有賦值。所以結果可想而知。

<!-- 題外話到此結束 -->
  RT:本文要說的是,在JavaScript里,我所知道的幾種定義類和對象的方式:<! -- 聲明:以下內容大部分來自《JavaScript高級程序設計》,只是個人敘述方式不同而已 -- >
  【直接量方式】
  使用直接量構建對象是最基礎的方式,但也有很多弊端。
復制代碼 代碼如下:

var Obj = new Object;
Obj.name = 'sun';
Obj.showName = function() {
alert('this.name');
}

我們構建了一個對象Obj,它有一個屬性name,一個方法showName。但是如果我們要再構建一個類似的對象呢?難道還要再重復一遍?
NO!,我們可以用一個返回特定類型對象的工廠函數(shù)來實現(xiàn)。就像工廠一樣,流水線的輸出我們要的特定類型結果。
  【工廠方式】
復制代碼 代碼如下:

function createObj(name) {
var tempObj = new Object;
tempObj.name = name;
tempObj.showName = function () {
alert(this.name);
};
return tempObj;
}
var obj1 = createObj('obj_one');
var obj2 = createObj('obj_two');

這種工廠函數(shù)很多人是不把他當做構建對象的一種形式的。一部分原因是語義:即它并不像使用了運算符new來構建的那么正規(guī)。還有一個更大的原因,是因為這個工廠每次產出一個對象都會創(chuàng)建一個新函數(shù)showName(),即每個對象擁有不同的版本,但實際上他們共享的是同一個函數(shù)。
有些人把showName在工廠函數(shù)外定義,然后通過屬性指向該方法,可以避開這個問題:
復制代碼 代碼如下:

function showName () {
alert(this.name);
}
function createObj(name) {
var tempObj = new Object;
tempObj.name = name;
tempObj.showName = showName;
return tempObj;
}
var obj1 = createObj('obj_one');
var obj2 = createObj('obj_two');

可惜的是,這種方式讓showName()這個函數(shù)看起來不像對象的一個方法。
  【構造函數(shù)方式】
這種方式是為了解決上面工廠函數(shù)的第一個問題,即沒有new運算符的問題??墒堑诙€問題它依然不能解決。我們來看看。
復制代碼 代碼如下:

function Obj(name) {
this.name = name;
this.showName = function () {
alert(this.name);
}
}
var obj1 = new Obj('obj_one');
var obj2 = new Obj('obj_two');

它的好處是不用在構造函數(shù)內新建一個對象了,因為new運算符執(zhí)行的時候會自動創(chuàng)建一個對象,并且只有通過this才能訪問這個對象。所以我們可以直接通過this來對這個對象進行賦值。而且不用再return,因為this指向默認為構造函數(shù)的返回值。
同時,用了new關鍵字來創(chuàng)建我們想要的對象是不是感覺更“正式”了。
可惜,它仍然不能解決會重復生成方法函數(shù)的問題,這個情況和工廠函數(shù)一樣。

  【原型方式】
這種方式對比以上方式,有個很大的優(yōu)勢,就是它解決了方法函數(shù)會被生成多次的問題。它利用了對象的prototype屬性。我們依賴原型可以重寫對象實例。
復制代碼 代碼如下:

var Obj = function () {}
Obj.prototype.name = 'me';
Obj.prototype.showName = function () {
alert(this.name);
}
var obj1 = new Obj();
var obj2 = new Obj();

我們依賴原型對構造函數(shù)進行重寫,無論是屬性還是方法都是通過原型引用的方式給新建的對象,因此都只會被創(chuàng)建一次??上У氖?,這種方式存在兩個致命的問題:
1。沒辦法在構建對象的時候就寫入想要的屬性,因為原型在構造函數(shù)作用域外邊,沒辦法通過傳遞參數(shù)的方式在對象創(chuàng)建的時候就寫入屬性值。只能在對象創(chuàng)建完畢后對值進行重寫。
2。致命問題在于當屬性指向對象時,這個對象會被多個實例所共享。考慮下面的代碼:
復制代碼 代碼如下:

var Obj = function () {}
Obj.prototype.name = 'me';
Obj.prototype.flag = new Array('A', 'B');
Obj.prototype.showName = function () {
alert(this.name);
}
var obj1 = new Obj();
var obj2 = new Obj();
obj1.flag.push('C');
alert(obj1.flag); // A,B,C
alert(obj2.flag); //A,B,C

是的,當flag屬性指向對象時,那么實例obj1和obj2都共享它,哪怕我們僅僅改變了obj1的flag屬性,但是它的改變在實例obj2中任然可見。
面對這個問題,讓我們不得不想是否應該把【構造函數(shù)方式】和【原型方式】結合起來,讓他們互補。。。

  【構造函數(shù)和原型混合方式】
我們讓屬性用構造函數(shù)方式創(chuàng)建,方法用原型方式創(chuàng)建即可:
復制代碼 代碼如下:

var Obj = function (name) {
this.name = name;
this.flag = new Array('A', 'B');
}
Obj.prototype = {
showName : function () {
alert(this.name);
}
}
var obj1 = new Obj();
var obj2 = new Obj();
obj1.flag.push('C');
alert(obj1.flag); // A,B,C
alert(obj2.flag); //A,B

這種方式有效地結合了原型和構造函數(shù)的優(yōu)勢,是目前用的最多,也是副作用最少的方式。
不過,有些追求完美的家伙還不滿足,因為在視覺上還沒達到他們的要求,因為通過原型來創(chuàng)建方法的過程在視覺上還是會讓人覺得它不太像實例的方法(尤其對于傳統(tǒng)OOP語言的開發(fā)者來說。)
所以,我們可以讓原型活動起來,讓他也加入到構造函數(shù)里面去,好讓這個構造函數(shù)在視覺上更為統(tǒng)一。而這一系列的過程只需用一個判斷即可完成。
復制代碼 代碼如下:

var Obj = function (name) {
this.name = name;
this.flag = new Array('A', 'B');
if (typeof Obj._init == 'undefined') {
Obj.prototype = {
showName : function () {
alert(this.name);
}
};
Obj._init = true;
}
}

如上,用_init作為一個標志來判斷是否已經給原型創(chuàng)建了方法。如果是那么就不再執(zhí)行。這樣其實在本質上是沒有任何變化的,方法仍是通過原型創(chuàng)建,唯一的區(qū)別在于這個構造函數(shù)看起來“江山統(tǒng)一”了。
但是這種動態(tài)原型的方式是有問題的,《JavaScript高級程序設計》里并沒有深究。創(chuàng)建第一個對象的時候會因為prototype在對象實例化之前沒來的及建起來,是根本無法訪問的。所以第一個對象是無法訪問原型方法的。同時這種方式在子類繼承中也會有問題。
關于解決方案,我會在下一文中說明。

其實就使用方便來說的話,個人覺得是沒必要做這個判斷的。。。呵呵 ^_^

相關文章

  • javascript new fun的執(zhí)行過程

    javascript new fun的執(zhí)行過程

    new fun的執(zhí)行過程分析,學習面向對象的朋友可以參考下。
    2010-08-08
  • javascript面向對象之二 命名空間

    javascript面向對象之二 命名空間

    javascript中本沒有命名空間的概念,但是要體現(xiàn)面向對象的思想,應當有命名空間,就像java中的package,.net中的namespace一樣,作用主要為了防止類名沖突,相同的類名只要屬于不同的命名空間,便不會沖突。
    2011-02-02
  • javascript 寫類方式之三

    javascript 寫類方式之三

    用構造函數(shù)來定義類屬性(字段) 用原型方式來定義類的方法。 就有了第三種方式。這種方式貌似采用的人較多。
    2009-07-07
  • javascript 面向對象編程  function是方法(函數(shù))

    javascript 面向對象編程 function是方法(函數(shù))

    在進行編程時,必免不了要碰到復雜的功能。初學者最怕復雜的功能,因為不能夠很好的進行功能邊界劃分,只能一大串if、循環(huán)加case堆疊在一起,結果出來的程序自己看著暈,別人看著更暈。
    2009-09-09
  • AppBaseJs 類庫 網上常用的javascript函數(shù)及其他js類庫寫的

    AppBaseJs 類庫 網上常用的javascript函數(shù)及其他js類庫寫的

    AppBaseJs類庫。一個借鑒了網上常用的函數(shù)及其他js類庫寫的,方便大家的調用。
    2010-03-03
  • JavaScript 對象鏈式操作測試代碼

    JavaScript 對象鏈式操作測試代碼

    自從使用了jQuery以后,對它的鏈式操作很是依賴,以至于常常覺得其他庫不好用。。
    2010-04-04
  • js 函數(shù)調用模式小結

    js 函數(shù)調用模式小結

    在javascript中一共有四種調用模式:方法調用模式、函數(shù)調用模式、構造器調用模式和apply調用模式。這些模式在如何初始化關鍵參數(shù)this上存在差異
    2011-12-12
  • Javascript函數(shù)加殼多用于事件綁定

    Javascript函數(shù)加殼多用于事件綁定

    逸云.framework by Neequ 幫助:將改寫函數(shù)體,使得同名函數(shù)可以同時執(zhí)行 func 將之加殼的函數(shù)體字符串 name 函數(shù)名 obj 可選,默認為 window,為應用函數(shù)的父對象,多用于事件綁定
    2007-12-12
  • JavaScript 核心參考教程 內置對象

    JavaScript 核心參考教程 內置對象

    JavaScript 是根據 "ECMAScript"標準制定的網頁腳本語言。這個標準由 ECMA 組織發(fā)展和維護。ECMA-262 是正式的 JavaScript 標準。
    2009-10-10
  • JavaScript 面向對象的之私有成員和公開成員

    JavaScript 面向對象的之私有成員和公開成員

    這節(jié)來說下JavaScript的私有成員和公開成員,雖然JavaScript沒有private和public關鍵字,但還是那句話——作為開發(fā)人員我們要有面向對象的思想!
    2010-05-05

最新評論

太湖县| 舞阳县| 仁寿县| 田阳县| 万安县| 无锡市| 北川| 天镇县| 惠水县| 延津县| 盈江县| 郧西县| 榕江县| 九台市| 大丰市| 舟山市| 铜鼓县| 长丰县| 临澧县| 大悟县| 南川市| 黔江区| 京山县| 桦川县| 柘荣县| 嘉兴市| 庆云县| 淳安县| 台南市| 新化县| 祁连县| 昌宁县| 汉川市| 慈溪市| 锦屏县| 枝江市| 桃园市| 拜泉县| 垫江县| 巴马| 青阳县|