前端工具鏈沒有說的秘密
184 subscribers
1 photo
17 links
随缘更新
Download Telegram
通常的来说,我们对 V8 的认知便是性能优化极好的 JavaScript 运行引擎,但是我们可以来看一下这俩段代码。

- Object.defineProperty([], 'length', {value: -1, configurable: true})
- Object.defineProperty([], 'len' + 'gth', {value: -1, configurable: true})

JavaScript 的语义上来说,这俩段代码并没有什么不同,但是当我们将他们运行在 Chrome 或者 Node.js 中,我们便能得到俩个截然不同的错误。

Object.defineProperty([], 'length', {value: -1, configurable: true})
VM8179:1 Uncaught RangeError: Invalid array length
at Function.defineProperty (<anonymous>)
at <anonymous>:1:8
(anonymous) @ VM8179:1

Object.defineProperty([], 'len' + 'gth', {value: -1, configurable: true})
VM8183:2 Uncaught TypeError: Cannot redefine property: length
at Function.defineProperty (<anonymous>)
at <anonymous>:2:8


那这和 V8 性能优化极好又有什么关系呢?我们可以在他们的源码中看到如下内容:

https://github.com/v8/v8/blob/04f51bc70a38fbea743588e41290bea40830a486/src/objects/objects.cc#L3004-L3007
 if (*name == ReadOnlyRoots(isolate).length_string()) {
// 2a. Return ArraySetLength(A, Desc).
return ArraySetLength(isolate, o, desc, should_throw);
}

简单理解一下,就是在这里直接使用了引用与系统内的常量字符串 "length" 引用进行了一个 O(1) 的快速匹配,从而优化了性能,但是也导致了我们上面的错误。

那么为什么 'length' 和 'len' + 'gth' 有区别呢?这个没有优化吗?我们可以在这Exploring V8's strings: implementation and optimizations》看到实际上在 V8 中存在着不同的字符串,当我们使用 %DebugPrint 对俩段内容进行输出的时候,我们可以发现:
- %DebugPrint('leng'+'th'):ONE_BYTE_STRING_TYPE
- %DebugPrint('length'):ONE_BYTE_INTERNALIZED_STRING_TYPE

这也是为什么后者没办法作为一个常量字符串和全局只读常量字符串 "length" 进行比较的原因。

----
主题之外,其实我们刚刚的代码上面看到一段东西:

https://github.com/v8/v8/blob/04f51bc70a38fbea743588e41290bea40830a486/src/objects/objects.cc#L3003
 // TODO(jkummerow): Check if we need slow string comparison.

#v8 #defineProperty #JavaScript
👍3