Câu hỏi Làm thế nào để đếm số lượng khóa / thuộc tính của một đối tượng trong JavaScript một cách hiệu quả?


Cách nhanh nhất để đếm số lượng khóa / thuộc tính của một đối tượng là gì? Nó có thể làm điều này mà không cần lặp qua đối tượng? tức là không làm

var count = 0;
for (k in myobj) if (myobj.hasOwnProperty(k)) count++;

(Firefox đã cung cấp một phép thuật __count__ tài sản, nhưng điều này đã được gỡ bỏ ở đâu đó xung quanh phiên bản 4.)


1196
2017-09-24 08:56


gốc


Liên quan: stackoverflow.com/questions/5223/… - ripper234
điểm chuẩn hiệu suất theo các cách khác nhau: jsben.ch/#/oSt2p - EscapeNetscape
Có thể trùng lặp Độ dài của đối tượng JavaScript - Adam Katz


Các câu trả lời:


Để thực hiện điều này trong bất kỳ môi trường tương thích ES5 nào, chẳng hạn như Nút, Chrome, IE 9+, FF 4+ hoặc Safari 5+:

Object.keys(obj).length

1991
2018-02-03 17:47



Không chỉ Node.js, nhưng bất kỳ môi trường nào hỗ trợ ES5 - Yi Jiang
BTW ... chỉ cần chạy một số thử nghiệm ... phương pháp này chạy trong thời gian O (n). Vòng lặp for không tệ hơn nhiều so với phương thức này. ** gương mặt buồn ** stackoverflow.com/questions/7956554/… - BMiner
-1 (-200 nếu tôi có thể) Điều này không chỉ lặp đi lặp lại thông qua đối tượng mà còn tạo ra một mảng hoàn toàn mới với tất cả các khóa của nó, vì vậy nó hoàn toàn thất bại khi trả lời câu hỏi. - GetFree
Nó có vẻ nhanh hơn nhiều so với thực hiện (ít nhất là trên Chrome 25): jsperf.com/count-elements-in-object - fserb
@GetFree Tại sao rất nhiều ngón tay cái lên? Đây chắc chắn là cách nhanh nhất về mặt mã hóa. Không yêu cầu thêm phương thức hoặc thư viện nào. Xét về tốc độ mã, dường như nó cũng không quá tệ. Không hoàn toàn thất bại. 87 dấu hiệu không thành công cho bạn. - Andrew


Bạn có thể sử dụng mã này:

if (!Object.keys) {
    Object.keys = function (obj) {
        var keys = [],
            k;
        for (k in obj) {
            if (Object.prototype.hasOwnProperty.call(obj, k)) {
                keys.push(k);
            }
        }
        return keys;
    };
}

Sau đó, bạn có thể sử dụng điều này trong các trình duyệt cũ hơn:

var len = Object.keys(obj).length;

141
2018-04-15 10:48



Mục đích của việc kiểm tra là gì (Object.prototype.hasOwnProperty.call(obj, k))? - styfle
@styfle Nếu bạn sử dụng cho vòng lặp để lặp qua các thuộc tính của đối tượng, bạn cũng có được các thuộc tính trong chuỗi nguyên mẫu. Đó là lý do tại sao kiểm tra hasOwnProperty là cần thiết. Nó chỉ trả về các thuộc tính được thiết lập trên chính đối tượng đó. - Renaat De Muynck
@styfle Để làm cho nó đơn giản hơn bạn chỉ có thể viết obj.hasOwnProperty(k) (Tôi thực sự đã làm điều này trong bài viết gốc của tôi, nhưng cập nhật nó sau này). hasOwnProperty có sẵn trên mọi đối tượng vì nó là một phần của Objectnguyên mẫu, nhưng trong trường hợp hiếm hoi rằng phương pháp này sẽ bị xóa hoặc ghi đè, bạn có thể nhận được kết quả không mong muốn. Bằng cách gọi nó từ Object.prototype nó làm cho nó ít mạnh mẽ hơn. Lý do sử dụng call là vì bạn muốn gọi phương thức obj thay vì trên nguyên mẫu. - Renaat De Muynck
Nó sẽ không tốt hơn để sử dụng phiên bản này? developer.mozilla.org/en-US/docs/JavaScript/Reference/… - Xavier Delamotte
@ XavierDelamotte Bạn hoàn toàn chính xác. Trong khi phiên bản của tôi hoạt động, nó rất cơ bản và là một ví dụ. Mã của Mozilla an toàn hơn. (PS: Liên kết của bạn cũng nằm trong câu trả lời được chấp nhận) - Renaat De Muynck


Nếu bạn đang sử dụng Underscore.js bạn có thể dùng _.kích thước (cảm ơn @douwe):
_.size(obj)

Hoặc bạn cũng có thể sử dụng _.keys có thể rõ ràng hơn đối với một số:
_.keys(obj).length 

Tôi khuyên bạn nên nhấn mạnh Underscore, một thư viện chặt chẽ để thực hiện rất nhiều điều cơ bản. Bất cứ khi nào có thể, chúng khớp với ECMA5 và trì hoãn việc triển khai gốc.

Nếu không, tôi sẽ hỗ trợ câu trả lời của @ Avi. Tôi đã chỉnh sửa nó để thêm một liên kết đến tài liệu MDC bao gồm phương thức keys () mà bạn có thể thêm vào các trình duyệt không phải ECMA5.


126
2018-05-16 15:24



Nếu bạn sử dụng underscore.js thì bạn nên sử dụng _.size để thay thế. Điều tốt là nếu bạn bằng cách nào đó chuyển từ mảng sang đối tượng hoặc ngược lại kết quả vẫn giữ nguyên. - douwe
Lưu ý: điều này cũng hoạt động tương tự với lodash - Jeremy - DeerAngel-org
Và từ sự hiểu biết của tôi lodash nói chung là tốt hơn so với gạch dưới (mặc dù họ làm những việc tương tự). - Merlyn Morgan-Graham
@ MerlynMorgan-Graham nếu tôi nhớ lại chính xác, lodash ban đầu là một ngã ba của gạch dưới ... - molson504x
_.keys(obj).length làm việc tốt nhất cho tôi, bởi vì đối tượng trả về của tôi đôi khi là một chuỗi đơn giản không có thuộc tính bên trong nó. _.size(obj) cho tôi trở lại độ dài của chuỗi, trong khi _.keys(obj).length trả về 0. - Jacob Stamm


Việc thực hiện Object tiêu chuẩn (ES5.1 Đối tượng thuộc tính nội bộ và phương pháp) không yêu cầu Object để theo dõi số lượng khóa / thuộc tính của nó, vì vậy không nên có cách tiêu chuẩn để xác định kích thước của một Object mà không lặp lại một cách rõ ràng hoặc ngầm qua các khóa của nó.

Vì vậy, đây là các lựa chọn thay thế phổ biến nhất:

1. Object.keys của ECMAScript ()

Object.keys(obj).length; Hoạt động bởi nội bộ lặp qua các phím để tính toán một mảng tạm thời và trả về độ dài của nó.

  • Ưu điểm - Cú pháp dễ đọc và dễ đọc. Không yêu cầu thư viện hoặc mã tùy chỉnh ngoại trừ shim nếu hỗ trợ gốc không khả dụng
  • Nhược điểm - Bộ nhớ trên do việc tạo mảng.

2. Giải pháp dựa trên thư viện

Nhiều ví dụ dựa trên thư viện ở nơi khác trong chủ đề này là thành ngữ hữu ích trong ngữ cảnh của thư viện của họ. Tuy nhiên, từ quan điểm hiệu suất, không có gì để đạt được so với một mã không có thư viện hoàn hảo vì tất cả các phương thức thư viện đó thực sự đóng gói hoặc là vòng lặp for hoặc ES5 Object.keys (bản địa hoặc shimmed).

3. Tối ưu hóa một vòng lặp

Các phần chậm nhất của vòng lặp như vậy thường là .hasOwnProperty() cuộc gọi, vì chức năng gọi điện trên không. Vì vậy, khi tôi chỉ muốn số lượng mục nhập của một đối tượng JSON, tôi chỉ cần bỏ qua .hasOwnProperty() gọi nếu tôi biết rằng không có mã nào cũng không mở rộng Object.prototype.

Nếu không, mã của bạn có thể được tối ưu hóa rất ít bằng cách thực hiện k địa phương (var k) và bằng cách sử dụng toán tử tăng thêm tiền tố (++count) thay vì postfix.

var count = 0;
for (var k in myobj) if (myobj.hasOwnProperty(k)) ++count;

Một ý tưởng khác dựa vào bộ nhớ đệm hasOwnProperty phương pháp:

var hasOwn = Object.prototype.hasOwnProperty;
var count = 0;
for (var k in myobj) if (hasOwn.call(myobj, k)) ++count;

Cho dù điều này là nhanh hơn hay không trên một môi trường nhất định là một câu hỏi về điểm chuẩn. Hiệu suất rất hạn chế có thể được mong đợi anyway.


66
2017-09-24 09:11



Tại sao var k in myobj tăng hiệu suất? Theo tôi biết, chỉ các hàm mới khai báo phạm vi mới trong JavaScript. Có phải trong vòng một ngoại lệ đối với quy tắc này không? - Lars Gyrup Brink Nielsen
Đây có phải là nhanh hơn? for (var k in myobj) hasOwn.call(myobj, k) && ++count; tức là thay thế câu lệnh if bằng đơn giản &&? - Hamza Kubba


Nếu bạn đang thực sự chạy vào một vấn đề hiệu suất tôi sẽ đề nghị gói các cuộc gọi thêm / loại bỏ các thuộc tính đến / từ đối tượng với một chức năng cũng tăng / giảm một thuộc tính có tên (kích thước?) Thích hợp.

Bạn chỉ cần tính số lượng tài sản ban đầu một lần và di chuyển từ đó. Nếu không có một vấn đề hiệu suất thực tế, đừng bận tâm. Chỉ cần quấn mã bit đó vào một hàm getNumberOfProperties(object) và được thực hiện với nó.


23
2017-09-24 09:13



@hitautodestruct Bởi vì ông cung cấp một giải pháp. - crush
@crush Câu trả lời này dường như gợi ý những điều cần làm thay vì đưa ra một giải pháp trực tiếp. - hitautodestruct
@hitautodestruct nó gợi ý một câu trả lời: tăng / giảm số lượng đóng gói với các phương thức add / remove. Có một câu trả lời chính xác như thế này bên dưới. Sự khác biệt duy nhất là, Confusion không cung cấp bất kỳ mã nào. Câu trả lời không bắt buộc phải cung cấp các giải pháp mã. - crush
@crush Phải rồi, nhưng họ không nên bắt đầu bằng một câu hỏi. Đã sửa :) - hitautodestruct
nó có thể không hoàn hảo ... nhưng so với "câu trả lời" khác thì đây có thể là giải pháp tốt nhất cho một số tình huống - d.raev


Tôi không biết bất kỳ cách nào để làm điều này, tuy nhiên để giữ cho các lần lặp ở mức tối thiểu, bạn có thể thử kiểm tra sự tồn tại của __count__ và nếu nó không tồn tại (tức là không phải Firefox) thì bạn có thể lặp lại đối tượng và định nghĩa nó để sử dụng sau, ví dụ:

if (myobj.__count__ === undefined) {
  myobj.__count__ = ...
}

Bằng cách này, mọi trình duyệt đều hỗ trợ __count__ sẽ sử dụng nó, và lặp lại sẽ chỉ được thực hiện cho những người không. Nếu số lượng thay đổi và bạn không thể làm điều này, bạn luôn có thể làm cho nó một chức năng:

if (myobj.__count__ === undefined) {
  myobj.__count__ = function() { return ... }
  myobj.__count__.toString = function() { return this(); }
}

Bằng cách này bất cứ lúc nào bạn tham khảo myobj.__count__ chức năng sẽ kích hoạt và tính toán lại.


15
2018-01-17 11:15



