2013-02-06 23 views
-1

我已經閱讀了很多關於封閉和原型的文章......但我仍然有一些問題。 http://blogs.msdn.com/b/kristoffer/archive/2007/02/13/javascript-prototype-versus-closure-execution-speed.aspxJavascript - closure - syntax - public members

我的問題是關於揭露公共方法: 我從這篇文章開始

這是方法:

從這個
// Closure implementation 
function Pixel(x, y){ 
    this.x = x; 
    this.y = y; 
    this.getX = function(){ 
    return this.x; 
    } 
    this.getY = function(){ 
    return this.y; 
    } 
    this.setX = function(value){ 
    this.x = value; 
    } 
    this.setY = function(value){ 
    this.y = value; 
    } 
} 

不同:

// Closure implementation 
function Pixel(x, y){ 
    this.x = x; 
    this.y = y; 
    return { 
     getX : function(){ 
      return this.x; 
      }, 
     getY : function(){ 
      return this.y; 
      }, 
     setX : function(value){ 
      this.x = value; 
      }, 
     setY : function(value){ 
      this.y = value; 
      } 
    } 
} 

哪一個是最好的嗎?爲什麼?

最後一個問題:從上面的基準中,有沒有一種方法可以使用閉包來獲得與原型相似的性能?

tx

+2

這些示例並不等同,也沒有真正使用閉包。拿第二個例子並運行'(new Pixel(4,2))。getX()'。返回值將是'undefined'而不是'4'。假設你解決了這個問題,最大的區別在於,在第二種情況下,實例化(返回)的對象不會從'Pixel.prototype'繼承,像'obj instanceof Pixel'這樣的測試會失敗。 –

+0

第一個示例是「類」定義,第二個示例完全不起作用。這是不同的。 – jbabey

回答

1

那麼沒有「更好」的實現。

第二個選項將產生錯誤,因爲你不能調用它的新因此this將參照窗口(或者你是當函數定義/叫什麼範圍內),所以不要用它

的第二個選項可以使用這樣的封閉:

function Pixel(x, y){ 
    this.x = x; 
    this.y = y; 
    var that = this; 
    return { 
     getX : function(){ 
      return that.x; 
      }, 
     getY : function(){ 
      return that.y; 
      }, 
     setX : function(value){ 
      that.x = value; 
      }, 
     setY : function(value){ 
      that.y = value; 
      } 
    } 
} 

但開始是真難看,是不是與prototype兼容,在我看來,給人以隱私問題看得過重。

+0

如果你做'var o = new Pixel(10,20)',那麼'o.getX()','this'將是返回的對象,但是'x'和'y'將會是未定義的。 – bfavaretto

+0

你可以用'new'調用任何函數。它只需要返回一個對象,如果沒有,就返回'this'。 –

+1

此外,第一個使用'var'語句的方法將作爲製作「私人領域」的更好方法。 – tcooc

0

有很多事情要說。首先,這種get/set機制在Javascript中很少適用。這個Java構造與 有關,確保所有數據訪問都是通過公共方法而不是通過私有屬性; JavaScript世界根本不在乎。

但是,讓我們說,你確實想要像素的對象,你想封裝它們xy數據,曝光,讓我們說,下面的兩個功能:

toString(); // String (a representation of this Pixel) 
offset(deltaX, deltaY); // Pixel (a new Pixel shifted by deltas from this one) 

然後,你可以做這樣的:

var PixelA = function(x, y) { 
    this.x = x; this.y = y; 
    this.toString = function() { 
     return "(" + this.x + ", " + this.y + ")"; 
    }; 
    this.offset = function(deltaX, deltaY) { 
     return new PixelA(this.x + deltaX, this.y + deltaY); 
    }; 
}; 

,或者你可以做這樣的:

var PixelB = function(x, y) { 
    this.toString = function() { 
     return "(" + x + ", " + y + ")"; 
    }; 
    this.offset = function(deltaX, deltaY) { 
     return new PixelB(x + deltaX, y + deltaY); 
    }; 
}; 

或者你可以做這樣的:

var PixelC = function(x, y) { 
    this.x = x; this.y = y; 
} 
PixelC.prototype.toString = function() { 
    return "(" + this.x + ", " + this.y + ")"; 
}; 
PixelC.prototype.offset = function(deltaX, deltaY) { 
    return new PixelC(this.x + deltaX, this.y + deltaY); 
}; 

注意:所有未經測試)。

PixelA是相當幼稚的。我們的數據沒有封裝;任何人都可以直接訪問或改變我們的內部xy屬性。這是內存密集型的; PixelA的每個實例都有自己的toStringoffset函數的副本。

PixelB解決了第一個問題。內部數據存儲在由構造函數生成的閉包中。 toStringoffset函數可以訪問這些變量,但外面什麼都不能直接看到它們。但它對第二個問題沒有提供幫助。

PixelC解決了第二個問題。由於toStringoffset函數存儲在原型中,因此實例不會被重複拷貝它們。但xy屬性再次公開,第一個問題又回來了。

我不知道選項D.我相信你需要在你的內部狀態封裝和給你的原型功能訪問該狀態之間做出選擇。你可以通過許多不同的並列曲線來試圖解決這個問題。但沒有一個真正解決這個潛在問題。您可以在任一方向執行某些優化,但問題是根本。

我很想被證明是錯誤的。

至於性能問題:基於閉包的構造不可能每個都像基於原型的構造一樣快。想一想爲基於閉包的版本中的每個實例分配所有這些屬性所需完成的所有工作,而這些工作無需在基於原型的版本中完成。現在有可能以封閉爲基礎的資產訪問速度會更快......