빈 배열은 동시에 참과 거짓으로 보입니다.


201

빈 배열은 true이지만 false와 같습니다.

var arr = [];
console.log('Array:', arr);
if (arr) console.log("It's true!");
if (arr == false) console.log("It's false!");
if (arr && arr == false) console.log("...what??");

나는 이것이 평등 연산자에 의해 운영되는 암시 적 변환 때문이라고 생각합니다.

누구나 무대 뒤에서 무슨 일이 일어나고 있는지 설명 할 수 있습니까?


1
다음은이 문제에 도움이 되거해야 비슷한 스레드는 다음과 같습니다 stackoverflow.com/questions/4226101/...은
리온 윌리엄스

2
참고 arr == true;-) true로 평가하지 않습니다
마이클 Krelin - 해커

5
와우 .. 네가이 모든 것을 가지고 있다고 생각했을 때.
harpo

3
Javascript 유형 강제 WTF를 피하려면 엄격한 동등성 opeartor를 사용하십시오 ===. 그런 다음 배열의 공허함을 테스트하려면arr === []
DjebbZ

17
배열의 공허함을 테스트하려면을 사용하지 마십시오 arr === []. 오른쪽이 새 배열을 인스턴스화하고 왼쪽의 변수가 방금 만든 것을 참조 할 수 없으므로 항상 false를 반환합니다. 테스트 공허함은 찾아보아야합니다 arr.length === 0.
Kyle Baker

답변:


274

여기서 다른 것을 테스트하고 있습니다.

if (arr) 객체에서 호출 (배열은 JS의 Object 인스턴스) 객체가 있는지 확인하고 true / false를 반환합니다.

호출 if (arr == false)하면 이 객체의 값 과 기본 값 을 비교 합니다false . 내부적으로 arr.toString()가 호출되어 빈 문자열을 반환합니다 "".

이것은 toStringArray에서 호출 되기 때문에 Array.join()빈 문자열은 JavaScript에서 잘못된 값 중 하나입니다.


2
Boolean([])반품 을 설명 할 수 있습니까 true?
Devy

11
JS에서는 객체가 부울로 강제 변환되면 항상 TRUE로 강제 변환됩니다. "부울 컨텍스트"테이블을보십시오 : javascript.info/tutorial/object-conversion
Niki

2
@Devy JavaScript의 모든 객체는 진실이므로 모든 객체를 부울로 변환하는 것은 true입니다. 참조 2ality.com/2013/08/objects-truthy.html
톰슨

62

라인에 대하여 :

if (arr == false) console.log("It's false!");

아마도 이것들이 도움이 될 것입니다 :

console.log(0 == false) // true
console.log([] == 0) // true
console.log([] == "") // true

내가 믿는 것은 부울 false0객체 (왼쪽)와 비교 하기 위해 강제된다는 것 입니다. 개체가 문자열 (빈 문자열)로 강제 변환됩니다. 그런 다음 빈 문자열은 숫자, 즉 0으로 강제됩니다. 최종 비교는 0== 0입니다 true.

편집 : 작동 방식에 대한 자세한 내용 은 사양의이 섹션을 참조하십시오 .

규칙 # 1에서 시작하는 상황은 다음과 같습니다.

1. Type (x)가 Type (y)와 다른 경우 14 단계로 이동하십시오.

적용되는 다음 규칙은 # 19입니다.

19. Type (y)가 부울 인 경우 비교 결과 x == ToNumber (y)를 반환합니다.

의 결과 ToNumber(false)입니다 0우리가 지금 가지고, 그래서 :

[] == 0

다시 한 번, 규칙 # 1은 14 단계로 넘어가라고 지시하지만 실제로 적용되는 다음 단계는 # 21입니다.

21. Type (x)가 Object이고 Type (y)가 String 또는 Number 인 경우 비교 결과를 ToPrimitive (x) == y로 반환하십시오.

결과 ToPrimitive([])는 빈 문자열이므로 이제 다음과 같습니다.

"" == 0

