關於Object-Oritented Javascript

關於javascript,,首先,我們得知道三個概念,基本OOP概念:Scope,Cloures,Context( 作用於,閉包,上下文)。對於OOP的應用,則需要知道 Constructors,Method( Public ,private,Privileged).

以上,內容由於時間關係,暫時不整理,今天主要記錄一下遇到得問題。



Q1:關於構造函數的三部曲。有如下一個構造函數,


var User = function (name) {
  this.name = name;

  function welcome () {
    alert( “Welcome back, ” +this.name + “.”);
  }

  welcome();
}


 
var me = new User( “Bob” );  // Alerts: “Welcome, Bob.”


要創建一個me實例,必須使用new操作符,以這種方式調用構造函數會經歷如下三個步驟;
(1)創建一個空對象,並且this變量引用了該對象,同時還繼承了該函數的原型。
(2)將構造函數的作用域賦給新對象,屬性和方法被加入到This引用的對象中。
(3)新創建的對象由this所引用,最終隱式的返回this。

也就是

var User = function (name) {
  var this = {}; //步驟(1)
this.constructor = User; //步驟(2)
// function body。。

return this;// 步驟(3)

}
我今天試圖將構造函數的返回值手動設置爲一個特權方法
var User = function (name) {
   this.name = name;

  function welcome () {
     alert( “Welcome back, ” +this.name + “.”);
  }

  return {welcome:welcome}
}

事實上這樣的話,當你new一個對象時,調用welcome(),並不能打印出this.name; this.name = undefined, 這就是因爲,函數最終的返回值並不是this,當你想要訪問該構造函數的屬性時,它將是沒有定義的。
需要注意一點:上面所說的“ 空對象”其實並不空,它已經從User的原型中繼承了許多成員,因此它更像是下面的語句:var this = Object.create( User.prototype).
當用New操作符創建對象時,構造函數總是返回一個對象,默認情況下是返回this 所引用的對象。如果在構造函數中並不向this添加人和屬性,將返回“空對象”。
我們可以根據需要返回任意的其他的對象,如下面的例子所示,that引用了新創建的對象,並且返回了that所引用的對象。如果試圖返回並非對象的值,函數會忽略該值,相反構造函數還是會返回This引用的這個對象。
var obj = function(){ 
this.name = "this is pp"; 
var that = {};  
that.name = "that is pp";
return that;
}
var o = new obj();
o.name; // "that is pp"


Q2:函數表達式與函數聲明的區別;
函數表達式: var fun = function fun(){ }
函數聲明:function fun(){ }
當你想在函數體中調用自己本身時,你就必須得用函數表達式了,比如
var user = function User(){var obj = {};
obj.constructor =User;
return obj;}



Q3:單體模式,使用同一個構造函數以new操作符來創建多個對象時,想獲得指向完全相同的對象的新指針。即想得到如下的預期效果
var uni1 = new Universe();
var uni2 = new Universe();
uni1 === uni2;// true
想實現如上效果,有三種方法可以解決。
1,使用全局變量globle來存儲該實例。但是,需要知道,過多的全局變量,會使全局環境受到污染。
2,在構造函數的靜態屬性中緩存該實例。
3.可以將實例包裝在一個閉包中。我們知道閉包訪問外部函數的變量是通過引用訪問。,不過,需要知道的一點是,閉包會帶來額外的開銷。

下面是一個在Universe構造函數的靜態屬性中緩存單個實例的例子
。。。。


下面是一個使用閉包來保護單個實例的例子,重點是在重寫構造函數。

function Universe(){
var instance = this;
this.time_s = 0;
this.bang = "big";
Universe = function (){
debugger
return instance;
}

};

var uni1 = new Universe();
var uni2 = new Universe();
uni1 === uni2 // true;


在分析這個例子的時候,需要知道,在閉包裏,如果閉包引用了外部函數的變量,外部函數的生命週期並不是在外部函數調用完後就結束,而是在內部閉包結束後,不在引用外部變量了,它的聲明週期才結束。也就是說,當第二次new 實例的時候,調用的是裏面這個Universe,但是裏面的Universe仍然能訪問外部函數的instance變量,而且是按引用訪問。
在實現上面這種方法的時候,有一個缺點,主要在於重寫構造函數會丟失在初始定義和重定義時刻之間添加到它裏面的屬性。爲了解決這個問題,我們需要做如下改動。
function Universe(){
var instance; 
Universe = function Universe(){
return instance;
}


Universe.prototype = this; //外部構造函數產生的實例
instance = new Universe(); //instance 並不是Undefined,它繼承了父類原型上的屬性和方法
// instance.constructor = Universe;


instance.time_s = 0;
instance.bang = "big";
return instance; //返回內部Universe的實例,第一次調用的時候new Universe()返回的也是內部Universe的實例。
}
測試用例如下:
Universe.prototype.nothing = true
true
var uni = new Universe()
undefined
Universe.prototype.everything = true
true
var uni = new Universe()
undefined
var uni2 = new Universe()
undefined
uni ===uni2    //他們是相同的實例
true
uni.nothing&&uni.everything&&uni2.nothing&&uni2.everything//所有原型屬性都起作用
true
uni.bang
"big"
uni.constructor===Universe
false









發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章