Object.getOwnPropertyNames vs Object.keys


213

Sự khác biệt giữa Object.getOwnPropertyNamesObject.keystrong javascript là gì? Ngoài ra một số ví dụ sẽ được đánh giá cao.


3
Đánh giá từ các bài viết MDN về cả hai, sự khác biệt là, liệu danh sách được trả về có bao gồm các thuộc tính không thể đếm được hay Object.keys()không : không trả về chúng, trong khi Object.getOwnPropertyNames()đó.
Sirko

Câu trả lời:


289

Có một chút khác biệt. Object.getOwnPropertyNames(a)trả về tất cả các thuộc tính riêng của đối tượng a. Object.keys(a)trả về tất cả các thuộc tính riêng Điều đó có nghĩa là nếu bạn xác định các thuộc tính đối tượng của mình mà không thực hiện một số trong enumerable: falsehai phương thức này thì hai phương thức này sẽ cho bạn cùng một kết quả.

Thật dễ dàng để kiểm tra:

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

Nếu bạn xác định một thuộc tính mà không cung cấp mô tả thuộc tính thuộc tính (có nghĩa là bạn không sử dụng Object.defineProperties), ví dụ:

a.test = 21;

sau đó thuộc tính đó trở thành một số tự động và cả hai phương thức tạo ra cùng một mảng.


26
Cụ thể, các lengththuộc tính của các đối tượng mảng là không thể đếm được, vì vậy nó không hiển thị trong Object.keys.
Barmar

6
@Barmar lengthThuộc tính của các đối tượng là trên nguyên mẫu, không phải chính đối tượng đó, vì vậy Object.keyscũng không Object.getOwnPropertyNamesliệt kê nó.
Qodesmith

9
@TheQodesmith kết quả của Object.getOwnPropertyNames(anyArray)bao gồmlength
Thorn

6
Tôi đứng sửa! Object.getOwnPropertyNames(anyArray)thực sự không bao gồm lengthtrong mảng trả về!
Qodesmith

Vâng, nhưng Array.prototype cũng có nó. Thật kỳ lạ khi người ta có thể sửa đổi Array.prototype giống như một mảng bình thường (ví dụ Array.prototype.push ('sao cũng được)). Nhưng nó dường như không có tác dụng đối với các thể hiện Array mới được tạo. stackoverflow.com/questions/48020958/
Mạnh

21

Một sự khác biệt nữa là trong trường hợp Object.getOwnPropertyNamesphương thức mảng sẽ trả về một thuộc tính bổ sung length.

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

1

Ký hiệu nghĩa đen vs constructor khi tạo đối tượng. Đây là một cái gì đó có tôi.

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";
    }
}

Vì vậy, trong trường hợp của tôi, foohàm không hoạt động nếu tôi cho nó các đối tượng thuộc loại cat2.

Có nhiều cách khác để tạo các đối tượng để có thể có các kink khác trong đó.


Object.getOwnPropertyNamessẽ trả lại tên tài sản cho cat1và không cat2. Hai cách tạo đối tượng không tạo ra sự khác biệt giữa Object.getOwnPropertyNamesObject.keys.
Boric

1
@Boric Có bạn đúng. Tôi có thể có nghĩa là sử dụng Object.getPrototypeOf (cat2) với cả hai phương thức thay vì chỉ cat2. Tôi không thể chắc chắn vì tôi không nhớ và không có mã. Tôi sẽ sửa nó trong câu trả lời.
h3dkandi

0

Như đã được giải thích, .keys không trả lại vô số tài sản.

Liên quan đến các ví dụ, một trong những trường hợp đáng tiếc là một Errorđối tượng: một số thuộc tính của nó là vô số.
Vì vậy, trong khi console.log(Object.keys(new Error('some msg')))sản lượng [], console.log(Object.getOwnPropertyNames(new Error('some msg')))sản lượng["stack", "message"]

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


-5

Một điểm khác biệt nữa là (ít nhất là với nodejs) chức năng "getOwnPropertyNames" không đảm bảo trật tự khóa, đó là lý do tại sao tôi thường sử dụng chức năng "khóa":

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

1
Có phải đó vẫn là trường hợp trong các phiên bản hiện tại của Node.js và nếu vậy, bạn có biết bất kỳ ví dụ nào về việc getOwnPropertyNameskhông theo thứ tự không? Bởi vì ES2015 chỉ định một đơn đặt hàng choObect.getOwnPropertyNames , trong khi đơn đặt hàngObect.keys vẫn tùy thuộc vào việc triển khai.
szupie

7
Tôi luôn nghĩ rằng không có thứ tự các khóa đối tượng JS và bạn không nên dựa vào nó ngay cả khi việc triển khai giữ trật tự?
Juan Mendes

1
Ừm, tôi nghĩ đó là cách khác; thứ tự cho getOwnPropertyNames được xác định trong thông số kỹ thuật. Object.keys là tùy thuộc vào việc thực hiện.
tjvr

1
Tất cả những điều sau đây có trật tự không xác định: for-in loop, Object.keys, và Object.getOwnPropertyNames. Điều đó nói rằng, cả ba sẽ liệt kê theo một trật tự nhất quán đối với nhau.
Thomas Eding
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.