Programming

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

procodes 2020. 5. 13. 20:53
반응형

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


빈 배열은 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??");

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

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


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

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

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

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


라인에 관하여 :

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)가 String이고 Type (y)가 Number이면 비교 결과를 ToNumber (x) == y로 리턴하십시오.

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

0 == 0

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

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

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

간단히 :

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

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으로 변환됩니다. 단일 요소를 가진 배열은 한 요소와 동일한 문자열로 변환됩니다. 배열에 단일 숫자가 포함 된 경우 해당 숫자는 문자열로 변환 된 다음 숫자로 다시 변환됩니다.

The second type of answer to the "why" question, other than "because the spec says", gives some explanation for why the behavior makes sense from the design perspective. On this issue I can only speculate. First, how would one convert an array to a number? The only sensible possibility I can think of would be to convert an empty array to 0 and any non-empty array to 1. But as Wayne's answer revealed, an empty array will get converted to 0 for many types of comparisons anyway. Beyond this, it's hard to think of a sensible primitive return value for Array.valueOf(). So one could argue that it just makes more sense to have Array.valueOf() be the default and return the Array itself, leading toString() to be the result used by ToPrimitive. It just makes more sense to convert an Array to a string, rather than a number.

Moreover, as hinted by the Flanagan quote, this design decision does enable certain types of beneficial behaviors. For instance:

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

This behavior allows you to compare a single-element array to numbers and get the expected result.


In if (arr), it is always evaluated (ToBoolean) to true if arr is an object because all objects in JavaScript are truthy. (null is not an object!)

[] == false is evaluated in iterative approach. At first, if one side of == is primitive and the other is object, it converts object to primitive at first, then converts both sides to Number if both sides are not string (string comparison is used if both sides are strings). So the comparison is iterated like, [] == false -> '' == false -> 0 == 0 -> true.


Example:

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

It happens because

ToNumber(ToPrimitive([])) == ToNumber(false)  
  1. [] is empty Array object → ToPrimitive([]) → "" → ToNumber("")0
  2. ToNumber(false) → 0
  3. 0 == 0 → true

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

You can empty a JavaScript Array by referencing it to a new array, using list = [] or deleting the elements of the currently referenced array list.length = 0.

Source: JavaScript Empty Array


None of the above helped me, when trying to use the knockout.js mapping plugin, perhaps since an "empty array" isn't really empty.

I ended up using: data-bind="if: arr().length" which did the trick.

This is specific to knockout, not the OP's question, but maybe it will help someone else browsing here in a similar situation.

참고URL : https://stackoverflow.com/questions/5491605/empty-arrays-seem-to-equal-true-and-false-at-the-same-time

반응형