javascript - 对象的属性名称如何存储在 Javascript 中?

标签 javascript google-chrome memory

我一直假设对象的键存储为字符串,并且将转换任何非字符串值。因此,正是在这种假设下,在编写一些必须为数千个键存储一个小值的代码时,我将所有键都转换为基数 36:

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

然后,我决定看看我的假设是否真的正确,并使用 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 团队添加的一些额外的技巧?

最佳答案

这确实是V8的一些额外技巧。

JSObject(JS Object 的内部 C++ 表示)有两个属性,elementsproperties,其中“元素”是带有数字索引的 JS 属性,而“属性”是带有字符串索引的 JS 属性。

显然,数字索引在这里消耗的内存要少得多,因为不需要存储属性名称。

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

A typical JavaScript object posesses two arrays: one for storing named properties, another for storing numeric elements.

这个从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 调用 SetElementSetProperty,具体取决于 key 。不确定为什么在您的测试用例 key = i + '0' 中检查失败。

关于javascript - 对象的属性名称如何存储在 Javascript 中?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9976498/

相关文章:

javascript - 如何使用 es6 模板文字作为 Angular 组件输入

javascript - 内容脚本创建的元素在页面上创建 Gmail、Facebook、stackoverflow 等问题

javascript - 我无法使 "commands"在 chrome 扩展中工作

android - three.js WebVR 示例代码适用于 threejs.org 但不适用于我的本地服务器

MySQL:如何将整个 myisam 表保存在内存中?

c++ - vector 数组是完全连续的内存吗?

javascript - 使用 findAndModify 时将函数参数作为 $set 运算符中的字段名称传递

javascript - 检测 HTML 表格单元格的文本内容(值)的更改并对更改的数据应用动画

javascript - 如何抑制c# WebBrowser控件中的 'stop running this script'提示?

c - libuv分配的内存缓冲区重用技术