原生的JSON.stringify是如何判断一个对象是数组的?

我把一个数组 setPrototypeOf(arr,null),并且 arr[Symbol.toStringTag]='Object',原生的JSON.stringify 仍然会将其作为数组来序列化,请问这是怎么识别的呢?pollyfill时如何模拟这一特性?另外为什么这时候数组仍然具有数组的特性,设置arr[]arr.length仍然会联动?

阅读 5k
2 个回答

V8 源码是这么实现的:https://github.com/v8/v8/blob...

// ES6 section 24.3.2 JSON.stringify.
BUILTIN(JsonStringify) {
  HandleScope scope(isolate);
  JsonStringifier stringifier(isolate);
  Handle<Object> object = args.atOrUndefined(isolate, 1);
  Handle<Object> replacer = args.atOrUndefined(isolate, 2);
  Handle<Object> indent = args.atOrUndefined(isolate, 3);
  RETURN_RESULT_OR_FAILURE(isolate,
                           stringifier.Stringify(object, replacer, indent));
}

而对 JSON.stringify 的具体实现是在 json-stringifier.cc 文件中。

原文件太长,我们直接看第 107 和 115 行:

Maybe<bool> is_array = Object::IsArray(replacer); //  107
Object::GetLengthFromArrayLike(isolate_, replacer), false); // 115

V8 引擎内部只有 Object,把 JSObject 转换为字符串时,使用的是 ArrayLike(类数组对象)。

  1. setPrototypeOf只是改变其原型,没有改变其自身,对于问题中,其本身仍然是个数组,只不过继承自Array的许多方法和属性没了。
  2. arr[Symbol.toStringTag]='Object'也只时在toString时候把你的arr指定为Object,对自身功能其实并无影响。
  3. polyfill?不太懂这里有什么是需要进行polyfill的