You might also be able to find a solution fromAI solution orcommunity posts

# BFE.dev solution for JavaScript Quiz 10. Equal

## TL;DR

For `==` it loosly checks equality with rules including:

1. `null` and `undefined` are equal
2. for `string` and `number`, string is converted to `number` first
3. for `bigint` and `string`, string is converted to `bigint` first
4. if either is `boolean`, `boolean` is converted to `number`
5. if either is primitive and the other is Object, convert the Object to primitive first

Above is not a full list, please refer to the detailed spec explanation in the section after this.

``console.log(0 == false)// true// booleans are converted to number first, 0 == 0console.log('' == false)// true// booleans are converted to number first, '' == 0// string vs number, string is converted to number. 0 == 0console.log([] == false)// true// booleans are converted to number first, [] == 0// 0 is primitive, so object(the array) is converted to primitive// there is no preferred type here and [] is converted to '', '' == 0// see details at https://bfe.dev/quiz/Implicit-Conversion-II/solution// again, '' is converted to 0, 0 == 0console.log(undefined == false)// false// booleans are converted to number first, undefined == 0// no cases is defined for `undefined` vs `number`, so falseconsole.log(null == false)// false, same as aboveconsole.log('1' == true)// true// booleans are converted to number first, '1' == 1// string vs number, string is converted to number. 1 == 0console.log(1n == true)// true// booleans are converted to number first, 1n == 1// bigint vs number, they are equal in value, so trueconsole.log(' 1     ' == true)// true// booleans are converted to number first, ' 1     ' == 1// string vs number, string is converted to number. 1 == 1``

## ECMAScript Spec about loosely equal `==`

From ECMAScript spec, loosely equal check works as below.

1. If Type(x) is the same as Type(y), then
1. Return IsStrictlyEqual(x, y).
2. If x is null and y is undefined, return true.
3. If x is undefined and y is null, return true.
4. NOTE: This step is replaced in section B.3.6.2.
5. If x is a Number and y is a String, return ! IsLooselyEqual(x, ! ToNumber(y)).
6. If x is a String and y is a Number, return ! IsLooselyEqual(! ToNumber(x), y).
7. If x is a BigInt and y is a String, then
1. Let n be StringToBigInt(y).
2. If n is undefined, return false.
3. Return ! IsLooselyEqual(x, n).
8. If x is a String and y is a BigInt, return ! IsLooselyEqual(y, x).
9. If x is a Boolean, return ! IsLooselyEqual(! ToNumber(x), y).
10. If y is a Boolean, return ! IsLooselyEqual(x, ! ToNumber(y)).
11. If x is either a String, a Number, a BigInt, or a Symbol and y is an Object, return ! IsLooselyEqual(x, ? ToPrimitive(y)).
12. If x is an Object and y is either a String, a Number, a BigInt, or a Symbol, return ! IsLooselyEqual(? ToPrimitive(x), y).
13. If x is a BigInt and y is a Number, or if x is a Number and y is a BigInt, then
1. If x is not finite or y is not finite, return false.
2. If ℝ(x) = ℝ(y), return true; otherwise return false.
14. Return false.

The steps are pretty straightforward it explains itself.

One thing is about ToPrimitive() though, let's continue.

## ToPrimitive() in ECMAScript Spec

This defines how we get primitive values from any data types, according to the ECMAScript spec:

1. If input is an Object, then
2. Let exoticToPrim be ? GetMethod(input, @@toPrimitive).
3. If exoticToPrim is not undefined, then
1. If preferredType is not present, let hint be "default".
2. Else if preferredType is string, let hint be "string".
3. Else,
1. Assert: preferredType is number.
2. Let hint be "number".
4. Let result be ? Call(exoticToPrim, input, « hint »).
5. If result is not an Object, return result.
6. Throw a TypeError exception.
4. If preferredType is not present, let preferredType be number.
5. Return ? OrdinaryToPrimitive(input, preferredType).
6. Return input.

Here it says, if Symbol.toPrimitive is defined in the object, then the method will be used in ToPrimitive(). This is pretty obvious, below is an example.

``const obj =  {    [Symbol.toPrimitive](hint) {      if (hint === 'number') {        return 100      }      return 'obj'    }  } + obj // 100``

If Symbol.toPrimitive is not defined, the default OrdinaryToPrimitive() is used.

## OrdinaryToPrimitive() in ECMAScript spec

This is the default process before Symbol.toPrimitive is a thing. According to the ECMAScript spec:

1. If hint is string, then
2. Let methodNames be « "toString", "valueOf" ».
3. Else,
4. Let methodNames be « "valueOf", "toString" ».
5. For each element name of methodNames, do
6. Let method be ? Get(O, name).
7. If IsCallable(method) is true, then
8. Let result be ? Call(method, O).
9. If result is not an Object, return result.
10. Throw a TypeError exception.

What it says is basically

1. if needs a string, first `toString()` then `valueOf()` is tried and return the first primitive value;
2. if needs a number, first `valueOf()` then `toString()` is tried and return the first primitive value;

For empty array `[]` in our question

1. there is no Symbol.toPrimitive defined in Array, continue.
2. Array inherits Object.prototype.valueOf() is tried, but it just returns the array itself, not a primitive value, continue
3. Different from Object.prototype.toString(), Array has its own Array.prototype.toString()
1. we can see from the spec that `Array.prototype.join()` is used here.
2. in Array.prototype.join(), it tries to convert all elements to string, which recursively calls Array.prototype.toString().