다시 한 번, 규칙 # 1은 14 단계로 넘어가라고 지시하지만 실제로 적용되는 다음 단계는 # 17입니다.

17. Type (x)가 문자열이고 Type (y)가 숫자 인 경우 비교 결과를 ToNumber (x) == y로 리턴하십시오.

의 결과 ToNumber("")IS 0우리를 잎 :

0 == 0

이제 두 값의 유형이 같으므로 1 단계에서 7 단계까지 계속됩니다.

7. x가 y와 같은 숫자 값이면 true를 반환합니다.

그래서 우리는 돌아온다 true.

간단히 :

ToNumber(ToPrimitive([])) == ToNumber(false)

2
훌륭한 참조! 혼동을 피하기 위해 규칙 # 1이 "14 단계로 이동"이라고 표시하더라도 "다음 적용 규칙이 # 19"인 이유는 14-18 단계가 유형의 유형과 일치하지 않기 때문입니다. 비교되는 가치.
숀 더 빈

2
좋은 설명입니다. 빈 배열은 진실한 것으로 간주되고 0은 거짓이지만 아직은 [] == 0사실입니다. 나는 스펙에 대한 설명을 바탕으로 이것이 어떻게 일어나는지 알지만 논리적 인 관점에서 이상한 언어 행동처럼 보입니다.
bigh_29

7

Wayne의 답변 을 보충 하고 왜 ToPrimitive([])return 을 설명하려고 ""한다면 'why'질문에 대한 두 가지 가능한 유형의 답변을 고려해 볼 가치가 있습니다. 첫 번째 유형의 답변은 "사양에서 이것이 JavaScript가 작동하는 방식"이라고 말했기 때문입니다. ES5 스펙, 섹션 9.1 에서 ToPrimitive의 결과를 오브젝트의 기본값으로 설명합니다.

객체의 기본값은 객체의 [[DefaultValue]] 내부 메소드를 호출하여 선택적 힌트 PreferredType을 전달하여 검색됩니다.

8.12.8 절[[DefaultValue]]방법이 설명되어 있습니다. 이 메소드는 "힌트"를 인수로 사용하며 힌트는 문자열 또는 숫자 일 수 있습니다. 힌트가 String 인 경우 세부 정보를 제공하여 문제를 단순화하기 위해 힌트가 존재 [[DefaultValue]]하는 toString()경우 값을 반환하고 기본 값을 반환하고 그렇지 않으면 값을 반환합니다 valueOf(). 힌트가 Number 인 경우 우선 순위 toString()valueOf()반대가 우선 순위를 가지 므로 valueOf()먼저 호출되고 기본 요소 인 경우 해당 값이 리턴됩니다. 따라서 여부 [[DefaultValue]]복귀의 결과 toString()또는 valueOf()개체에 대해 지정된 PreferredType에 의존하는지 여부를이 함수 프리미티브 값을 반환한다.

기본 valueOf()Object 메서드는 객체 자체 만 반환하므로 클래스가 기본 메서드를 재정의하지 않으면 valueOf()Object 자체 만 반환됩니다. 의 경우입니다 Array. [].valueOf()객체 []자체를 반환합니다 . Array객체는 프리미티브가 아니기 때문에 [[DefaultValue]]힌트는 관련이 없습니다. 배열의 반환 값은의 값이 toString()됩니다.

인용 데이비드 플래너의 자바 스크립트 : 확실한 가이드 그런데, 이러한 유형의 질문에 대한 답을 얻기 위해 모든 사람의 첫 번째 장소를해야 훌륭한 책이다 :

이 객체 대 숫자 변환의 세부 사항은 빈 배열이 숫자 0으로 변환되는 이유와 단일 요소가있는 배열이 숫자로 변환되는 이유를 설명합니다. 배열은 기본 값이 아닌 객체를 반환하는 defaultValueOf () 메서드를 상속하므로 배열에서 숫자로의 변환은 toString () 메서드를 사용합니다. 빈 배열은 빈 문자열로 변환됩니다. 빈 문자열은 숫자 0으로 변환됩니다. 단일 요소를 가진 배열은 한 요소와 동일한 문자열로 변환됩니다. 배열에 단일 숫자가 포함 된 경우 해당 숫자는 문자열로 변환 된 다음 숫자로 다시 변환됩니다.

