自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

如何在 JavaScript 對象中嵌入私有成員

開發(fā) 開發(fā)工具 前端
對于創(chuàng)建真正的私有數(shù)據(jù)來講,閉包空間屬性(機制)是一個很棒的做法?;蛟S你得面對內(nèi)存消耗小幅度增加(問題),但就我的看法,這卻很合理 (這個代價可以換取相對于常規(guī)方法更高的性能增長)。

最近,我開發(fā)一個項目 Angular Cloud Data Connector, 幫助Angular開發(fā)者使用云數(shù)據(jù),特別是 Azure移動服務(wù), 使用WEB標(biāo)準(zhǔn),像索引數(shù)據(jù)庫(indexed DB)。我嘗試建立一種方式,使得JavaScript開發(fā)者能將私有成員嵌入到一個對象中。

[[138984]]

我解決這個問題的技術(shù)用到了我命名的閉包空間(closure space)。在這篇入門文章中,我要分享的是如何在你的項目中用它,及它對主流瀏覽器的性能和內(nèi)存的影響。

在深入學(xué)習(xí)前,咱們先說下,你為什么需要用到私有成員(private members), 還有一種替代方式來模擬私有成員。

如果你想點評本文,盡情推(twitter)我: @deltakosh

1. 為何要用私有成員(Private Members)

當(dāng)你用JavaScript 創(chuàng)建一個對象時,可以聲明值成員(value members)。 如果你打算控制對它們的讀/寫訪問操作,可以如下聲明: 

  1. var entity = {}; 
  2.  
  3. entity._property = "hello world"
  4. Object.defineProperty(entity, "property", { 
  5.     get: function () { return this._property; }, 
  6.     set: function (value) { 
  7.         this._property = value; 
  8.     }, 
  9.     enumerable: true
  10.     configurable: true 
  11. }); 

這樣實現(xiàn),你能完全控制讀和寫操作。問題在于_property 成員仍然可以直接訪問和修改。

這也就是為何我們需要更加穩(wěn)定可靠的方式,聲明私有成員,它智能通過對象的方法來訪問。

#p#

2. 使用閉包空間(Closure Space)

解決方法是使用閉包空間。每當(dāng)內(nèi)部函數(shù) (inner fanction) 訪問來自外部函數(shù)作用域的變量時,瀏覽器為你分配一段內(nèi)存空間。有時很取巧,不過就我們的題目來講,這算是一個***的解決方案。

我們在上個代碼版本中添加這個特性:

  1. var createProperty = function (obj, prop, currentValue)  
  2.     Object.defineProperty(obj, prop,  
  3.     { 
  4.             get: function () { return currentValue; }, 
  5.             set: function (value) { 
  6.             currentValue = value; 
  7.                     }, 
  8.                     enumerable: true
  9.                     configurable: true    }); 
  10.                     }  
  11. var entity = {};  
  12. var myVar = "hello world";createProperty(entity, "property", myVar); 

示例中,createProperty 函數(shù)有一個 currentValue 變量,存在 get 和 set 方法。此變量會保存到 get 和 set 函數(shù)的閉包空間中?,F(xiàn)在,只有這兩個函數(shù)能看到和更新 currentValue 變量! 任務(wù)完成!

