JavaScript에서 객체의 키 / 속성 수를 효율적으로 계산하는 방법은 무엇입니까?


1544

객체의 키 / 속성 수를 계산하는 가장 빠른 방법은 무엇입니까? 객체를 반복하지 않고 이것을 할 수 있습니까? 즉,하지 않고

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

(Firefox는 마법의 __count__속성을 제공 했지만 버전 4 부근에서 제거되었습니다.)



2
다양한 방법으로 성능 벤치 마크 : jsben.ch/#/oSt2p
EscapeNetscape

답변:


2516

Node , Chrome, IE 9+, Firefox 4+ 또는 Safari 5+ 와 같은 ES5 호환 환경 에서이 작업을 수행하려면

Object.keys(obj).length

8
Node.js뿐만 아니라 ES5를 지원하는 모든 환경
Yi Jiang

59
BTW ... 방금 몇 가지 테스트를 실행했습니다 ...이 방법은 O (n) 시간에 실행됩니다. for 루프는이 방법보다 나쁘지 않습니다. ** 슬픈 얼굴 ** stackoverflow.com/questions/7956554/…
BMiner

161
-1 (가능한 경우 -200) 이것은 객체를 반복 할뿐만 아니라 모든 키로 완전히 새로운 배열을 생성하므로 질문에 완전히 대답하지 못합니다.
GetFree

42
그것은 훨씬 더 빨리 위해하는 것보다 같다 (크롬 25 이상) : jsperf.com/count-elements-in-object
fserb

34
@GetFree 왜 그렇게 많은 엄지 손가락? 이것은 코딩 측면에서 가장 빠른 방법입니다. 추가 방법이나 라이브러리가 필요하지 않습니다. 코드 속도면에서 그렇게 나쁘지는 않습니다. 전혀 실패하지 않습니다. 87 엄지 손가락이 실패합니다.
Andrew

150

이 코드를 사용할 수 있습니다 :

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

그런 다음 이전 브라우저에서도 사용할 수 있습니다.

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

2
수표의 목적은 무엇입니까 (Object.prototype.hasOwnProperty.call(obj, k))?
styfle

14
@styfle for 루프를 사용하여 객체의 속성을 반복하면 프로토 타입 체인의 속성도 얻을 수 있습니다. 이것이 점검 hasOwnProperty이 필요한 이유 입니다. 객체 자체에 설정된 속성 만 반환합니다.
Renaat De Muynck

13
@styfle 더 간단하게하기 위해 글을 쓸 수 있습니다 obj.hasOwnProperty(k)(실제로 원래 게시물 에서이 작업을 수행했지만 나중에 업데이트했습니다). hasOwnPropertyObject프로토 타입의 일부이기 때문에 모든 객체에서 사용할 수 있지만,이 방법이 제거되거나 재정의되는 경우는 드물지만 예기치 않은 결과가 발생할 수 있습니다. 그것을 호출함으로써 Object.prototype조금 더 강력 해집니다. 사용하는 이유 는 프로토 타입 대신 call메소드를 호출하기 때문 obj입니다.
Renaat De Muynck

6
이 버전을 사용하는 것이 더 좋지 않습니까? developer.mozilla.org/en-US/docs/JavaScript/Reference/…
Xavier Delamotte

1
@XavierDelamotte 당신은 절대적으로 맞습니다. 내 버전이 작동하는 동안 매우 기본적이고 모범적 인 예입니다. 모질라 코드가 더 안전합니다. (PS : 귀하의 링크도 허용 된 답변입니다)
Renaat De Muynck

137

당신이 사용하는 경우 Underscore.js를 당신이 사용할 수있는 _.size (감사 @douwe을) :
_.size(obj)

또는 _.keys 를 사용할 수도 있습니다.
_.keys(obj).length

많은 기본 작업을 수행하기위한 엄격한 라이브러리 인 Underscore를 강력히 권장합니다. 가능할 때마다 ECMA5와 일치하고 기본 구현을 연기합니다.

그렇지 않으면 @Avi의 답변을 지원합니다. ECMA5가 아닌 브라우저에 추가 할 수있는 keys () 메소드를 포함하는 MDC 문서에 대한 링크를 추가하도록 편집했습니다.


9
underscore.js를 사용하는 경우 대신 _.size를 사용해야합니다. 좋은 점은 배열에서 객체로 또는 그 반대로 전환하면 결과가 동일하게 유지된다는 것입니다.
douwe

2
그리고 내 이해에서 lodash는 일반적으로 밑줄보다 낫습니다 (비슷한 일을하지만).
멀린 모건-그레이엄

1
@ MerlynMorgan-Graham 내가 올바르게 기억한다면 lodash는 원래 밑줄의 포크입니다.
molson504x

6
_.keys(obj).length내 반환 객체는 때로는 속성이없는 일반 문자열이기 때문에 나에게 가장 효과적이었습니다. _.size(obj)날 동안, 문자열의 길이를 다시 부여합니다 _.keys(obj).length반환 0
야곱 STAMM

O (n) 복잡성 . Lodash와 Underscore는 Object.keys내부적으로 사용 됩니다. Underscore는 정의되지 않은 for..in경우 모든 키를 루프 내의 배열로 복사합니다 Object.keys.
N. Kudryavtsev

82

표준 Object 구현 ( ES5.1 Object Internal Properties and Methods )에는 Object키 / 속성 수를 추적 할 필요가 없으므로 키 Object를 명시 적으로 또는 암시 적으로 반복하지 않고 크기를 결정하는 표준 방법이 없어야 합니다.

가장 일반적으로 사용되는 대안은 다음과 같습니다.

1. ECMAScript의 Object.keys ()

Object.keys(obj).length;의 작품 내부 의 키 반복 임시 배열을 계산하고 그 길이를 반환합니다.

  • 장점 -읽기 쉽고 깨끗한 구문. 기본 지원을 사용할 수없는 경우 shim을 제외하고 라이브러리 또는 사용자 정의 코드가 필요하지 않습니다
  • 단점 -어레이 생성으로 인한 메모리 오버 헤드.

2. 라이브러리 기반 솔루션

이 주제의 다른 곳에서 많은 라이브러리 기반 예제는 라이브러리와 관련하여 유용한 관용구입니다. 그러나 성능 관점에서 볼 때 모든 라이브러리 메소드는 실제로 for-loop 또는 ES5 Object.keys(네이티브 또는 shimmed)를 캡슐화하므로 완벽한 라이브러리가없는 코드와 비교할 때 얻을 것이 없습니다 .

3. for-loop 최적화

이러한 for-loop 의 가장 느린 부분.hasOwnProperty()함수 호출 오버 헤드로 인해 일반적으로 호출입니다. 따라서 JSON 객체의 항목 수를 원할 때 .hasOwnProperty()코드가 없거나 확장되지 않는다는 것을 알고 있으면 호출을 건너 뜁니다 Object.prototype.

그렇지 않으면 k로컬 ( var k) 을 만들고 접두사 ++count대신 접두사 증가 연산자 ( )를 사용 하여 코드를 약간 최적화 할 수 있습니다 .

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

또 다른 아이디어는 hasOwnProperty메소드 캐싱에 의존합니다 .

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

주어진 환경에서 이것이 더 빠른지 아닌지는 벤치마킹의 문제입니다. 어쨌든 매우 제한된 성능 향상을 기대할 수 있습니다.


var k in myobj성능 이 향상됩니까? 내가 아는 한 함수 만 JavaScript에서 새로운 범위를 선언합니다. 인 루프가이 규칙의 예외입니까?
Lars Gyrup Brink Nielsen

1
이게 더 빠릅니까? for (var k in myobj) hasOwn.call(myobj, k) && ++count;즉, if 문을 간단한 &&?
Hamza Kubba

당신이 할 수있는 마지막 일은 : Object.getOwnPropertyNames(obj).length; 훨씬 간단합니다.
윌트

29

실제로 성능 문제가 발생하는 경우 적절한 이름의 (크기?) 속성을 늘리거나 줄이는 함수를 사용하여 객체에 속성을 추가하거나 제거하는 호출을 래핑하는 것이 좋습니다.

초기 속성 수를 한 번만 계산하고 거기서부터 계속 진행하면됩니다. 실제 성능 문제가 없다면 귀찮게하지 마십시오. 함수에 그 코드를 감아 서 getNumberOfProperties(object)끝내십시오.


4
그는 솔루션을 제공하기 때문에 @hitautodestruct.
분쇄

@crush이 답변은 직접적인 해결책을 제시하기보다는해야 할 일을 제안하는 것 같습니다.
hitautodestruct

5
@hitautodestruct는 add / remove 메소드를 사용하여 캡슐화 된 수를 늘리거나 줄입니다. 아래에 이와 같은 또 다른 대답이 있습니다. 유일한 차이점은 혼란은 코드를 제공하지 않았다는 것입니다. 답변은 코드 솔루션만을 제공하도록 요구되지 않습니다.
호감

1
그것은 다른 "답변"이 상황에 가장 적합한 솔루션이 될 수 있습니다에 비해 완벽 ...하지만하지 않을 수 있습니다
d.raev

1
지금까지 이것은 O (1) 상수 시간 성능 복잡성이라는 유일한 솔루션이므로 "반복없이"에 대한 질문 세부 사항에 답변하는 유일한 솔루션이므로 tru Accepted Answer가되어야합니다. O (n) 선형 시간 성능 복잡성을 제공하기 때문에 대부분의 다른 답변은 그렇지 않습니다. 그것은 함수 호출이 O (n)이므로 .keys () 함수와 같은 것을 호출하는 1 행 솔루션의 경우에도 마찬가지입니다.
cellepo

17

Avi Flax https://stackoverflow.com/a/4889658/1047014에 명시된 바와 같이

Object.keys(obj).length

는 객체의 열거 가능한 모든 속성에 대한 트릭을 수행하지만 열거 할 수없는 속성을 포함하기 위해 대신 사용할 수 있습니다 Object.getOwnPropertyNames. 차이점은 다음과 같습니다.

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

여기에 명시된 바와 같이 이것은 브라우저와 동일한 브라우저 지원이 있습니다Object.keys

그러나 대부분의 경우 이러한 유형의 작업에 숫자를 포함하지 않으려는 경우가 있지만 항상 차이점을 아는 것이 좋습니다.)


1
언급에 대 한 엄지 손가락 Object.getOwnPropertyNames, 당신은 여기에 하나만 ...
Wilt

15

나는 이것을 할 수있는 방법을 모른다. 그러나 반복을 최소화하기 위해 존재 여부를 확인하려고 시도하고 존재 __count__하지 않는 경우 (예 : Firefox가 아닌 경우) 객체를 반복하고 정의 할 수 있습니다 나중에 사용하기 위해 예를 들면 다음과 같습니다.

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

이런 식으로 지원하는 모든 브라우저 __count__가이를 사용하며 반복하지 않는 브라우저에 대해서만 반복이 수행됩니다. 카운트가 변경되어이를 수행 할 수없는 경우 항상 함수로 만들 수 있습니다.

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

이 방법으로 언제든지 myobj를 참조하십시오. __count__함수가 실행되고 다시 계산됩니다.


13
참고 Object.prototype.__count__도마뱀 1.9.3에서 제거되고 : whereswalden.com/2010/04/06/... 카운트 / -property -의 물체 - - - 제거되는
dshaw

17
이제 Firefox 4가 종료되었으므로이 답변은 더 이상 사용되지 않습니다. Object.__count__사라졌고, 좋은 탈퇴도있었습니다.
Yi Jiang

1
나는 그 대답이 쓸모 없다고 말하지 않을 것이다. 함수에 값을 캡슐화하는 것은 여전히 ​​흥미로운 전략입니다.
devios1

연장 프로토 타입 객체를 사용한다
Aaria 카터 위어

13

Avi Flax에서 반복하려면 Object.keys (obj) .length가 연결된 함수가없는 개체에 적합합니다.

예:

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

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);});}} */

이것을 피하는 단계 :

  1. 키 수를 세려는 객체에 함수를 넣지 마십시오.

  2. 별도의 객체를 사용하거나 함수를 위해 특별히 새로운 객체를 만듭니다 (를 사용하여 파일에있는 함수 수를 계산하려는 경우 Object.keys(obj).length)

또한 예 내 nodejs에서 _ 또는 밑줄 모듈을 사용했습니다.

문서는 여기에서 찾을 수 있습니다 http://underscorejs.org/ 뿐만 아니라 GitHub의 및 기타 다양한 정보의 소스로

마지막으로 lodash 구현 https://lodash.com/docs#size

_.size(obj)


에 대한 귀하의 의견에 답변 Array(obj).length: 작동하지 않습니다. http://jsfiddle.net/Jhy8M/
Jamie Chong

네, 가능하다면이 답변을 제거하거나 모두 함께 편집하게 될 것입니다
Belldandu

나는 이것이 함수와 관련이 있다는 것을 알지 못하고 Chrome에서는이 동작이 전혀 보이지 않습니다. 나는 이것이의 기본 동작과해야 할 일을했을 수도 의심 것 열거 : Object.defineProperty ()false나는 아직 방법에 대한 문서를 찾을 수 없습니다했습니다 불구 var obj = { a: true, b: true }다를 수 있습니다 var obj = {}; obj.a = true; obj.b = true;또는 W3의 다른 해석 / 의미가있다 단순히 경우를 Chrome에서 채택했습니다.
Nolo

10

위에 답변 된대로 : Object.keys(obj).length

그러나 이제 ES6에 실제 Map 클래스 가 있으므로 객체의 속성을 사용하는 대신 사용하는 것이 좋습니다 .

const map = new Map();
map.set("key", "value");
map.size; // THE fastest way

8

Underscore.js가 프로젝트에 포함 된 사람들은 다음을 수행 할 수 있습니다.

_({a:'', b:''}).size() // => 2

또는 기능적 스타일 :

_.size({a:'', b:''}) // => 2

8

다음은 세 가지 방법에 대한 성능 테스트입니다.

https://jsperf.com/get-the-number-of-keys-in-an-object

Object.keys (). 길이

초당 20,735

매우 간단하고 호환됩니다. 실행 빠른 하지만 그것은 그 다음 멀리 던져 도착 키의 새로운 배열을 생성하기 때문에 비싼.

return Object.keys(objectToRead).length;

열쇠를 통해 루프

초당 15,734

let size=0;
for(let k in objectToRead) {
  size++
}
return size;

약간 느리지 만 메모리 사용에 근접하지 않으므로 모바일 또는 다른 소형 컴퓨터에 최적화하려는 경우 더 좋습니다.

객체 대신 맵 사용

초당 953,839,338

return mapToRead.size;

기본적으로 Map은 자체 크기를 추적하므로 숫자 필드 만 반환합니다. 다른 방법보다 훨씬 빠릅니다. 객체를 제어 할 수 있으면 대신지도로 변환하십시오.


6

보낸 사람 : https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty

Object.defineProperty (obj, prop, descriptor)

모든 객체에 추가 할 수 있습니다.

Object.defineProperty(Object.prototype, "length", {
    enumerable: false,
    get: function() {
        return Object.keys(this).length;
    }
});

또는 단일 객체 :

var myObj = {};
Object.defineProperty(myObj, "length", {
    enumerable: false,
    get: function() {
        return Object.keys(this).length;
    }
});

예:

var myObj = {};
myObj.name  = "John Doe";
myObj.email = "leaked@example.com";
myObj.length; //output: 2

그런 식으로 추가하면 for..in 루프에 표시되지 않습니다.

for(var i in myObj) {
     console.log(i + ":" + myObj[i]);
}

산출:

name:John Doe
email:leaked@example.com

참고 : <IE9 브라우저에서는 작동하지 않습니다.


내장 프로토 타입을 확장하거나 속성 (예 : 원숭이 패치)을 폴리 필하려는 경우 올바르게 수행하십시오. 호환성을 위해 먼저 속성이 존재하는지 확인한 다음 속성을 열거 할 수 없도록 설정하여 자체 키를 만드십시오. 생성 된 개체는 오염되지 않습니다. 메소드의 사용 실제 방법을 . 내 권장 사항 : 내장 예제 와 같이 가능한 한 가깝게 동작하는 방법을 추가하는 방법을 보여주는 다음 예 를 따르십시오 .
user4642212

5

이 문제를 해결 한 방법은 객체에 저장된 항목 수를 기록하는 기본 목록을 직접 구현하는 것입니다. 매우 간단합니다. 이 같은:

function BasicList()
{
   var items = {};
   this.count = 0;

   this.add = function(index, item)
   {
      items[index] = item;
      this.count++;
   }

   this.remove = function (index)
   {
      delete items[index];
      this.count--;
   }

   this.get = function(index)
   {
      if (undefined === index)
        return items;
      else
        return items[index];
   }
}

1
재미있는 대안. 이렇게하면 집계 계산 함수의 오버 헤드가 제거되지만 요소를 추가하거나 제거 할 때마다 함수 호출 비용이 발생하지만 불행히도 더 나쁠 수 있습니다. 필자는 일반 목록과 비교할 때 제공 할 수있는 데이터 캡슐화 및 사용자 정의 메소드에 이러한 목록 구현을 개인적으로 사용하지만 빠른 항목 계산이 필요한 경우는 아닙니다.
Luc125

1
나는 당신의 대답을 좋아하지만, 나는 또한 희박하고 클릭 한 투표입니다. 이것은 흥미로운 딜레마를 제시합니다. 귀하의 답변에 이미 찬성 투표 한 상황과 같은 지시 사항의 일부 행동을 설명하지는 않지만 "클릭하여 투표"하라는 지시를 받았으며 그렇게 할 수 없습니다. 명령은 자동으로 실패하지만 여기서 자동으로 실패하는 것은 코드가 좋아하는 것이 아닙니다. 그냥 머리 위로.
L0j1k

1
나는이 답변, 멋진 데이터 구조를 정말로 좋아합니다. 추가시 함수 호출에 성능 영향이있는 경우 객체를 반복해야하는 경우 성능이 훨씬 향상됩니다. 이것은 가장 빠른 루프 패튼을 허용해야합니다var i = basiclist.count while(i--){...}
Lex

기본 목록에 최소한 기본 점검이 포함되어서는 안됩니까? add기존 항목을 대체 하는지 또는 remove존재하지 않는 색인으로 호출 되는지 확인하는 것과 같습니다. 또한 undefined유효한 항목 값인 경우 목록에 지정된 색인이 있는지 확인할 수 없습니다 .
Robert

2
목록을 주문하고 반복 가능해야합니다. 데이터는 객체에 저장되므로 요소 순서를 보장 할 수 없습니다. 구멍이있는 목록의 길이는 어떻게 찾습니까? this.count? 가장 높은 인덱스 값? 동일한 인덱스에 두 개의 항목을 추가하면 카운트가 오류 상태가됩니다.
Ultimate Gobblement

4

Object.keys(data).length키 데이터가있는 JSON 객체의 길이를 찾는 데 사용할 수 있습니다.


3

프로젝트에 Ext JS 4가있는 사용자는 다음을 수행 할 수 있습니다.

Ext.Object.getSize(myobj);

이것의 장점은 모든 Ext 호환 브라우저 (IE6-IE8 포함)에서 작동한다는 것입니다. 그러나 다른 제안 된 솔루션과 마찬가지로 실행 시간이 O (n)보다 나쁘지 않다고 생각합니다.


2

당신이 사용할 수있는:

Object.keys(objectName).length; 

Object.values(objectName).length;

1

OP는 객체가 nodeList인지 여부를 지정하지 않았습니다. 그렇다면 길이 메소드를 직접 사용할 수 있습니다. 예:

buttons = document.querySelectorAll('[id=button)) {
console.log('Found ' + buttons.length + ' on the screen'); 

0

위의 jQuery가 작동하지 않으면 시도하십시오.

$(Object.Item).length

3
Object.Item존재하지 않는 것 같습니다
Luc125

-1

나는 이것이 가능하지 않다고 생각합니다 (적어도 내부를 사용하지 않으면). 그리고 나는 이것을 최적화함으로써 많은 것을 얻을 것이라고 생각하지 않습니다.


2
받아 들여진 대답은 이것이 가능 하다는 것을 보여 주며 , 얻을 것이 없다고 주장 할 문맥이 없습니다.
도관

-1

다음과 같이 모든 객체에 사용할 수 있도록하려고합니다.

Object.defineProperty(Object.prototype, "length", {
get() {
    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;
        };
    }
    return Object.keys(this).length;
},});

console.log({"Name":"Joe","Age":26}.length) //returns 2

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.