Làm thế nào để liệt kê các thuộc tính của một đối tượng JavaScript?


842

Nói rằng tôi tạo một đối tượng như vậy:

var myObject =
        {"ircEvent": "PRIVMSG", "method": "newURI", "regex": "^http://.*"};

Cách tốt nhất để lấy danh sách các tên tài sản là gì? tức là tôi muốn kết thúc với một số 'khóa' biến như vậy:

keys == ["ircEvent", "method", "regex"]

3
Hơi lạc đề một chút, nhưng nếu bạn sử dụng underscore.js:_.keys(myJSONObject)
Endy Tjahjono

Câu trả lời:


1076

Trong các trình duyệt hiện đại (IE9 +, FF4 +, Chrome5 +, Opera12 +, Safari5 +), bạn có thể sử dụng phương thức Object.keys tích hợp :

var keys = Object.keys(myObject);

Trên đây có một polyfill đầy đủ nhưng một phiên bản đơn giản là:

var getKeys = function(obj){
   var keys = [];
   for(var key in obj){
      keys.push(key);
   }
   return keys;
}

Thay thế var getKeysbằng Object.prototype.keysđể cho phép bạn gọi .keys()trên bất kỳ đối tượng. Mở rộng nguyên mẫu có một số tác dụng phụ và tôi không khuyên bạn nên làm điều đó.


17
Tôi sẽ cập nhật lại hiệu ứng 'bạn có thể bị cám dỗ làm điều này với nguyên mẫu đối tượng ... nhưng đừng!'
AnthonyWJones

4
bất cứ ai cũng muốn bật đèn lên, tại sao không nên thêm chức năng vào nguyên mẫu của Object?
Vishwanath

2
Đó là một câu hỏi hoàn toàn khác về chính nó, một tìm kiếm nhanh ở đây trên stackoverflow hoặc trên google sẽ cho bạn nhiều thứ để đọc
ximi

3
Các for (var key in myObject) {...}kỹ thuật rất hữu ích cho runtimes javascript bên ngoài các trình duyệt và V8. Ví dụ: khi chuyển các truy vấn giảm bản đồ javascript vào Rịa, Objectđối tượng không tồn tại, vì vậy Object.keysphương thức này không khả dụng.
ekillaby

19
@slashnick "Phiên bản đơn giản hóa" của bạn trả về tất cả các thuộc tính trong chuỗi nguyên mẫu của đối tượng (vì nó đang sử dụng "for ... in"), trong khi phương thức (ECMAScript 5.1) Object.keyschỉ trả về các thuộc tính của đối tượng. Tôi thấy đó là một sự khác biệt quan trọng.
Martin Carel

255

Như slashnick đã chỉ ra, bạn có thể sử dụng cấu trúc "for in" để lặp lại một đối tượng cho tên thuộc tính của nó. Tuy nhiên, bạn sẽ lặp lại tất cả các tên thuộc tính trong chuỗi nguyên mẫu của đối tượng. Nếu bạn muốn lặp chỉ trên thuộc tính riêng của đối tượng, bạn có thể tận dụng các Object # hasOwnProperty () phương pháp. Do đó có những điều sau đây.

for (var key in obj) {
    if (obj.hasOwnProperty(key)) {
        /* useful code here */
    }
}

25
Tôi ước tôi đã đọc nó trước khi câu trả lời của slashnic ở trên. Tôi chỉ phải mất 15 phút để giữ escphím vì đối tượng có khoảng một triệu tài sản, hầu hết chúng không được sử dụng và tôi đã có một cảnh báo về nó.
Đánh dấu Henderson

Đây là một bài viết xuất sắc về chủ đề của chính Zakas: nczonline.net/blog/2010/07/27/NH
Pablo Cabrera

4
LOL @MarkHenderson - nhưng lần sau, chỉ cần giết quá trình của trình duyệt và khởi động lại thay vì lãng phí 15 phút :)
JD Smith

Một chức năng liên quan là obj.getOwnPropertyNames () - developer.mozilla.org/en-US/docs/JavaScript/Reference/
Steve Goodman

@MarkHenderson Tại sao bạn không sử dụng console.log?
LasagnaAndroid

102