唯一需要警惕 caveat,警告,注意)的是源值 (myVar) 仍可訪問。下面給出另一個更健壯的版本(保護(hù) myVar 變量):

  1. var createProperty = function (obj, prop) { 
  2.     var currentValue = obj[prop]; 
  3.     Object.defineProperty(obj, prop, { 
  4.         get: function () { return currentValue; }, 
  5.         set: function (value) { 
  6.             currentValue = value; 
  7.         }, 
  8.         enumerable: true
  9.         configurable: true 
  10.     }); 
  11.  
  12. var entity = { 
  13.     property: "hello world" 
  14. }; 
  15.  
  16. createProperty(entity, "property"); 

采用該函數(shù), 即便源值都銷毀(destructed,注:意思是不能直接賦值)了。到此大功告成了!

#p#

3. 性能考慮Performance Considerations

現(xiàn)在咱們看看性能。

很明顯,比起一個簡單的變量,閉包空間,甚或(對象)屬性要慢的多,且更消耗資源。這就是本文更多關(guān)注普通方式和閉包空間機制差異的原因。

為證明閉包空間機制并不比標(biāo)準(zhǔn)方式更消耗資源, 我寫了下面代碼做個基準(zhǔn)測試:

 

  1. <!DOCTYPE html> 
  2. <html xmlns="http://www.w3.org/1999/xhtml"
  3. <head> 
  4.     <title></title> 
  5. </head> 
  6. <style> 
  7.     html { 
  8.         font-family: "Helvetica Neue", Helvetica; 
  9.     } 
  10. </style> 
  11. <body> 
  12.     <div id="results">Computing...</div> 
  13.     <script> 
  14.         var results = document.getElementById("results"); 
  15.         var sampleSize = 1000000; 
  16.         var opCounts = 1000000; 
  17.  
  18.         var entities = []; 
  19.  
  20.         setTimeout(function () { 
  21.             // Creating entities 
  22.             for (var index = 0; index < sampleSize; index++) { 
  23.                 entities.push({ 
  24.                     property: "hello world (" + index + ")" 
  25.                 }); 
  26.             } 
  27.  
  28.             // Random reads 
  29.             var start = new Date().getTime(); 
  30.             for (index = 0; index < opCounts; index++) { 
  31.                 var position = Math.floor(Math.random() * entities.length); 
  32.                 var temp = entities[position].property; 
  33.             } 
  34.             var end = new Date().getTime(); 
  35.  
  36.             results.innerHTML = "<strong>Results:</strong><br>Using member access: <strong>" + (end - start) + "</strong> ms"
  37.         }, 0); 
  38.  
  39.         setTimeout(function () { 
  40.             // Closure space ======================================= 
  41.             var createProperty = function (obj, prop, currentValue) { 
  42.                 Object.defineProperty(obj, prop, { 
  43.                     get: function () { return currentValue; }, 
  44.                     set: function (value) { 
  45.                         currentValue = value; 
  46.                     }, 
  47.                     enumerable: true
  48.                     configurable: true 
  49.                 }); 
  50.             } 
  51.             // Adding property and using closure space to save private value 
  52.             for (var index = 0; index < sampleSize; index++) { 
  53.                 var entity = entities[index]; 
  54.  
  55.                 var currentValue = entity.property; 
  56.                 createProperty(entity, "property", currentValue); 
  57.             } 
  58.  
  59.             // Random reads 
  60.             var start = new Date().getTime(); 
  61.             for (index = 0; index < opCounts; index++) { 
  62.                 var position = Math.floor(Math.random() * entities.length); 
  63.                 var temp = entities[position].property; 
  64.             } 
  65.             var end = new Date().getTime(); 
  66.  
  67.             results.innerHTML += "<br>Using closure space: <strong>" + (end - start) + "</strong> ms"
  68.         }, 0); 
  69.  
  70.         setTimeout(function () { 
  71.             // Using local member ======================================= 
  72.             // Adding property and using local member to save private value 
  73.             for (var index = 0; index < sampleSize; index++) { 
  74.                 var entity = entities[index]; 
  75.  
  76.                 entity._property = entity.property; 
  77.                 Object.defineProperty(entity, "property", { 
  78.                     get: function () { return this._property; }, 
  79.                     set: function (value) { 
  80.                         this._property = value; 
  81.                     }, 
  82.                     enumerable: true
  83.                     configurable: true 
  84.                 }); 
  85.             } 
  86.  
  87.             // Random reads 
  88.             var start = new Date().getTime(); 
  89.             for (index = 0; index < opCounts; index++) { 
  90.                 var position = Math.floor(Math.random() * entities.length); 
  91.                 var temp = entities[position].property; 
  92.             } 
  93.             var end = new Date().getTime(); 
  94.  
  95.             results.innerHTML += "<br>Using local member: <strong>" + (end - start) + "</strong> ms"
  96.         }, 0); 
  97.  
  98.     </script> 
  99. </body> 
  100. </html> 

我創(chuàng)建了一百萬個對象,都有屬性成員。要完成下面三個測試:

  • 執(zhí)行 1百萬次隨機訪問屬性。

  • 執(zhí)行1百萬次隨機訪問閉包空間實現(xiàn)版本。

  • 執(zhí)行1百萬次隨機訪問常規(guī)get/set實現(xiàn)版本。

測試結(jié)果參見下面表格和圖表:

JavaScript:如何在對象中嵌入私有成員

JavaScript:如何在對象中嵌入私有成員

我們發(fā)現(xiàn),閉包空間實現(xiàn)總是快于常規(guī)實現(xiàn),根據(jù)瀏覽器的不同,還可以做進(jìn)一步的性能優(yōu)化。

Chrome 上的性能表現(xiàn)低于預(yù)期?;蛟S存在 bug,因此,為確認(rèn)(存在 bug),我聯(lián)系了 Google 項目組,描述發(fā)生的癥狀。還有,如果你打算測試在 Microsoft Edge —微軟新發(fā)布的瀏覽器,在windows10 中默認(rèn)安裝—中的性能表現(xiàn),你可以點擊下載 。

然而,如果仔細(xì)研究,你會發(fā)現(xiàn),使用閉包空間或?qū)傩员戎苯釉L問變量成員要10倍左右。 因此,使用要恰當(dāng)且謹(jǐn)慎。

JavaScript:如何在對象中嵌入私有成員

#p#

4. 內(nèi)存占用(Memory Footprint)

我們也得驗證該技術(shù)不會消耗過多內(nèi)存。為測試內(nèi)存占用基準(zhǔn)情況,我寫了下面代碼段:

直接屬性引用版本(Reference Code)

 

  1. var sampleSize = 1000000; 
  2.  var entities = [];  
  3. // Creating entities 
  4. for (var index = 0; index < sampleSize; index++) { 
  5.     entities.push({ 
  6.             property: "hello world (" + index + ")" 
  7. });} 
  8.  
  9. 常規(guī)方式版本(Regular Way,get/set) 
  10.  
  11. var sampleSize = 1000000; 
  12.  
  13. var entities = []; 
  14.  
  15. // Adding property and using local member to save private value 
  16. for (var index = 0; index < sampleSize; index++) { 
  17.     var entity = {}; 
  18.  
  19.     entity._property = "hello world (" + index + ")"
  20.     Object.defineProperty(entity, "property", { 
  21.         get: function () { return this._property; }, 
  22.         set: function (value) { 
  23.             this._property = value; 
  24.         }, 
  25.         enumerable: true
  26.         configurable: true 
  27.     }); 
  28.  
  29.     entities.push(entity); 
  30.  
  31. 閉包空間版本(Closure Space Version) 
  32.  
  33. var sampleSize = 1000000; 
  34.  
  35. var entities = []; 
  36.  
  37. var createProperty = function (obj, prop, currentValue) { 
  38.     Object.defineProperty(obj, prop, { 
  39.         get: function () { return currentValue; }, 
  40.         set: function (value) { 
  41.             currentValue = value; 
  42.         }, 
  43.         enumerable: true
  44.         configurable: true 
  45.     }); 
  46.  
  47. // Adding property and using closure space to save private value 
  48. for (var index = 0; index < sampleSize; index++) { 
  49.     var entity = {}; 
  50.  
  51.     var currentValue = "hello world (" + index + ")"
  52.     createProperty(entity, "property", currentValue); 
  53.  
  54.     entities.push(entity); 

之后,我(在三個主流瀏覽器上)運行所有的三段代碼,啟動(瀏覽器)內(nèi)嵌的內(nèi)存性能分析器(本示例中使用 F12 工具條):

JavaScript:如何在對象中嵌入私有成員

我計算機上運行的結(jié)果如下圖表:

JavaScript:如何在對象中嵌入私有成員

就閉包空間和常規(guī)方式,只有 Chrome上,閉包空間(內(nèi)存占用)表現(xiàn)稍好,在 IE11 和 Firefox上占用內(nèi)存反而增多,但是瀏覽器的比較結(jié)果e—對于現(xiàn)代瀏覽器,用戶很可能不會在意這點差別。

更多 JavaScript 實踐

或許你會吃驚,微軟提供了一批有關(guān)開源 Javascript 主題的免費學(xué)習(xí)材料, 我們正在發(fā)起一個任務(wù),關(guān)于創(chuàng)建更多 Microsoft Edge 來臨 系列。 查看我的文章:

或者我們團隊系列:

以及一些免費工具:Visual Studio 社區(qū),Azure 試用版跨瀏覽器測試工具用于 Mac, Linux, 或者 Windows。

結(jié)論(Conclusion)

如你所見,對于創(chuàng)建真正的私有數(shù)據(jù)來講,閉包空間屬性(機制)是一個很棒的做法?;蛟S你得面對內(nèi)存消耗小幅度增加(問題),但就我的看法,這卻很合理 (這個代價可以換取相對于常規(guī)方法更高的性能增長)。

隨帶說一句, 如果你要自己動手試試,所以代碼可以在 here下載。 推薦一篇不錯的文章, “how-to” on Azure Mobile Services here。

責(zé)任編輯:王雪燕 來源: oschina
相關(guān)推薦

2009-07-22 10:08:48

Javascript私

2010-07-26 09:20:48

C#

2024-04-11 08:30:05

JavaScript數(shù)組函數(shù)

2020-11-26 08:12:24

JavaScript對象數(shù)組

2021-07-09 12:37:31

GoPython編程語言

2023-04-26 15:19:36

JavaScripMap數(shù)組

2022-01-21 10:58:39

JavaScriptGolangPython

2024-10-22 15:10:49

2013-03-04 14:35:05

WordPressEdge AnimatHTML5

2019-04-23 15:20:26

JavaScript對象前端

2011-03-21 12:41:41

JavaScript

2021-03-11 23:43:20

JavaScript數(shù)組開發(fā)

2021-03-18 10:45:02

JavaScript數(shù)組運算符

2020-08-23 11:32:21

JavaScript開發(fā)技術(shù)

2021-06-03 10:00:47

JavaScript 前端數(shù)克隆對象

2022-03-15 07:55:09

JavaScript線性儀表圖開發(fā)

2021-03-26 23:41:19

JavaScript對象開發(fā)

2011-08-02 10:50:02

ActiveDirec組成員

2022-07-07 07:22:01

瀏覽器JavaScript工具

2010-08-10 15:55:20

FlexHTML頁面
點贊
收藏

51CTO技術(shù)棧公眾號