preface

For those of you who think javaScript is easy, this line of javaScript code might make you wonder about your life.

(! (~ + []) + {}) [- [~ +""] + [] [] * [~ + []] + ~ ~! + + []] + [] ({}) [[~! + []] * ~ + []]Copy the code

Friends learned, later encounter some unreasonable, let you do not open son of the people will send this code to him.

So why does this code print sb?

In fact, this code test is js type conversion some basic principles

The first knowledge to be used is the priority of THE JS operator, because such a long section of operation to see people dazzling, we must first according to the priority divided into N small sections, and then each break

1. The priority of the JS operator

Priorities are listed as follows:

Priority from high to low:

According to this rule, we divide the string of operations into the following 16 subexpressions:

The operators are highlighted in red. What you may not realize is that the brackets [] are also an operator that accesses an array item by index, and can also access subcharacters of a string, similar to the charAt method: ‘abcd'[1] // returns ‘b’. And the brackets have the highest precedence.

The next step is to use javascript’s knowledge of type conversions. Let’s talk about when type conversions are needed. Type conversions are required when the operand types on either side of the operator are inconsistent or are not primitive (also known as primitive) types.

Let’s go over it quickly. In JavaScript, there are two types of values: Primitives and objects.

  • The primitive values are undefined, null, Booleans, numbers, and strings.
  • All other values are of object type, including arrays and functions.

2. Type conversion

(1) First classify the classes according to the operator:

  • Minus -, times *, is definitely doing math, so the operand needs to be converted to number.

  • Plus plus, it could be string concatenation, it could be math, so it could be a number or a string

  • Unary operations, such as +[], that have only one operand, are converted to number

(2) Let’s look at the transformation rules.

(2).1 For non-primitive types, ToPrimitive() converts the value to the primitive type:

ToPrimitive (input, PreferredType?

The optional parameter PreferredType is a Number or String. The return value is any original value. If the PreferredType is Number, the execution order is as follows:

If input is primitive, return

Otherwise, the input is Object. Call the obj. The valueOf (). If the result is Primitive, go back.

Otherwise, call obj.tostring (). If the result is primitive, return

Otherwise, TypeError is thrown

If the PreferredType is String, step 2 and step 3 are interchangeable. If the PreferredType is not available, the Date instance is set to String and everything else is Number

(2).2 Converts the value to a number by ToNumber()

Convert values to numbers via ToNumber() and look directly at the ECMA 9.3 table

parameter The results of
undefined NaN
null + 0
Boolean value True is converted to 1 and false to +0
digital Without conversion
string Parsing a string to a number. For example,”324″ is converted to 324

If the input value is an object, ToPrimitive(obj, Number) is first called to convert the object to its original value, and ToNumber() is then called to convert the original value to a Number.

(2).3 Converts the value to a string through ToString()

Convert values to strings via ToString(), looking directly at the table in ECMA 9.8

parameter The results of
undefined “undefined”
null “null”
Boolean value “true” 或者 “false”
digital Numbers as strings, for example. “1.765”
string Without conversion

If the input value is an object, ToPrimitive(obj, String) is called first to convert the object to its original value, and ToString() to convert the original value to a String.

So much for the rules, let’s go ahead and execute the magic code step by step based on the subexpression we’ve partitioned above. Start ~

Let’s start with the simplest subexpression 16: +[]

There is only one operand [], which must be converted to number. According to rule 2 above, [] is an array of type object. Call toPrimitive to convert to the original type, and PreferredType to number, which indicates the PreferredType. We then call the valueOf method of the array first, which returns itself as follows:

And you’re done! The subexpression 16 is transformed, +[], and finally 0 is obtained.

Subexpression 15: [~+””]

The empty string “” is preceded by two unary operators, but there is still only one operand, so the final type to be converted to is number. If you look at rule 2, the empty string calls toNumber to get 0. Next up is ~, what is this thing? It’s a bit operator, and its job is to take a number minus and subtract it by one, so ~0 is -1.

Remember, this subexpression is also wrapped in brackets, so the final value is [-1], which is an array with only one element, -1.

[0] –[-1][0] –[-1][0] –[-1][0]

Further up, subexpression 14: [~+[]]

In fact, it is very obvious to apply the principle of 15, and 16. The answer is [-1]

Now it’s a little bit different, but that’s ok. We’re going to do the math, and we’re going to convert the [-1] to a number, like 16.

ToPrimitive: toPrimitive: Object

② Call valueOf to return itself [-1]

③ Because it is not a primitive type, continue to call toString, return “-1”

④”-1″ is the primitive type, then call toNumber and return -1

⑤ Multiply by -2, return 2

Subexpression 10: ~~! +[], without further discussion, answer 1.

With 9 and 10, we come to the subexpression 4, which now looks like this: 2+1. Well, I won’t say much more.

Continuing with expression 7:! (~+[]), ~+[]=-1 What is minus 1? Here to say this exclamation mark, it is logical to take the meaning, the expression into a Boolean type, transformation rules and js Truthy and Falsy principle is the same, followed by a digital, except for the 0 to false, followed by a string of, in addition to the empty string is false. Here! Negative 1 is of course false.

Next, the expression 3: false+{} is somewhat critical. If a Boolean is added to an object, the {} should be converted to the original type as follows:

ToPrimitive: toPrimitive: Object

Call valueOf, return itself {}, call toString, return “[object object]”

(4) Add false to [object object];

⑤ Add result “false[object object]”

Given expressions 3 and 4, we can now look at expression 1, which looks like this: “false[object object]”[3], because this [] can take subcharacters of strings, like charAt, so we get “s”.

After the arduous process above, we get the character “s”, which is the left half of the picture, and the remaining “B”, the same principle can be worked out, I will not demonstrate it here, I leave it to you to practice

Now, it’s not that complicated, it’s just that there are some things that you have to do over and over again, as long as you have a sense of prioritization, you can break up the big strings into the little strings, and then you can use your knowledge of type conversion to do them one by one. What do you think? It’s still amazing to see here?

Similarly, Chinese characters are formed in this way, in the same way as English.

reference

www.cnblogs.com/ziyunfei/ar… Zhidao.baidu.com/question/43…