【问题标题】:Object.getOwnPropertyNames vs Object.keysObject.getOwnPropertyNames 与 Object.keys
【发布时间】:2014-05-04 16:58:17
【问题描述】:

javascript中Object.getOwnPropertyNamesObject.keys有什么区别?还有一些例子将不胜感激。

【问题讨论】:

标签: javascript


【解决方案1】:

如前所述,.keys 不会返回不可枚举的属性。

关于示例,其中一种陷阱情况是 Error 对象:它的某些属性是不可枚举的。
所以虽然console.log(Object.keys(new Error('some msg'))) 产生[]console.log(Object.getOwnPropertyNames(new Error('some msg'))) 产生 ["stack", "message"]

console.log(Object.keys(new Error('some msg')));
console.log(Object.getOwnPropertyNames(new Error('some msg')));

【讨论】:

    【解决方案2】:

    有一点不同。 Object.getOwnPropertyNames(a) 返回对象a所有属性。 Object.keys(a) 返回所有可枚举 自己的属性。这意味着如果你定义你的对象属性而不创建它们中的一些enumerable: false,这两种方法会给你同样的结果。

    很容易测试:

    var a = {};
    Object.defineProperties(a, {
        one: {enumerable: true, value: 1},
        two: {enumerable: false, value: 2},
    });
    Object.keys(a); // ["one"]
    Object.getOwnPropertyNames(a); // ["one", "two"]
    

    如果你定义一个属性而不提供属性属性描述符(意味着你不使用Object.defineProperties),例如:

    a.test = 21;
    

    然后这样的属性会自动成为一个可枚举的并且两个方法都产生相同的数组。

    【讨论】:

    • 特别是数组对象的length属性是不可枚举的,所以它不会出现在Object.keys中。
    • @Barmar 对象的length 属性位于原型上,而不是对象本身,因此Object.keysObject.getOwnPropertyNames 都不会列出它。
    • @TheQodesmith Object.getOwnPropertyNames(anyArray) 的结果包括 length
    • 我的立场是正确的! Object.getOwnPropertyNames(anyArray) 确实在返回的数组中包含 length
    • 是的,但是 Array.prototype 也有。可以像普通数组一样修改 Array.prototype(即 Array.prototype.push('whatever')),这有点奇怪。但它似乎对新创建的 Array 实例没有影响。 stackoverflow.com/questions/48020958/…
    【解决方案3】:

    创建对象时的文字符号与构造函数。 这让我很受启发。

    const cat1 = {
        eat() {},
        sleep() {},
        talk() {}
    };
    
    // here the methods will be part of the Cat Prototype
    class Cat {
        eat() {}
        sleep() {}
        talk() {}
    }
    
    const cat2 = new Cat()
    
    Object.keys(cat1) // ["eat", "sleep", "talk"]
    Object.keys(Object.getPrototypeOf(cat2)) // []
    
    Object.getOwnPropertyNames(cat1) // ["eat", "sleep", "talk"]
    Object.getOwnPropertyNames(Object.getPrototypeOf(cat2)) // ["eat", "sleep", "talk"]
    
    cat1 // {eat: function, sleep: function, talk: function}
    cat2 // Cat {}
    
    // a partial of a function that is used to do some magic redeclaration of props
    function foo(Obj) {
        var propNames = Object.keys(Obj);
    
        // I was missing this if
        // if (propNames.length === 0) {
        //     propNames = Object.getOwnPropertyNames(Obj);
        // }
    
        for (var prop in propNames) {
            var propName = propNames[prop];
    
            APIObject[propName] = "reasign/redefine or sth";
        }
    }
    

    所以在我的情况下,如果我给它提供 cat2 类型的对象,foo 函数就不起作用。

    还有其他方法可以创建对象,因此其中也可能存在其他问题。

    【讨论】:

    • Object.getOwnPropertyNames 将返回 cat1 而不是 cat2 的属性名称。两种创建对象的方式不会产生Object.getOwnPropertyNamesObject.keys 之间的区别。
    • @Boric 是的,你是对的。我本可以将 Object.getPrototypeOf(cat2) 与这两种方法一起使用,而不仅仅是 cat2。我不能确定,因为我不记得也没有代码。我会在答案中修复它。
    【解决方案4】:

    另一个区别是数组Object.getOwnPropertyNames 方法将返回一个额外的属性length

    var x = ["a", "b", "c", "d"];
    Object.keys(x);  //[ '0', '1', '2', '3' ]
    Object.getOwnPropertyNames(x);  //[ '0', '1', '2', '3', 'length' ]
    

    【讨论】:

      【解决方案5】:

      另一个区别是(至少在 nodejs 中)“getOwnPropertyNames”函数不保证键顺序,这就是我通常使用“keys”函数的原因:

          Object.keys(o).forEach(function(k) {
            if (!o.propertyIsEnumerable(k)) return;
            // do something...
          });
      

      【讨论】:

      • 在当前版本的 Node.js 中仍然是这种情况,如果是这样,你知道getOwnPropertyNames 不正常的任何例子吗?因为 ES2015 指定了an order for Obect.getOwnPropertyNames,而order for Obect.keys 仍然由实现来决定。
      • 我一直认为JS对象键没有顺序,即使实现保持顺序也不应该依赖它?
      • 嗯,我认为是相反的; getOwnPropertyNames 的顺序在规范中定义。 Object.keys 由实现决定。
      • 以下所有内容的顺序未指定:for-in loopObject.keysObject.getOwnPropertyNames。也就是说,所有三个都将以一致的顺序相互枚举。
      猜你喜欢
      • 1970-01-01
      • 2016-09-16
      • 2017-09-12
      • 2013-10-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多