Như Sam Dutton đã trả lời, một phương pháp mới cho chính mục đích này đã được giới thiệu trong ECMAScript Edition Edition. Object.keys()sẽ làm những gì bạn muốn và được hỗ trợ trong Firefox 4 , Chrome 6, Safari 5 và IE 9 .

Bạn cũng có thể dễ dàng thực hiện phương thức trong các trình duyệt không hỗ trợ. Tuy nhiên, một số triển khai ngoài đó không tương thích hoàn toàn với Internet Explorer. Đây là một giải pháp tương thích hơn:

Object.keys = Object.keys || (function () {
    var hasOwnProperty = Object.prototype.hasOwnProperty,
        hasDontEnumBug = !{toString:null}.propertyIsEnumerable("toString"),
        DontEnums = [ 
            'toString', 'toLocaleString', 'valueOf', 'hasOwnProperty',
            'isPrototypeOf', 'propertyIsEnumerable', 'constructor'
        ],
        DontEnumsLength = DontEnums.length;

    return function (o) {
        if (typeof o != "object" && typeof o != "function" || o === null)
            throw new TypeError("Object.keys called on a non-object");

        var result = [];
        for (var name in o) {
            if (hasOwnProperty.call(o, name))
                result.push(name);
        }

        if (hasDontEnumBug) {
            for (var i = 0; i < DontEnumsLength; i++) {
                if (hasOwnProperty.call(o, DontEnums[i]))
                    result.push(DontEnums[i]);
            }   
        }

        return result;
    };
})();

Lưu ý rằng câu trả lời hiện được chấp nhận không bao gồm kiểm tra hasOwnProperty () và sẽ trả về các thuộc tính được kế thừa thông qua chuỗi nguyên mẫu. Nó cũng không giải thích cho lỗi DontEnum nổi tiếng trong Internet Explorer nơi các thuộc tính không thể đếm được trên chuỗi nguyên mẫu khiến các thuộc tính được khai báo cục bộ có cùng tên để thừa hưởng thuộc tính DontEnum của chúng.

Việc triển khai Object.keys () sẽ cung cấp cho bạn một giải pháp mạnh mẽ hơn.

EDIT: sau một cuộc thảo luận gần đây với kangax , một người đóng góp nổi tiếng cho Prototype, tôi đã triển khai cách khắc phục lỗi DontEnum dựa trên mã cho Object.forIn()chức năng của anh ta được tìm thấy ở đây .


Câu trả lời tuyệt vời, tôi nghĩ rằng câu trả lời được chấp nhận vẫn là giải pháp chính xác hiệu quả nhất, cho rằng nó luôn luôn là một câu lệnh JSON. Đây chắc chắn là một để sử dụng ở nơi khác.
David Snabel-Caunt

1
@David Caunt: Cảm ơn :-) Thật không may, câu trả lời được chấp nhận vẫn không phù hợp với lỗi DontEnum và bạn không bao giờ biết đối tượng JSON nào có thể có một chuỗi như "valueOf" hoặc "constructor" là một trong các khóa của nó. Nó cũng sẽ lặp đi lặp lại trên các phần mở rộng Object.prototype. Mặc dù vậy, thông thường, mã ngắn hơn trông hấp dẫn hơn đáng kể so với mã lớn hơn, mạnh hơn, nhưng điểm của câu trả lời này là sử dụng ECMAScript 5 Object.keys(), có thể được triển khai trong các trình duyệt không hỗ trợ sử dụng mã này. Phiên bản gốc sẽ còn hiệu quả hơn thế này.
Andy E

2
Rất đẹp, Andy :) Tôi sẽ giống như để nhắc nhở - không ai dường như đề cập trong chủ đề này - đó ES5 Object.keyschỉ trả về một mảng các chuỗi tương ứng với đếm được thuộc tính của một đối tượng. Điều này có thể không quan trọng khi làm việc với các đối tượng gốc (do người dùng xác định), nhưng sẽ hiển thị rất nhiều với các đối tượng máy chủ (mặc dù hành vi của đối tượng máy chủ không xác định là một câu chuyện riêng - đau đớn). Để liệt kê TẤT CẢ các thuộc tính (bao gồm cả không thể đếm được), ES5 cung cấp Object.getOwnPropertyNames(xem hỗ trợ của nó trong bảng tổng hợp của tôi - kangax.github.com/es5-compat-table )
kangax

