繁体   English   中英

for..in 循环和 Object.keys 不同的行为

[英]for..in loop & Object.keys different behavior

我有这个对象函数构造函数:

const Shape = function(name){
this.name = name;
}
Shape.prototype.getName = function(){
    return this.name;
};

我有这个实例

const square = new Shape("square");

当我使用 for 循环迭代方形对象时,我可以看到迭代过程正在方形对象的原型上发生

for (const key in square) console.log(key);
/* #output:
name
getName
*/

但是当我使用 Object.keys() 函数时,我可以看到迭代过程没有迭代原型对象

/* #output:
["name"]
*/

背后的原因是什么?

这是我尝试过的:

我试图从原型对象中 console.log getName 方法的描述符,我已经看到 enumerable 属性默认设置为 true:

console.log(Object.getOwnPropertyDescriptor(Object.getPrototypeOf(square), "getName"))

/* #output:
configurable: true
enumerable: true
value: ƒ ()
writable: true
__proto__: Object
*/

Object.keys只迭代可枚举的自己的属性。 相反, for..in迭代对象原型链上任何位置的所有可枚举属性。

使用此代码:

const Shape = function(name){
    this.name = name;
}
Shape.prototype.getName = function(){
    return this.name;
};

Shape实例正在接收一个自己的name属性,因此它会被两种迭代方法迭代。 相比之下, getName在实例的原型上——它不是实例本身的属性,所以它不会在Object.keys返回:

 const Shape = function(name){ this.name = name; } Shape.prototype.getName = function(){ return this.name; }; const square = new Shape("square"); console.log( square.hasOwnProperty('name'), square.hasOwnProperty('getName'), Shape.prototype.hasOwnProperty('getName') );

背后的原因是什么?

for-in循环遍历对象中所有以字符串命名的可枚举属性,包括继承的属性。

Object.keys只为您提供对象自己(非继承)字符串命名的可枚举属性的数组。 只是为了说明,它类似于:

// Rough, not-exact-in-every-detail implementation of `Object.keys`
// in terms of `for-in`
const result = [];
for (const name in object) {
    if (Object.prototype.hasOwnProperty.call(object, name)) {
        result.push(name);
    }
}

还有Object.getOwnPropertyNames为您提供所有对象自己的以字符串命名的属性(甚至是不可枚举的)的数组,以及Object.getOwnPropertySymbols为您提供对象自己的以符号命名的属性的数组(即使是非- 可枚举的)。 (没有Object.keys的 Symbol 等价物。)


我试图从原型对象中 console.log getName 方法的描述符,我已经看到 enumerable 属性默认设置为 true:

当您像在问题中一样通过分配创建属性时。 如果通过Object.defineProperty或在class构造中使用方法语法创建属性,则enumerable默认为false

例子:

 // Your original code: const Shape = function(name){ this.name = name; } Shape.prototype.getName = function(){ return this.name; }; showFlag(Shape.prototype, "getName"); // true // Using `Object.defineProperty`: const Shape2 = function(name){ this.name = name; } Object.defineProperty(Shape2.prototype, "getName", { value: function(){ return this.name; }, writable: true, // These also default to `false`, but you configurable: true // usually want them to be `true` for methods }); showFlag(Shape2.prototype, "getName"); // false // Using `class` syntax class Shape3 { constructor(name) { this.name = name; } getName() { return this.name; } } showFlag(Shape3.prototype, "getName"); // false function showFlag(proto, name) { console.log(Object.getOwnPropertyDescriptor(proto, name).enumerable); }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM