问题描述
我正在研究Javascript的原型制作,并且为了进行实验,尝试尽可能地剥离一些基本对象的信息。但是,我在以下代码段中遇到了一个问题:
let x = [];
Object.setPrototypeOf(x,null);
console.log(Object.prototype.toString.call(x));
>>> [object Array]
我在这里的困惑:删除原型后,Object.prototype.toString
怎么仍然知道x
是Array
类型的?如果没有这些属性,此信息从何而来?运行Object.getownPropertyNames(x)
和Object.getownPropertySymbols(x)
,我看不到x
上剩余的任何属性,这些属性包含字符串Array
的任何路径。此信息存储在哪里?
如果这是那些“内部插槽”之一(尽管我不确定是哪一个),有没有办法对其进行修改?我至少可以直接访问它吗?
更新:
Yousaf注意到String.toStringTag
通常访问属性Object.prototype.toString
,以提供在上述示例中代替“ Array”的字符串。确实,设置x[Symbol.toStringTag] = 'my_string'
允许我们更改.toString()
的值。但是,我认为它仍然不能解决问题,因为x[Symbol.toStringTag]
在设置之前是undefined
,不包含所需的“数组”字符串。
解决方法
在任何对象上调用.toString()
时,它都会创建格式为[object x]
的字符串,其中x
是内置构造函数(例如{{ 1}}和Date
。
调用Array
时,需要执行几个步骤,其中一个步骤是检查.toString()
中的this
的值是否为数组。如果是数组,则将tag设置为字符串.toString()
。
来自Spec - 19.1.3.6 Object.prototype.toString ( ):
- 如果isArray为true,则将builtinTag设为“ Array”。
在ES6之前,在用户定义的构造函数的实例上调用'Array'
时,记录了.toString()
。 ES6提供了一种使用众所周知的Symbol Symbol.toStringTag
覆盖标签的方法。