2011-05-27 41 views
3

我想知道哪種情況有更多的「開銷」:JavaScript應該儘可能共享函數或創建新函數?

1)情況1:500萬個對象共享30個函數。每次調用函數時,有一個開銷,因爲它需要做f.call(例如,ARG1,ARG2等)

//example code 
function makeObject() 
{ 
    return { method1:func1, 
      method2:func2, 
      ... 
      method30:func30 }; 
} 

2)案例2:5萬個對象,每組30個功能( = 1.5億個人功能實例)。每次被調用的函數,有沒有「路由開銷」但當然,在具有犧牲多個實例

//example code 
function makeObject() 
{ 
    return { method1:func1.bind(asd), 
      method2:func2.bind(asd), 
      ... 
      method30:func30.bind(asd) }; 
} 

500萬隻是一個數字我的手指打出來,而我的大腦還是搞清楚一個很好的數舉一個例子。

基本上我想知道一般我們應該儘可能共享函數還是創建新函數?

(你可以認爲我永遠不會使用eval函數的任何地方,在整個頁)

+0

我假設5m對象是動態創建的? – Kayla 2011-05-27 07:06:33

+3

運行測試。這是知道或確定的唯一途徑。 (爲什麼不只是使用「原型鏈」,讓引擎「分享」這些功能?) – 2011-05-27 07:06:34

+0

500萬將是不現實的,也許僅用於基準測試 – Ibu 2011-05-27 07:10:05

回答

5

由於幾乎所有現代瀏覽器優化prototype-scopeschain查找,你絕對應該去的方法共享。

用簡單的語言描述的優化技術是一種hash lookup table,JavaScript引擎用來從out of scope變量訪問屬性/方法。因此,與傳統的scope chain lookup相比,引擎必須爬過每個父範圍變量/激活對象的開銷非常小。

這個優化的lookup只會失敗,如果有某種直接的eval'編碼。由於eval可以從上下文中更改屬性,因此引擎必須回退到經典的查找algorythm(這有點慢)。

但是,5米的物體對於JavaScript引擎來說是不真實的,我希望這些數字只是例子。在真實世界的場景中,調用函數數量的5m對象會造成堆棧溢出和遍佈各處的「運行腳本過長」錯誤。

單獨的parsing time爲1.5億功能將是可恥的。

+0

FYI Chrome(V8)和FF(TraceMonkey)都只緩存函數聲明,真正創建一個對象文字('{}')和一個具有相同來源的新函數的指針,它們不會重新解析和編譯它們。 – 2011-05-27 07:29:00

+0

@cwolves:有趣。有沒有哪種資源在詳細描述該技術?我想知道限制條件在哪裏(即超出範圍方法和逃避代碼)。 – jAndy 2011-05-27 07:55:56

+0

@cwolves @cwolves你的意思是說創建附加函數的開銷很小(與範圍鏈查找開銷相比) – Pacerier 2011-05-31 03:10:23

1

如果假設的情況下2是關於創建對象的與此類似:

function makeObject() 
{ 
    return { method1:func1, 
      method2:func2, 
      ... 
      method30:func30 }; 
} 

那麼你將不得不每30個樓盤的對象5米。不是「1.5億個人功能實例」。功能實例的數量仍然是30.

要創建5m這樣的對象將花費你一些東西。增加財產比閱讀費用高出約3-10倍。這意味着創建這樣的集合可能需要比使用__proto__使用一級間接尋址方法訪問方法花費更多時間。

簡而言之:對於5米/ 30的情況1在大多數情況下更爲優化。但有些情況下,將方法引用放入對象本身是值得考慮的。例如。有限數量(例如單身人士)經常訪問的對象/方法。

+0

幾乎完全相同。您的代碼適用於case 1. case 2不是這樣的用例子更新了這個問題) – Pacerier 2011-05-31 03:52:03

+0

[quote]但有些情況下,將方法引用放入對象本身是值得考慮的。例如。有限的數量(如單身人士)經常訪問的對象/方法。[/ quote]對不起,你介意闡述嗎? (我真的不明白) – Pacerier 2011-05-31 03:53:18

+0

@Prier:正如我所說的,如果你有單身對象(例如,模擬JS中的名稱空間是由單身對象創建的),那麼將函數直接放入這樣的單例對象是有意義的。如果你有經典的對象/類的情況下,許多實例共享同一個類(a.k.a. prototype),那麼你應該使用'.prototype.foo = function(){}'選項。 – 2011-06-11 19:41:20

1

爲什麼不這樣呢? :

function myObject() { } 

myObject.prototype.method1 = func1 
myObject.prototype.method2 = func2, 
      ... 
myObject.prototype.method30 = func30 

所以,如果你創建對象作爲

var obj = new myObject(); 

,那麼你將調用其方法爲:

obj.method1(); 
obj.method2(); 

沒有需要call()等神奇的...

在這種情況下,您將不需要通過相同的30 pro來填充對象的每個實例perties。

+0

我的問題是針對多個繼承問題。所以基本上我想知道如果B類擴展類A,那麼類B的實例是否使用與A類的實例相同的函數實例?或者我們應該爲每個實例創建新的函數實例(因爲這樣更容易) – Pacerier 2011-06-01 08:28:58