"사양이 말했기 때문에"이외의 "왜"질문에 대한 두 번째 유형의 답변은 왜 디자인 관점에서 동작이 의미가 있는지에 대한 설명을 제공합니다. 이 문제에 대해서는 추측 만 할 수 있습니다. 먼저 배열을 숫자로 변환하는 방법은 무엇입니까? 내가 생각할 수있는 유일한 가능성은 빈 배열을 0으로, 비어 있지 않은 배열을 1로 변환하는 것입니다. 그러나 Wayne의 답변이 밝힌 것처럼 빈 배열은 여러 유형의 비교를 위해 0으로 변환됩니다. 이 외에도 Array.valueOf ()에 대한 합리적인 기본 반환 값을 생각하기가 어렵습니다. 따라서 Array.valueOf()기본값이되고 Array 자체를 반환하는 것이 더 합리적이라고 주장 할 수 toString()있으며 ToPrimitive가 사용하는 결과가됩니다. 배열을 숫자가 아닌 문자열로 변환하는 것이 더 합리적입니다.

또한, Flanagan 인용에서 알 수 있듯이,이 디자인 결정은 특정 유형의 유익한 행동을 가능하게합니다. 예를 들어 :

var a = [17], b = 17, c=1;
console.log(a==b);      // <= true
console.log(a==c);      // <= false

이 동작을 통해 단일 요소 배열을 숫자와 비교하고 예상 결과를 얻을 수 있습니다.


이 답변에 감사드립니다.이 질문에 대한 자세한 설명입니다.
Estus Flask

3
console.log('-- types: undefined, boolean, number, string, object --');
console.log(typeof undefined);  // undefined
console.log(typeof null);       // object
console.log(typeof NaN);        // number
console.log(typeof false);      // boolean
console.log(typeof 0);          // number
console.log(typeof "");         // string
console.log(typeof []);         // object
console.log(typeof {});         // object

console.log('-- Different values: NotExist, Falsy, NaN, [], {} --');
console.log('-- 1. NotExist values: undefined, null have same value --');
console.log(undefined == null); // true

console.log('-- 2. Falsy values: false, 0, "" have same value --');
console.log(false == 0);        // true
console.log(false == "");       // true
console.log(0 == "");           // true

console.log('-- 3. !NotExist, !Falsy, and !NaN return true --');
console.log(!undefined);        // true
console.log(!null);             // true

console.log(!false);            // true
console.log(!"");               // true
console.log(!0);                // true

console.log(!NaN);              // true

console.log('-- 4. [] is not falsy, but [] == false because [].toString() returns "" --');
console.log(false == []);       // true
console.log([].toString());     // ""

console.log(![]);               // false

console.log('-- 5. {} is not falsy, and {} != false, because {}.toString() returns "[object Object]" --');
console.log(false == {});       // false
console.log({}.toString());     // [object Object]

console.log(!{});               // false

console.log('-- Comparing --');
console.log('-- 1. string will be converted to number or NaN when comparing with a number, and "" will be converted to 0 --');
console.log(12 < "2");          // false
console.log("12" < "2");        // true
console.log("" < 2);            // true

console.log('-- 2. NaN can not be compared with any value, even if NaN itself, always return false --');
console.log(NaN == NaN);        // false

console.log(NaN == null);       // false
console.log(NaN == undefined);  // false
console.log(0 <= NaN);          // false
console.log(0 >= NaN);          // false
console.log(undefined <= NaN);  // false
console.log(undefined >= NaN);  // false
console.log(null <= NaN);       // false
console.log(null >= NaN);       // false

console.log(2 <= "2a");         // false, since "2a" is converted to NaN
console.log(2 >= "2a");         // false, since "2a" is converted to NaN

console.log('-- 3. undefined can only == null and == undefined, and can not do any other comparing even if <= undefined --');
console.log(undefined == null);         // true
console.log(undefined == undefined);    // true

