2012-04-02 12 views
5

私は、オブジェクトのキーが文字列として格納され、文字列以外の値がキャストされるという前提のもとでした。オブジェクトの属性名はどのようにJavascriptに格納されていますか?

// theKey is an integer 
myMap[theKey.toString(36)] = theValue; 

その後、私は私の仮定かどうかを確認することにしました:キーの何千ものために小さな値を格納していたいくつかのコードを書いて、私は36をベースにすべてのキーを変換しながら、だから、それは、この仮定の下にありましたChromeのプロファイラを使用してメモリ使用量を確認しました。

window.objIntegers = {}; 
for (i = 100000; i--) window.objIntegers[i] = 'a'; 
// 786kb 

window.objStrings = {}; 
for (i = 100000; i--) window.objStrings[i.toString(36)] = 'a'; 
// 16.7mb! 

// and the same pattern but with: 
key = i + .5; // 16.7mb 
key = i + ''; // 786kb 
key = '0' + i; // 16.7mb 
key = i + '0'; // 16.7mb 

は明らかに、私の仮定はオフだった:大雑把ここで私が走ったテストやメモリ使用量があります。私が思っていることは、それらがどのように保存されているか、この動作が標準であるか、Chromium/WebKitチームによって追加されたちょっとしたトリッキーなのかです。

答えて

0

Chromiumでは最適化されています。内部的にプロパティを格納する最も効率的な方法を決定するヒューリスティック(here's one mention of it)があると私は信じています。 ECMAScriptの仕様は、JavaScriptと環境の間のインタフェースであり、JavaScriptに公開されているオブジェクトが内部的にどのように実装されているかについては何も言及していません。

3

これは確かにV8のトリッ​​クです。 「プロパティ」JSが文字列インデックスを持つ属性であるが

JSObject(JS Objectの内部C++表現)は、「要素」は、JS、数値インデックスを有する属性である2つの属性elementspropertiesを有しています。

明らかに、プロパティ名を格納する必要がないため、数値インデックスのメモリ消費量ははるかに少なくなります。

http://code.google.com/intl/de-DE/chrome/devtools/docs/memory-analysis-101.html#primitive_objects

典型的なJavaScriptオブジェクトは、2つの配列posesses:名前付きプロパティを格納するための1つ、数値要素を格納するための別の。

これはV8のソースコードから見ることができます。

http://code.google.com/p/v8/source/browse/trunk/src/objects.h#1483

// [properties]: Backing storage for properties. 
... 
// [elements]: The elements (properties with names that are integers). 

http://code.google.com/p/v8/source/browse/trunk/src/runtime.cc#4462

MaybeObject* Runtime::SetObjectProperty(Isolate* isolate, 
             Handle<Object> object, 
             Handle<Object> key, 
             Handle<Object> value, 
             PropertyAttributes attr, 
             StrictModeFlag strict_mode) { 
    ... 

    // Check if the given key is an array index. 
    uint32_t index; 
    if (key->ToArrayIndex(&index)) { 
    // In Firefox/SpiderMonkey, Safari and Opera you can access the characters 
    // of a string using [] notation. We need to support this too in 
    // JavaScript. 
    // In the case of a String object we just need to redirect the assignment to 
    // the underlying string if the index is in range. Since the underlying 
    // string does nothing with the assignment then we can ignore such 
    // assignments. 
    if (js_object->IsStringObjectWithCharacterAt(index)) { 
     return *value; 
    } 

    Handle<Object> result = JSObject::SetElement(
     js_object, index, value, attr, strict_mode, set_mode); 
    if (result.is_null()) return Failure::Exception(); 
    return *value; 
    } 

    if (key->IsString()) { 
    Handle<Object> result; 
    if (Handle<String>::cast(key)->AsArrayIndex(&index)) { 
     result = JSObject::SetElement(
      js_object, index, value, attr, strict_mode, set_mode); 
    } else { 
     Handle<String> key_string = Handle<String>::cast(key); 
     key_string->TryFlatten(); 
     result = JSReceiver::SetProperty(
      js_object, key_string, value, attr, strict_mode); 
    } 
    if (result.is_null()) return Failure::Exception(); 
    return *value; 
    } 

    // Call-back into JavaScript to convert the key to a string. 
    bool has_pending_exception = false; 
    Handle<Object> converted = Execution::ToString(key, &has_pending_exception); 
    if (has_pending_exception) return Failure::Exception(); 
    Handle<String> name = Handle<String>::cast(converted); 

    if (name->AsArrayIndex(&index)) { 
    return js_object->SetElement(
     index, *value, attr, strict_mode, true, set_mode); 
    } else { 
    return js_object->SetProperty(*name, *value, attr, strict_mode); 
    } 
} 

私が詳細に入るが、SetObjectPropertyはどちらか呼び出すことに注意しませんSetElementまたはSetProperty(キーによって異なります)。あなたのテストケースでチェックが失敗した理由はわかりませんkey = i + '0'