【Web前端问题】同一数据Object.keys,Object.values和Object.entries获得的个数不同

同一数据Object.keys,Object.values和Object.entries获得的个数不同

  • 使用localStorage

localStorage.setItem(`0`,`你好`);

localStorage.setItem(`1`,`再见`);

localStorage.setItem(`2`,`byb`);

localStorage.setItem(`name`,`nono`);

console.log(Object.keys(localStorage));

console.log(Object.values(localStorage));

console.log(Object.entries(localStorage));

console.log(`---------`);

for(var a in localStorage){

console.log(localStorage[a]);

}

输出结果:

如图所示

  • 设置自定义对象

   let obj = {};

Object.defineProperties(obj, {

"0": {

value: `你好`,

enumerable:false

},

"1": {

value: `再见`,

enumerable:false

},

"2": {

value: `byb`,

enumerable:false

},

"name": {

value: `nono`,

enumerable:true

},

"length": {

value: 4,

enumerable:false

}

});

console.log(Object.keys(obj));

console.log(Object.values(obj));

console.log(Object.entries(obj));

console.log(`---------`);

for (var a in obj) {

console.log(obj[a]);

}

输出结果:

图片描述

回答:

我在 Chrome 中测试,Object.keysObject.valuesObject.entries 返回的数量是一样的,都是 4 个。

本来我猜测,可能题主用的是 polyfill 非标准实现,或者是浏览器早期的不规范实现。但是,

  1. 通过 Object.getOwnPropertyDescriptor 可以发现,设置过的 item 的可枚举性始终为 true,而与 propertyIsEnumerable 检测的结果不一致(使用 propertyIsEnumerable 时,只有 name 是数字,而且是标准书写形式的整数时才会 true,其它都会 false),但 for/in 时却都能枚举出来;
  2. 另外,如果尝试用 localStorage.setItem 来设置 lengthgetItemsetItem__proto__ 这些 name,那么 localStorage.getItem 读取时倒还正常,直接访问对象属性时情况就非常混乱了。凡是 setItem 过的都会被枚举出来,但取得的值却是原型链中的值(如果原型链中存在,不论是否原生,也不论在 setItem 之前或之后添加)。

综上可见,localStorage 的可靠读取方式是 localStorage.getItem(name),直接 localStorage[name] 读取只是一种便捷用法,实现非常不可靠,很可能语言标准中都没具体规定,宿主是看着办的,就算规定了这情况也太曲折了。这非常类似于用 new Proxy 自行实现的对象,内部返回非常不统一。

简单来说,

  • 出问题是 localStorage 使用方式的锅,getItem 的方式始终是稳定的,不应当把这个 API 看作是一个普通对象来用;
  • 枚举性不统一,是 localStorage 实现的锅,或 Object.getOwnPropertyDescriptorpropertyIsEnumerablefor/in 实现的锅,因为结果不应当不同;
  • Object.keysObject.valuesObject.entries 结果长度不一致,一定是此三者实现的锅,因为无论处理的奇葩是什么,它们三个都不应该长度不一样。

回答:

并非不同,是你那该死的极差的编码风格倒置 es 跟你开了个玩笑。

Object.valuesObject.entries 相比较 Object.keys 有一个不同,那就是 keys 只需要遍历对象即可,而前者还需要获取值。

这一过程就存在一个 IsPropertyKey 的判断,而这个判断的标准是 key 必须是字符串类型或Symbol类型才算是一个认可的属性名。

可你好死不死,非要取个 01 才爽。具体在遍历一个 Storage 类型时是怎么样,我就不是很清楚了。

不过,此一问题,你可以换成这样:

localStorage.setItem(`funk0`,`你好`);

localStorage.setItem(`funk1`,`再见`);

localStorage.setItem(`funk2`,`byb`);

localStorage.setItem(`name`,`nono`);

console.log(Object.keys(localStorage));

console.log(Object.values(localStorage));

console.log(Object.entries(localStorage));

console.log(`---------`);

for(var a in localStorage){

console.log(localStorage[a]);

}

世界又正常了!

Happy coding!

回答:

localStorage.propertyIsEnumerable("1") //false

localStorage.propertyIsEnumerable("name") //true

可能localStorage.setItem 第一参能视为数字的情况下则不可枚举

以上是 【Web前端问题】同一数据Object.keys,Object.values和Object.entries获得的个数不同 的全部内容, 来源链接: utcz.com/a/143322.html

回到顶部