JSON.parse(str) 以某种方式检索到原始对象 __proto__ 的非常具体的信息,这些信息不在 JSON 字符串 (=str) 中。如何?

JSON.parse(str) somehow retrieved very specific information of __proto__ of original object, which is not in the JSON string(=str). How?

在 JavaScript 中,JSON.parse(str); 将 JSON 字符串转换为 JavaScript 对象。 我发现奇怪的是,即使 JSON 字符串不包含任何关于 Object__proto__ 的信息,JSON.parse(str) 有时会设法恢复 [=20] 的嵌套属性=] 属性.

示例(运行 直接在 Brave 浏览器的开发者工具控制台中):

{

    let user1 = {
      name: "John",
      surname: "Smith",
      isAdmin: false,
      "birthday": new Date(2000, 2, 3),
      "friends": [0,1,2,3]
    };

    user1.__proto__.age = 30;

    const str1 = JSON.stringify(user1, null, 2);

    user1.__proto__ = null;
    user1 = null;
    const user2 = JSON.parse(str1);

    console.log(str1);
    console.log(user2);

    const str2 = `{
      "name": "John",
      "surname": "Smith",
      "isAdmin": false,
      "birthday": "2000-03-02T15:00:00.000Z",
      "friends": [
        0,
        1,
        2,
        3
      ]
    }`;

    const user3 = JSON.parse(str2);

    console.log(user3);

}

在这里,user1 是用这样那样的属性创建的。然后在其 proto 上我指定年龄:30 属性。 从 user1 我用 JSON.stringify 制作了它的 JSON 字符串,并将它保存在 str1 中。现在我删除了 user1 及其 __proto__。 只是为了确保,我打印 str1 并且它 没有关于 __proto__ 和 age:30 的信息,正如预期的那样。 但是,当我使用 JSON.parsestr1 创建 user2 时,__proto__ 的 age:30 被恢复 。这怎么可能? 现在我什至用变量名 str2 制作完全相同的 JSON 字符串,并用 str2 创建另一个对象。结果是一样的。这太疯狂了。

console.log(str1) 的输出;

{
  "name": "John",
  "surname": "Smith",
  "isAdmin": false,
  "birthday": "2000-03-02T15:00:00.000Z",
  "friends": [
    0,
    1,
    2,
    3
  ]
}

console.log(user2) 的输出;

{name: 'John', surname: 'Smith', isAdmin: false, birthday: '2000-03-02T15:00:00.000Z', friends: Array(4)}
birthday: "2000-03-02T15:00:00.000Z"
friends: (4) [0, 1, 2, 3]
isAdmin: false
name: "John"
surname: "Smith"
[[Prototype]]: Object
age: 30
constructor: ƒ Object()
hasOwnProperty: ƒ hasOwnProperty()
isPrototypeOf: ƒ isPrototypeOf()
propertyIsEnumerable: ƒ propertyIsEnumerable()
toLocaleString: ƒ toLocaleString()
toString: ƒ toString()
valueOf: ƒ valueOf()
__defineGetter__: ƒ __defineGetter__()
__defineSetter__: ƒ __defineSetter__()
__lookupGetter__: ƒ __lookupGetter__()
__lookupSetter__: ƒ __lookupSetter__()
__proto__: (...)
get __proto__: ƒ __proto__()
set __proto__: ƒ __proto__()

console.log(user3) 的输出;

{name: 'John', surname: 'Smith', isAdmin: false, birthday: '2000-03-02T15:00:00.000Z', friends: Array(4)}
birthday: "2000-03-02T15:00:00.000Z"
friends: (4) [0, 1, 2, 3]
isAdmin: false
name: "John"
surname: "Smith"
[[Prototype]]: Object
age: 30
constructor: ƒ Object()
hasOwnProperty: ƒ hasOwnProperty()
isPrototypeOf: ƒ isPrototypeOf()
propertyIsEnumerable: ƒ propertyIsEnumerable()
toLocaleString: ƒ toLocaleString()
toString: ƒ toString()
valueOf: ƒ valueOf()
__defineGetter__: ƒ __defineGetter__()
__defineSetter__: ƒ __defineSetter__()
__lookupGetter__: ƒ __lookupGetter__()
__lookupSetter__: ƒ __lookupSetter__()
__proto__: (...)
get __proto__: ƒ __proto__()
set __proto__: ƒ __proto__()

顺便说一下,我关闭并打开了浏览器并重新运行 代码块以确保它不是某些预分配变量的结果。结果是一样的,它(年龄:30)不是来自预先分配的变量或缓存值。

我还打开了一个新选项卡并执行了以下较小的代码块。

{
    const str2 = `{
      "name": "John",
      "surname": "Smith",
      "isAdmin": false,
      "birthday": "2000-03-02T15:00:00.000Z",
      "friends": [
        0,
        1,
        2,
        3
      ]
    }`;

    const user3 = JSON.parse(str2);

    console.log(user3);
}

在这种情况下, proto 中的 age: 30 属性 不存在,这是第一个示例发生的原始预期结果,至少对于我.

具有较小代码块的输出:

{name: 'John', surname: 'Smith', isAdmin: false, birthday: '2000-03-02T15:00:00.000Z', friends: Array(4)}
birthday: "2000-03-02T15:00:00.000Z"
friends: (4) [0, 1, 2, 3]
isAdmin: false
name: "John"
surname: "Smith"
[[Prototype]]: Object
constructor: ƒ Object()
hasOwnProperty: ƒ hasOwnProperty()
isPrototypeOf: ƒ isPrototypeOf()
propertyIsEnumerable: ƒ propertyIsEnumerable()
toLocaleString: ƒ toLocaleString()
toString: ƒ toString()
valueOf: ƒ valueOf()
__defineGetter__: ƒ __defineGetter__()
__defineSetter__: ƒ __defineSetter__()
__lookupGetter__: ƒ __lookupGetter__()
__lookupSetter__: ƒ __lookupSetter__()
__proto__: (...)
get __proto__: ƒ __proto__()
set __proto__: ƒ __proto__()

看来我误用了prototype。 删除年龄的正确方法:30 是

两者都

delete user1.__proto__.age;

delete Object.prototype.age;

与这里的user1=null无关。

出于某种原因 user1.__proto__ = null 没有取得任何成就,如果有人提示我原因就太好了

编辑:user1.__proto__ = null 确实删除了用户 1 的 proto,但它不影响 Object.prototype。我认为它只会将 user1 从原型链中分离出来。