2
Tôi đã tích hợp giải pháp này vào es5-shim github.com/kriskowal/es5-shim/blob/master/es5-shim.js#L390
Kris Kowal

2
Ai đó có thể giải thích tại sao điều này được thực hiện như Object.keys(stuff)và không stuff.keys()?
Blazemonger

32

Lưu ý rằng Object.keys và các phương thức ECMAScript 5 khác được Firefox 4, Chrome 6, Safari 5, IE 9 trở lên hỗ trợ.

Ví dụ:

var o = {"foo": 1, "bar": 2}; 
alert(Object.keys(o));

Bảng tương thích ECMAScript 5: http : // Khangax.github.com/es5-compat-table/

Mô tả các phương thức mới: http://markcaudill.com/index.php/2009/04/javascript-new-features-ecma5/


Ngoài ra, hãy kiểm tra các phím () trong bảng điều khiển cho Chrome Dev Tools, Fireorms, v.v.
Sam Dutton


28

Object.getOwnPropertyNames(obj)

Hàm này cũng hiển thị các thuộc tính không thể đếm được ngoài các thuộc tính được hiển thị bởi Object.keys(obj) .

Trong JS, mọi thuộc tính đều có một vài thuộc tính, bao gồm cả boolean enumerable .

Nói chung, các thuộc tính không thể đếm được là "nội tâm" hơn và ít được sử dụng hơn, nhưng đôi khi thật sâu sắc khi nhìn vào chúng để xem điều gì đang thực sự xảy ra.

Thí dụ:

var o = Object.create({base:0})
Object.defineProperty(o, 'yes', {enumerable: true})
Object.defineProperty(o, 'not', {enumerable: false})

console.log(Object.getOwnPropertyNames(o))
// [ 'yes', 'not' ]

console.log(Object.keys(o))
// [ 'yes' ]

for (var x in o)
    console.log(x)
// yes, base

Cũng lưu ý cách làm:

  • Object.getOwnPropertyNamesObject.keys không đi lên chuỗi nguyên mẫu để tìmbase
  • for in làm

Tìm hiểu thêm về chuỗi nguyên mẫu tại đây: https://stackoverflow.com/a/23877420/895245


16

Tôi là một fan hâm mộ lớn của chức năng kết xuất.

http://ajaxian.com/archives/javascript-variable-dump-in-coldfusion văn bản thay thế


1
+1 vì tôi có ý định xây dựng một cái gì đó tương tự (mặc dù không tốt bằng).
Camilo Martin

1
netgrow.com.au/assets/files/dump/dump.zip không tìm thấy Làm cách nào tôi có thể tải xuống javascript?
Kiquenet

@Kiquenet mỗi khi tôi muốn xây dựng một cái gì đó như thế này tôi giải quyết cho trình kiểm tra đối tượng thông thường, nếu bạn muốn kết xuất đó trong HTML thì có những thứ như mô-đun npm . Thành thật mà nói, điều khiến tôi bế tắc là tôi muốn thứ gì đó tốt hơn những gì trên hình ảnh đó nhưng không bao giờ có thể khái niệm hóa nó. Thật là tồi tệ khi duyệt các đối tượng trong thanh tra nhưng heuristic để thử và suy ra ý nghĩa từ các đối tượng tùy ý (ví dụ: sắp xếp các mảng của các đối tượng vào các bảng với các cột) không phải lúc nào cũng hoạt động trong thực tế.
Camilo Martin

Có gì về Khá In Javascript https://j11y.io/demos/prettyprint/ ?
Kiquenet

13

Có thể làm điều đó với jQuery như sau:

var objectKeys = $.map(object, function(value, key) {
  return key;
});

9

nếu bạn đang cố gắng chỉ lấy các phần tử nhưng không phải các hàm thì mã này có thể giúp bạn

this.getKeys = function() {

    var keys = new Array();
    for(var key in this) {

        if( typeof this[key] !== 'function') {

            keys.push(key);
        }
    }
    return keys;
}

đây là một phần trong quá trình triển khai HashMap của tôi và tôi chỉ muốn các khóa, "đây" là đối tượng hashmap chứa các khóa


8

Điều này sẽ hoạt động trong hầu hết các trình duyệt, ngay cả trong IE8 và không có thư viện thuộc bất kỳ loại nào được yêu cầu. var i là chìa khóa của bạn.