console.log(undefined == "");           // false
console.log(undefined == false);        // false
console.log(undefined <= undefined);    // false
console.log(undefined <= null);         // false
console.log(undefined >= null);         // false
console.log(0 <= undefined);            // false
console.log(0 >= undefined);            // false

console.log('-- 4. null will be converted to "" when <, >, <=, >= comparing --');
console.log(12 <= null);        // false
console.log(12 >= null);        // true
console.log("12" <= null);      // false
console.log("12" >= null);      // true

console.log(0 == null);         // false
console.log("" == null);        // false

console.log('-- 5. object, including {}, [], will be call toString() when comparing --');
console.log(12 < {});           // false, since {}.toString() is "[object Object]", and then converted to NaN
console.log(12 > {});           // false, since {}.toString() is "[object Object]", and then converted to NaN
console.log("[a" < {});         // true, since {}.toString() is "[object Object]"
console.log("[a" > {});         // false, since {}.toString() is "[object Object]"
console.log(12 < []);           // false, since {}.toString() is "", and then converted to 0
console.log(12 > []);           // true, since {}.toString() is "", and then converted to 0
console.log("[a" < []);         // false, since {}.toString() is ""
console.log("[a" > []);         // true, since {}.toString() is ""

console.log('-- 6. According to 4 and 5, we can get below weird result: --');
console.log(null < []);         // false
console.log(null > []);         // false
console.log(null == []);        // false
console.log(null <= []);        // true
console.log(null >= []);        // true

2

if (arr) 에서 JavaScript의 모든 객체 가 true이므로 arr이 객체 인 경우 항상 (ToBoolean) true로 평가 됩니다. (null은 객체가 아닙니다!)

[] == false반복적 인 접근 방식으로 평가됩니다. 처음에 한쪽 ==이 프리미티브이고 다른 쪽이 객체 인 경우 처음에는 오브젝트를 프리미티브로 변환 한 다음 양쪽이 아닌 경우 양쪽을 숫자로 변환합니다 string(양쪽이 문자열 인 경우 문자열 비교가 사용됨). 따라서 비교는 [] == false-> '' == false-> 0 == 0-> 와 같이 반복 true됩니다.


2

예:

const array = []
const boolValueOfArray = !!array // true

발생하기 때문에

ToNumber(ToPrimitive([])) == ToNumber(false)  
  1. []Array개체입니다 → ToPrimitive([])→ ""→ ToNumber("")0
  2. ToNumber(false) → 0
  3. 0 == 0 → 참

1

요소가있는 배열 (0, false 또는 다른 빈 배열에 관계없이)은 항상 true추상 같음 비교 를 사용하여 확인 ==됩니다.

1. [] == false; // true, because an empty array has nothing to be truthy about
2. [2] == false; // false because it has at least 1 item
3. [false] == false; // also false because false is still an item
4. [[]] == false; // false, empty array is still an item

그러나 Strict Equality Comparison을 사용 ===하면 변수의 내용과 데이터 유형을 평가하려고합니다. 그 이유는 다음과 같습니다.

1. [] === false; // false, because an array (regardless of empty or not) is not strictly comparable to boolean `false`
2. [] === true; // false, same as above, cannot strictly compare [] to boolean `true`
3. [[]] === false; // true, because see #1

-1

list = []현재 참조 된 배열의 요소를 사용 하거나 삭제 하여 새 배열을 참조하여 JavaScript 배열을 비울 수 있습니다 list.length = 0.

출처 : JavaScript Empty Array


-2

knockout.js 매핑 플러그인을 사용하려고 할 때 위의 어느 것도 도움이되지 않았습니다. 아마도 "빈 배열"이 실제로 비어 있지 않기 때문일 것입니다.

나는 data-bind="if: arr().length"속임수를 쓰는 것을 사용 했다.

이것은 OP의 질문이 아닌 녹아웃에만 해당되지만 비슷한 상황에서 다른 사람이 여기를 탐색하는 데 도움이 될 수 있습니다.


이 답변은 관련이 없습니다
fauverism

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