Lưu ý rằng Object.prototype.__count__ đang bị xóa trong Gecko 1.9.3: whereswalden.com/2010/04/06/…đếm-property-of-objects-is-being-removed / - dshaw
Bây giờ Firefox 4 đã hết, câu trả lời này đã lỗi thời. Object.__count__ đã biến mất, và tốt riddance quá. - Yi Jiang
Tôi sẽ không nói câu trả lời là lỗi thời. Nó vẫn là một chiến lược thú vị để đóng gói một giá trị trong một hàm. - devios1
nên sử dụng đối tượng nguyên mẫu để mở rộng - Aaria Carter-Weir


Theo tuyên bố của Avi Flax https://stackoverflow.com/a/4889658/1047014

Object.keys(obj).length

sẽ thực hiện thủ thuật cho tất cả các thuộc tính enumerable trên đối tượng của bạn, nhưng cũng bao gồm các thuộc tính không thể đếm được mà bạn có thể sử dụng Object.getOwnPropertyNames. Đây là sự khác biệt:

var myObject = new Object();

Object.defineProperty(myObject, "nonEnumerableProp", {
  enumerable: false
});
Object.defineProperty(myObject, "enumerableProp", {
  enumerable: true
});

console.log(Object.getOwnPropertyNames(myObject).length); //outputs 2
console.log(Object.keys(myObject).length); //outputs 1

console.log(myObject.hasOwnProperty("nonEnumerableProp")); //outputs true
console.log(myObject.hasOwnProperty("enumerableProp")); //outputs true

console.log("nonEnumerableProp" in myObject); //outputs true
console.log("enumerableProp" in myObject); //outputs true

Như đã nêu đây điều này có cùng hỗ trợ trình duyệt như Object.keys

Tuy nhiên, trong hầu hết các trường hợp, bạn có thể không muốn bao gồm các số không phải trong các loại hoạt động này, nhưng nó luôn luôn tốt để biết sự khác biệt;)


15
2018-03-30 01:11





Để lặp lại câu trả lời của Avi Flax Object.keys (obj) .length là chính xác cho một đối tượng không có chức năng gắn với nó

thí dụ:

obj = {"lol": "what", owo: "pfft"};
Object.keys(obj).length; // should be 2

đấu với

arr = [];
obj = {"lol": "what", owo: "pfft"};
obj.omg = function(){
    _.each(obj, function(a){
        arr.push(a);
    });
};
Object.keys(obj).length; // should be 3 because it looks like this 
/* obj === {"lol": "what", owo: "pfft", omg: function(){_.each(obj, function(a){arr.push(a);});}} */

các bước để tránh điều này:

  1. không đặt các hàm vào một đối tượng mà bạn muốn đếm số lượng khóa trong

  2. sử dụng một đối tượng riêng biệt hoặc tạo một đối tượng mới cụ thể cho các hàm (nếu bạn muốn đếm số lượng hàm có trong tệp bằng cách sử dụng Object.keys(obj).length)

cũng có tôi đã sử dụng mô-đun _ hoặc gạch dưới từ các nút trong ví dụ của tôi

tài liệu có thể tìm thấy ở đây http://underscorejs.org/ cũng như nguồn của nó trên github và nhiều thông tin khác

Và cuối cùng là triển khai lodash https://lodash.com/docs#size

_.size(obj)


12
2018-01-04 09:04



Trả lời nhận xét của bạn về Array(obj).length: Nó không hoạt động. http://jsfiddle.net/Jhy8M/ - Jamie Chong
yeah tôi nhìn vào nó nhiều hơn một chút sẽ kết thúc loại bỏ câu trả lời này nếu có thể hoặc chỉ cần chỉnh sửa tất cả cùng nhau - Belldandu
chỉnh sửa câu trả lời của tôi để lặp lại trên câu trả lời của Avi Flax - Belldandu
Tôi không thấy rằng điều này có liên quan gì đến chức năng, vì một, và trong Chrome tôi không thấy hành vi này chút nào. Tôi nghi ngờ điều này có thể liên quan đến hành vi mặc định của Object.defineProperty (): đếm được đó là false, mặc dù tôi chưa tìm thấy bất kỳ tài liệu nào về cách var obj = { a: true, b: true } có thể khác với var obj = {}; obj.a = true; obj.b = true; hoặc đơn giản là nếu một giải thích / ngữ nghĩa khác của W3 đã được Chrome chấp nhận. - Nolo