DLabs.AI 2024年11月26日
JavaScript Is Weird. And That’s Why We Love It.
index_new5.html
../../../zaker_core/zaker_tpl_static/wap/tpl_guoji1.html

 

本文探讨了JavaScript中一些奇特的现象及原理,包括typeof NaN、数值运算的限制、类型转换等方面,帮助读者更好地理解这门语言。

typeof NaN的结果为number,NaN是试图成为数字但失败的情况

JavaScript使用IEEE 754标准的浮点数,超过Number.MAX_SAFE_INTEGER和Number.MIN_SAFE_INTEGER的计算可能不准确

在二进制中数字的书写方式导致0.2 + 0.1!== 0.3等奇特现象,可通过合理设置小数位数解决

JS的动态类型机制和‘duck typing’,如数组与其他类型的运算结果可能出人意料

According to the 2021 Stack Overflow Developer Survey, JavaScript is the most widely used technology among professionals and amateurs alike.

Some 61.51% of developers love the coding language. But that still leaves some 40% of programmers who prefer to stay away. So why is that? Well, there’s a fair degree of weirdness about JS, which could be one explanation.

Just check the example below:

 

 

In this article, we’ll run through why some JavaScript actions work the way they do (as opposed to how you might expect).

No hanging around, let’s get stuck in!

The oddities of Numbers vs Not a Number

Let’s start by looking at typeof NaN.

Many people ask why the entry to this operation is number. You can read a lot about this topic in the specifications, which state what numbers mean in JS:

‘Number type set of all possible Number values including the special “Not-a-Number” (NaN) value, positive infinity, and negative infinity’

But what exactly is “Not-a-Number”? In simple terms, NaN is something that tries to be a number — but fails.

An example could be something that:

And there are several more cases where the result cannot be determined by the actual numbers in the range supported by JS.

 

9999999999999999 === 10000000000000000

 

Once again, the result seems odd — so where does this bizarreness come from? The answer is similar to the previous case.

JavaScript uses floating-point numbers written using the IEEE 754 standard, which (like every number standard) has its limitations. In essence, when you pass a certain limit, natural numbers (integers) are no longer exact. You may now be asking, “So, is there a way to check this border?” 

Again, the standard JS library gives two constants within which we can safely perform calculations.

 

Number.MAX_SAFE_INTEGER < 9999999999999999
Number.MIN_SAFE_INTEGER > -9999999999999999

 

In the example, you can see that going beyond them isn’t a great idea if you want accurate calculations.

 

0.2 + 0.1 !== 0.3 but 0.5 + 0.1 === 0.6

 

Here’s another quirk of JavaScript that seems super weird. But in actual fact, this is not so much the fault of the language. It’s more a problem with how numbers are written in binary. Fortunately, there is a way to deal with this. 

You just need to enter results with a reasonable number of decimal places.

 

Math.max() === -Infinity and Math.min() === Infinity

 

This takes us onto the real question: what are these two functions? Their task is to select the largest and smallest number from a given set of numbers as arguments in turn.

What’s wrong with the Object and Array?

 

[] + [] === “”

 

And you guessed it — now we enter even more weirdness. If you recall your first JavaScript course, tutorial, or book, we bet it said something like ‘JS is a dynamically typed language’. But what does that mean in practice? 

In short, it means we shouldn’t worry about the type of variable. We should only assign a value to it, then let the JS engine determine the type we are dealing with.

 

let a = 124;
let b = 'meow';
typeof a // number
typeof b // string

 

How does JS do this? By using something called the “duck typing” mechanism. The following quote paints a nice picture of how this works:

‘If it looks like a duck and quacks like a duck, it must be a duck.’

OK — nice quote: but how does it relate to the example? 

Well, it just so happens that arrays in JS cannot be added together with the + operator. However, we can combine two text strings this way. Meaning a smart JS engine can project arrays onto empty strings dynamically, then join them together. And the output is an empty string.

 

[] + {} === ‘[Object object]’

 

Again, the result may surprise you. But the principle actually reflects the previous example. As we know, an array cannot be added to something, so it is converted to an empty string. As a result, the object is also converted to a string.

The following example is what the textual representation of an object might look like:

 

 String({})

 

{} + [] === 0

 

OK, if you’ve managed to stick with us until now, you’re doing great. But the next part could be the final straw. Because you might now be wondering, ‘But why is the addition not commutative?’ When, in actual fact, it is! 

Just remember that previously, we did not add. Instead, we combined (concatenated) two strings of characters. ‘So are we adding now?’ you ask. Well, of course not! That would be too easy. This plus sign changes the empty array to a number here.

.

+ '27' // 27
!! 1   // true
'' + 777 // '777'


If you didn’t know the magic of these methods, now you do. And we’re sure you’ll find them helpful to avoid having to write casting functions.

Still, you might feel there’s a little weirdness lurking somewhere. And that’s because we still have this empty object. But, surprise, surprise, JS has tricked you once again! It just so happens that {} is not only used to signify an empty object.

Sometimes, it’s used to declare a block of code. And at this point, the parser treats it as an empty code block that does absolutely nothing. 

Consequently, it’s ignored for this operation.

The truth, the whole truth, but is it really the truth?

 

true + true + true === 3 and true-true === 0

 

As is the case with most programming languages, true is equated with the number 1. Therefore, no one should be surprised that 3 * true gives us 3. And the same goes for `1 – 1 === 0.

 

true == 1 but true !== 1

 

Here, you should understand the difference between the ‘equality’ == and ‘identity’ === operators. The identity operator does not allow implicit type coercion. And as a result, true (which is a boolean type) cannot become 1 (a number).

 

(!+[]+[]+![]).length === 9

 

That might have your head in a bit of spin, so to cheer you up, know that only a few things will ever truly surprise you in programming. But to understand this, you have to break the parenthetical expression into pieces once again.

It will be easier to explain what mechanisms take place here if we consider this expression from the end, so let’s do that:

 

Now we’ve been through much of the weirdness of JavaScript, we hope you’re learning to love it as much as we do. And if you feel we’ve missed something — or if you have a question for the team — feel free to share your thoughts on Twitter or LinkedIn.

 

______

This article was originally published in Polish on my personal blog.

Artykuł JavaScript Is Weird. And That’s Why We Love It. pochodzi z serwisu DLabs.AI.

Fish AI Reader

Fish AI Reader

AI辅助创作,多种专业模板,深度分析,高质量内容生成。从观点提取到深度思考,FishAI为您提供全方位的创作支持。新版本引入自定义参数,让您的创作更加个性化和精准。

FishAI

FishAI

鱼阅,AI 时代的下一个智能信息助手,助你摆脱信息焦虑

联系邮箱 441953276@qq.com

相关标签

JavaScript 数值运算 类型转换 动态类型
相关文章