JavaScript 배열의 음수 인덱스가 배열 길이에 영향을 주어야합니까?


84

자바 스크립트에서 다음과 같은 배열을 정의합니다.

var arr = [1,2,3];

또한 할 수 있습니다

arr[-1] = 4;

이제 내가하면

arr = undefined;

또한 arr [-1] 의 값에 대한 참조를 잃습니다 .

그래서 논리적으로 arr [-1]도 arr 의 일부인 것 같습니다 .

그러나 내가 다음을 수행하면 (arr을 정의되지 않음으로 설정하지 않고)

arr.length;

4가 아닌 3을 반환합니다 .

따라서 내 요점은 배열 이 음수 인덱스 와 함께 사용될 수 있다면 이러한 음수 인덱스도 길이의 일부 여야한다는 것입니다 **. 내가 틀렸거나 배열에 대한 개념을 놓치고있을 수도 있습니다.


음수 인덱스를 사용하려는 이유는 무엇입니까? 내가 뭔가를 놓치지 않는 한 요점을 보지 못합니다.
elclanrs

11
당신은 또한 쓸 수 있고 또한 arr[1.5] = 1길이에 영향을 미치지 않습니다. 언어 사양은 길이에 영향을 미치는 요소에 대해 매우 명확합니다. 당신은 그것을 좋아하지 않을 수도 있지만 당신은 그것과 함께 살아야합니다. 또는 자신의 경쟁 언어를 설계하고 사람들이이 언어로 전환하도록 설득하십시오.
Raymond Chen

1
@DigvijayYadav : JavaScript의 다른 많은 것들처럼 결함이나 기능으로 간주 될 수 있습니다. 이것은 배열이 객체처럼 동작하기 때문입니다. 문자열을 사용할 수도 var a = []; a['foo'] = 'baz'있지만 그렇다고해서 그렇게해야한다는 의미는 아닙니다. 그것은 분명히 모든 관습에 위배됩니다.
elclanrs

2
여러분, 여기서 요점은 배열이 객체라는 것입니다. 다른 점이 없다. 그것이이 행동의 이유이며, 당신이 그것을 좋아하지 않더라도 완전히 의도적 인 것입니다. 모든 숫자가 부동 소수점, 심지어 정수로 표현된다는 것을 알 때까지 기다리십시오. 자바 스크립트는 ... 호기심 언어
토니 R

2
사양에서 배열 요소의 설정을 정의하는 알고리즘의 세부 정보를 찾을 수 있습니다. es5.github.com/#x15.4.5.1 . ( 특히 4 단계) 및 "배열 인덱스"는 여기에 정의되어 있습니다 : es5.github.com /#x15.4 .
Felix Kling 2012

답변:


109

그래서 논리적으로는 arr [-1]도 arr의 일부인 것 같습니다.

예,하지만 당신이 생각하는 방식은 아닙니다.

임의의 속성을 배열에 할당 할 수 있습니다 (JavaScript의 다른 객체와 마찬가지로). 배열을 "인덱싱"하고 -1값을 할당 할 때 수행하는 작업 입니다. 이것은 배열의 구성원이 아니며 임의의 속성 일 뿐이므로 length해당 속성을 고려 해서는 안됩니다 .

즉, 다음 코드는 동일한 작업을 수행합니다.

var arr = [1, 2, 3];

​arr.cookies = 4;

alert(arr.length) // 3;

31
네, 음의 인덱스는 실제 인덱스처럼 작동하지 않습니다.
me_digvijay 2012

4
맞습니다, 그것들은 배열의 임의의 속성 일뿐입니다.
Andrew Whitaker 2012

그러나 양수 인덱스를 인덱스와 같은 속성이 아닌 속성으로 사용하고 배열 길이에 기여하지 않도록하려면 어떻게해야합니까?
me_digvijay nov.

7
그런 다음 배열을 사용하지 말고 일반 ol '객체를 사용하십시오. 그러나이 경우 내장 length자산을 잃게됩니다 .
Andrew Whitaker 2012

2
@Digvijay : (I 가정) 때문에 콘솔은 그냥 평범한 않는 양의 정수의 이름을 가진 속성을 보여줍니다 for에서 루프 0.length. 수행 console.dir(arr)전체 개체를 볼 수 있습니다. 또한 대괄호 표기법을 사용하여 배열에 액세스하는 것은 배열의 특성이 아니라 객체 ( var obj = {foo: 'bar'}; obj.foo or obj['foo']) 의 고유 한 특성입니다 .
펠릭스 클링

25

length속성은 가장 높은 할당 된 "인덱스"보다 높은 숫자 1을 반환합니다. 여기서 배열 "인덱스"는 0보다 크거나 같은 정수입니다. JS는 "희소"배열을 허용합니다.

var someArray = [];
someArray[10] = "whatever";
console.log(someArray.length); // "11"

물론 어떤 요소는 존재하지 않는 경우 length이다 0. 또한 가장 높은 요소를 제거하는 데 length사용 delete하는 경우 업데이트되지 않습니다 .

그러나 배열은 객체이므로 음수 또는 분수를 포함한 다른 임의의 속성 이름으로 속성을 할당 할 수 있습니다.

someArray[-1] = "A property";
someArray[3.1415] = "Vaguely Pi";
someArray["test"] = "Whatever";

뒤에서 JS는 .NET과 같은 숫자를 제공하더라도 속성 이름을 문자열로 변환합니다 -1. (양의 정수 인덱스도 문자열이됩니다.)

배열 방법은 같은 .pop(), .slice()등이 아닌 다른 속성에 제로 또는-높은 정수 "인덱스",에서만 작업은, 그래서 length그 점에서 일치한다.


귀하의 답변이 많은 도움을 주셔서 감사합니다. 또한 음수 인덱스로 splice 방법을 시도해 보았는데 -1을 사용하면 배열의 마지막 요소로 이동하고 -2는 두 번째 마지막 요소로 이동하는 식으로 계속됨을 발견했습니다.
me_digvijay nov.

+1. 길이는 얼마나 많은 요소가 있는지 또는 얼마나 많은 속성이 있는지 알려주지 않습니다. 그것은 단지 가장 높은 인덱스 + 1입니다. 예를 들어 주어진 var a = new Array(9), a길이가 9이고 요소가 전혀 없습니다.
RobG

1
@DigvijayYadav-예, Array.slice()방법 은 그렇게해야합니다. 이 String.slice()방법 은 같은 일을합니다.
nnnnnn

7

위치 (또는 0) 인덱스를 사용하면 값이 배열 내에 배치됩니다.

var array = [];

array[0] = "Foo";
array[1] = "Bar";

// Result: ["Foo", "Bar"]
// Length: 2

인덱스가 아닌 값 (0-9 + 아님)을 추가하는 경우에는 해당되지 않습니다.

var array = [];

array[0]  = "Foo";
array[1]  = "Bar";
array[-1] = "Fizzbuzz"; // Not a proper array index - kill it

// Result: ["Foo", "Bar"]
// Length: 2

값은 규칙에 따라 플레이 할 때만 배열에 배치됩니다. 그렇지 않으면 수락되지 않습니다. 그러나 JavaScript의 거의 모든 경우에 해당하는 Array 객체 자체에서 허용됩니다. ["Foo", "Bar"]배열에있는 유일한 값 이지만 여전히 액세스 할 수 있습니다 "Fizzbuzz".

array[-1]; // "Fizzbuzz"

그러나 "인덱스"가 유효하지 않기 때문에 이것은 배열 값의 일부가 아닙니다. 대신 다른 구성원으로 배열에 추가되었습니다. 동일한 방식으로 다른 배열 구성원에 액세스 할 수 있습니다.

array["pop"]; // function pop() { [native code] }

여기서 우리는 pop배열 의 메서드에 액세스하고 있으며 이는 여기에 네이티브 코드가 포함되어 있음을 알려줍니다. "pop"키를 사용하여 배열 값에 액세스하는 것이 아니라 배열 개체 자체의 구성원에 액세스합니다. 객체의 공개 멤버를 순환하여 추가로 확인할 수 있습니다.

for (var prop in array) 
    console.log(prop, array[prop]);

다음을 뱉어냅니다.

 0 Foo
 1 Bar
-1 Fizzbuzz

그래서 다시, 그건 객체 있지만, 그렇지 않다 에서 배열 .

멋진 질문입니다! 확실히 더블 테이크를하게 만들었습니다.


1
+1 사양에서도 양의 숫자 속성 이름을 가진 속성을 배열의 요소 라고 합니다 (다른 속성은 아님) : es5.github.com/#x15.4 .
펠릭스 클링

결과는되지 않습니다 : ["Foo", "Bar"]하지만 ["Foo", "Bar", -1: "Fizzbuzz"]확인 여기에 바이올린 . 작성한 것처럼 키가 -1 인 속성이되지만 출력에서 ​​확실히 볼 수 있습니다. 그렇지 않으면 귀하의 대답은 훌륭하고 완전합니다. 변경하면 나는 다시 찬성 할 것이고, 나의 반대표는 가혹했지만 제거 할 수 없습니다. 시간이 만료되었습니다.
Wilt

5

음수 색인 및 기타 색인을 길이에 포함 시키려면 직접 기능을 작성하십시오.

function getExtendedArray() {
    var a = [];

    Object.defineProperty(a, 'totalLength', { 
        get : function() { return Object.keys(a).length; }
    });

    return a;
}

예를 들면 다음과 같습니다.

var myArray = getExtendedArray();
console.log(myArray.totalLength); // 0
myArray.push("asdf");
myArray[-2] = "some string";
myArray[1.7777] = "other string";
console.log(myArray.totalLength); // 3

길이에 번호가 매겨진 인덱스 / 속성 만 포함 하려면 키에 대한 if 문을 추가 할 수 있습니다.- if(Number(key) != NaN) length++;부동 항목을 필터링 && key % 1 == 0하려면 조건에 추가 하십시오
Bonnev