var myJSONObject =  {"ircEvent": "PRIVMSG", "method": "newURI", "regex": "^http://.*"}; 
var keys=[];
for (var i in myJSONObject ) { keys.push(i); }
alert(keys);

2
Câu trả lời của bạn có vẻ giống với những câu đã được đăng, còn gì để thêm không?
VKen

7

Trong các trình duyệt hỗ trợ js 1.8:

[i for(i in obj)]

7

Mozilla có đầy đủ chi tiết triển khai về cách thực hiện trong trình duyệt không được hỗ trợ, nếu điều đó giúp:

if (!Object.keys) {
  Object.keys = (function () {
    var hasOwnProperty = Object.prototype.hasOwnProperty,
        hasDontEnumBug = !({toString: null}).propertyIsEnumerable('toString'),
        dontEnums = [
          'toString',
          'toLocaleString',
          'valueOf',
          'hasOwnProperty',
          'isPrototypeOf',
          'propertyIsEnumerable',
          'constructor'
        ],
        dontEnumsLength = dontEnums.length;

    return function (obj) {
      if (typeof obj !== 'object' && typeof obj !== 'function' || obj === null) throw new TypeError('Object.keys called on non-object');

      var result = [];

      for (var prop in obj) {
        if (hasOwnProperty.call(obj, prop)) result.push(prop);
      }

      if (hasDontEnumBug) {
        for (var i=0; i < dontEnumsLength; i++) {
          if (hasOwnProperty.call(obj, dontEnums[i])) result.push(dontEnums[i]);
        }
      }
      return result;
    };
  })();
}

Bạn có thể bao gồm nó theo cách bạn muốn, nhưng có thể trong một số loại extensions.jstệp ở đầu ngăn xếp tập lệnh của bạn.


Việc triển khai MDN dựa trên Andy E, đã được đưa ra như một câu trả lời.
outis

5

Sử dụng Reflect.ownKeys()

var obj = {a: 1, b: 2, c: 3};
Reflect.ownKeys(obj) // ["a", "b", "c"]

Object.keysObject.getOwnPropertyNames không thể có được các thuộc tính không thể đếm được . Nó hoạt động ngay cả đối với các thuộc tính không thể đếm được .

var obj = {a: 1, b: 2, c: 3};
obj[Symbol()] = 4;
Reflect.ownKeys(obj) // ["a", "b", "c", Symbol()]


4

Vì tôi sử dụng underscore.js trong hầu hết mọi dự án, tôi sẽ sử dụng keyshàm:

var obj = {name: 'gach', hello: 'world'};
console.log(_.keys(obj));

Đầu ra của nó sẽ là:

['name', 'hello']

Đây là một thư viện công cụ cho chức năng javascript thường được sử dụng: underscorejs.org
schmijos

4

Xây dựng trên câu trả lời được chấp nhận.

Nếu đối tượng có thuộc tính bạn muốn gọi say .properIES () hãy thử!

var keys = Object.keys(myJSONObject);

for (var j=0; j < keys.length; j++) {
  Object[keys[j]].properties();
}

0

Giải pháp hoạt động trên các trường hợp của tôi và trình duyệt chéo:

var getKeys = function(obj) {
    var type = typeof  obj;
    var isObjectType = type === 'function' || type === 'object' || !!obj;

    // 1
    if(isObjectType) {
        return Object.keys(obj);
    }

    // 2
    var keys = [];
    for(var i in obj) {
        if(obj.hasOwnProperty(i)) {
            keys.push(i)
        }
    }
    if(keys.length) {
        return keys;
    }

    // 3 - bug for ie9 <
    var hasEnumbug = !{toString: null}.propertyIsEnumerable('toString');
    if(hasEnumbug) {
        var nonEnumerableProps = ['valueOf', 'isPrototypeOf', 'toString',
            'propertyIsEnumerable', 'hasOwnProperty', 'toLocaleString'];

        var nonEnumIdx = nonEnumerableProps.length;

        while (nonEnumIdx--) {
            var prop = nonEnumerableProps[nonEnumIdx];
            if (Object.prototype.hasOwnProperty.call(obj, prop)) {
                keys.push(prop);
            }
        }

    }

    return keys;
};
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.