4

배열 은 JS에서 특별한 종류의 객체 입니다. 우리가 효과적으로 작업 할 수 있기 때문에 좋은 특수 구문이 있습니다. 그런 식으로 배열 리터럴을 작성하는 것이 얼마나 지루할 것인지 상상해보십시오.

const array = {0: 'foo', 1: 'bar', 2: 'baz'} //etc...

그러나 그들은 여전히 객체입니다 그럼에도 불구하고. 따라서 다음과 같이하면됩니다.

const myArray = [42, 'foo', 'bar', 'baz'];

myArray[-1] = 'I am not here';
myArray['whatever'] = 'Hello World';

이러한 정수가 아닌 속성은 객체 (배열이 있음)에 연결되지만 Array.length.

네이티브 'length'메소드는 모든 속성을 계산하는 getter라고 가정 할 수 있습니다 (그리고 인덱스 속성이고 값은 실제 값임 ). 양의 정수 또는 0으로 변환 할 수 있습니다. 이 의사 구현과 같은 것 :

specs 로 인해 네이티브 length메서드 ( 게터 ( exampleArray.length))는 '2 32 ' 미만의 모든 '음수가 아닌 정수 '키를 확인하고 가장 큰 값을 가져와 숫자 값 + 1을 반환합니다.

setter ( exampleArray.length = 42) 로서 주어진 길이가 음이 아닌 정수 키의 실제 수보다 큰 경우 '누락 된'인덱스에 대해 빈 슬롯을 생성하거나, 음이 아닌 정수 키 (및 해당 값)를 주어진 길이.

의사 구현 :

const myArray = {
  '-1': 'I am not here', // I have to use apostrophes to avoid syntax error
  0: 42,
  1: 'foo',
  2: 'bar',
  3: 'baz',
  whatever: 'Hello World',

  get myLength() {
    let highestIndex = -1;
    for (let key in this) {
      let toInt = parseInt(key, 10);
      if (!Number.isNaN(toInt) && toInt > -1) {
        // If you're not an integer, that's not your business! Back off!
        if (toInt > highestIndex) highestIndex = toInt;
      }
    }
    return highestIndex + 1;
  },
  set myLength(newLength) {
    /* This setter would either:
      1) create some empty slots for 'missing' indices if the given length is greater than the actual number of non-negative-integer keys
      2) delete all non-negative-integer keys (and their values) which are not greater then the given length.
    */
  }
}

console.log(myArray.myLength); // 4

myArray[9] = 'foobar';

console.log(myArray.myLength); // 10


3

JavaScript의 배열은 실제로 객체입니다. 그들은 단순히 Array 생성자에서 프로토 타입을 만듭니다.

배열 인덱스는 실제로 해시 맵의 키이며 모든 키는 문자열로 변환됩니다. 모든 키 (예 : "-1")를 만들 수 있지만 Array의 메서드는 배열처럼 작동하도록 조정됩니다. 따라서 length객체의 크기가 아니라 가장 큰 정수 인덱스보다 더 큰 것이 보장됩니다. 마찬가지로 인쇄 arr는 정수 키가> = 0 인 값만 나열합니다.

여기에 더 많은 정보가 있습니다.


바로 그거죠. 또는 우리는 왜 array [ 'foo']가 유효한 색인이 아닌지 궁금해 할 수 있습니다. 자바 스크립트를 사용하면 할 수 있지만 배열 (및 해당 요소)의 정의가 한 언어에서 다른 언어로 변경된다는 의미는 아닙니다. 의도 한대로 작동합니다.
tw airball

사실 "배열"은 JS에 존재하지 않습니다. 그러나 "객체"라고도하는 "연관 배열"은 JS의 핵심입니다. 따라서 일반 배열을 모방하는 Array 객체를 만드는 것은 큰 도약이 아닙니다.
Tony R

1
배열과 일반 객체 사이에는 매우 특별한 차이점이 하나 있습니다. 바로 자체 조정 길이 속성입니다.
RobG

1

MDN에 따르면 :

길이 속성의 값은 양의 부호가있는 정수이고 2의 32 제곱 (232)보다 작은 값입니다.

Javascript에서는 생성 한 모든 객체에 속성을 설정할 수 있습니다.

var array = new Array();
array = [1,2,3];
array["boom"] = "pow";

마찬가지로 음수 인덱스를 설정하면 인덱스의 일부가 아닌 배열의 속성으로 저장됩니다.

array[-1] = "property does not add to array length";

이것이 길이가 그것을 반영하지 않는 이유이지만 for..in 루프가 그것을 보여줍니다.


-1

양수가 아니거나 숫자가 아닌 인덱스를 사용하면 배열이 키-값 쌍이있는 연관 배열로 작동합니다.

배열을 반복하려면 다음을 사용할 수 있습니다.

for(var index in myArray) {
  document.write( index + " : " + myArray[index] + "<br />");
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.