Has Javascript changed its rules about what is false or true?

Asked

Viewed 229 times

7

It occurred to me in the part about booleans, the following problem.

I have this variable:

var name = "10kg" / 10;

if (name) {
  console.log(name);
} else {
  console.log("Not exist");
}

The same should return to me: Not Exist, on the console. However, it appears as NaN (Not a Number).

I just read the documentation in Firefox and it says that if it is 0, -0, null, NaN, underfined, this has to return me false, or as I have determined Not Exist, but in that case they will return the results in the else.

Did I write the wrong code? Did the rule change? Or did I not correctly interpret the documentation?

Because in class it was done this way and appeared on the console the desired result.

  • 2

    The curious thing is that if you test this code in Nodejs this code returns Not exist and if you test it on Deno it does not compile with error error: TS2362 [ERROR]: The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type.
let name = "10kg" / 10; with the "10kg" unbridled.

  • This is really with the colleague explained, they are traps, and the beginners (here tbm include me), fall into it and have no idea what happened. Very strange.

3 answers

12


Rules of programming languages can not change, the whole world depends on them stable, would break everything that people did.

Well, in fact they even change when there was a serious error in the language, or we’re talking about PHP that doesn’t mind breaking a lot of stuff and letting everyone else in. But I don’t even know if this is bad because they improve several mistakes that the language had. Of course, there’s a very bad side.

Javascript is a language full of bad rules. Almost all language problems are related to poorly defined rules.

Dynamic typing against the DOM

In the specific case there are errors because of weak typing which is something a language should not have, this causes several problems, and there is error because of the poorly done implementation of the DOM in the browser.

Let’s change the code to see what’s going on:

var name = "10kg" / 10;
console.log(typeof name);
if (name) console.log(name);
else console.log("Not exist");

I put in the Github for future reference.

Note that the variable name is the type string. So since a number is kind of string? Unlike the pattern we learned that JS has dynamic typing, DOM object variables are not dynamic typing and if you put a value of a different type than you expect there yes the language implicitly converts the value to the variable type.

I put in the Github for future reference.

Weak typing

Then there is another weak typing error. When a text can be completely converted to number it is, and it should not happen. But when you have a part that is text, the conversion does not occur, and then instead of generating a valid value generates an Nan.

Then comes another weak typing error. When using a value in a place that expects a boolean it uses the automatic conversion rule to get the expected value, and a string with any text is true. A rule is very clear on that, just one string empty is false (which is another weird rule). There is a text, it is not empty. This should be prohibited in any decent language, but it is not in JS.

Three automatic conversions that should not have been made caused confusion. And in general people do not understand or do not know about them. Just because it’s not intuitive shouldn’t be allowed.

What you have to do?

  • Never use a value that is not specifically of the type you want. Do not split with a string and do not use a value that is not a boolean where one expects a value like if for example. If you always remember this JS will be a much better experience for you.
  • Never use DOM variable names unless they are treated as local. I already explain

Done like this you don’t even need the if because it deals with a programming error, and programming errors must be fixed and not checked running, can not be treated as something valid, even if the language allows.

Fiat 147 todo detonado andando pelas ruas

Although this case didn’t even work with the expected outcome.

Works perfectly (but is not yet certain):

var name = 10 / 10;
if (name) console.log(name);
else console.log("Not exist");

I put in the Github for future reference.

Even better to create a boolean the right way:

var name = 10 / 10;
if (name != 0) console.log(name);
else console.log("Not exist");

I put in the Github for future reference.

Inappropriate variable name

A numeric variable called name creates confusion (even if it were nome because names are not numbers). And then we see the Javascript problem (in the browser). Let’s change the name:

var x = "10kg" / 10;
console.log(typeof x);
if (x) console.log(x);
else console.log("Not exist");

I put in the Github for future reference.

Note that changing the variable name is another behavior. The conversion is not done and happens as expected. In fact it has a conversion, but it is done after.

name is not actually a local variable, it is the DOM variable whose full name is window.name and you can’t have your type changed.

You can use the name ensure that you are using a local variable:

let name = "10kg" / 10;
console.log(typeof name);
if (name) console.log(name);
else console.log("Not exist");

I put in the Github for future reference.

So in Node/Deno it can happen differently (see comment above), which is another crazy of the entire ecosystem. But nothing strange because all web technology was poorly thought out.

Completion

And that’s one more reason I can say that dynamic typing is wrong in most scenarios, it’s not just weak typing that’s bad at all. Even in scripts which I thought was right, is wrong because they are often used embedded in other applications that do not have dynamic typing and creates an impedance, and then all of this happens.

Javascript should not allow automated conversions that cause confusion. Even in the case of DOM that cannot have dynamic typing, the solution should be to give an error of execution when trying to change the type of the variable and not make a senseless conversion. Violates the typing style, but does not generate a false result.

  • Thank you very much, I found very good your explanation I will write this down, not to forget. Vlu even.

10

This is no problem in your logic. This is a Javascript trap.

In your browser’s Javascript, when you declare a variable in the global scope, it becomes a property of the object window.

As well as other html elements like head, body, div, etc, the object window also has a property called name. That property name but it has a Setter, and this Setter will transform any value you assign to it into a string, because by default, the property name of an element can only store strings.

How you used a variable called name in its global scope, you are actually storing the value of NaN on the property name of window, which means that NaN is being converted into a string 'NaN', and as you may know, a non-empty string is treated as a true condition.

Take the test.

Using name:

var name = "10kg" / 10;

if (typeof name === 'string') {
  console.log('name é uma string')
}

if (name) {
  console.log('e como name é uma string não vazia, ela é verdadeira')
}

Using any other name:

var result = "10kg" / 10;

if (typeof result === 'string') {
  console.log('name é uma string')
} else {
  console.log('result NÃO é uma string')
}

if (result) {
  console.log('e como result é uma string não vazia, ela é verdadeira')
} else {
  console.log('result é de fato NaN, e portanto, é uma condição falsa')
}

  • Thank you very much támbem, very accurate information, I did not know these details, I will note down támbem not to forget and use in my code.

9

That nay is a Javascript trap, actually is a "Javascript trap in browsers"

When you use name in the main scope it will understand that refers to the window.name, which by default already comes set as an empty string, the value of "10kg" / 10 will be NaN, as the property Window.name only accepts string it will make an automatic "cast" for string, making the value in "NaN", so that’s why it happens name.length function, if you happen to use any other variable name that does not exist in the main scope in window.{...} an error will occur, since it will not convert to string:

var foobar = "10kg" / 10;

console.log("variável foobar:", foobar);
console.log("typeof foobar:", typeof foobar);

var name = "10kg" / 10;

console.log("variável name:", name);
console.log("typeof name:", typeof name);

See that the variable foobar returned Number (even if Nan means not to be a number, it is still part of that interface and so the typeof returns like this).

Any other property "writable", for example, if you do var location = "10kg" / 10; in the main scope you will make the page redirect to an address like http://localhost/NaN:

Resultado no navegador

That is, the properties of the object Window can have various behaviors.

Note that a similar situation in browsers occurs with element Ids in HTML pages:

Elements with id="..." are available as window.

In Node.js

In the code:

var name = "10kg" / 10;

console.log("variável name:", name);
console.log("typeof name:", typeof name);

the result will be:

C:\Users\user>node index.js
variável name: NaN
typeof name: number

That is to say, nay is even a problem with Javascript and yes with certain decisions that initial implementations of Javascript (Netscape/Mozilla), Jscript (Internet Explorer), among others (time of the first browser war)those decisions are likely to stand for reasons of backward compatibility.

Using let (or const)

As already explained in What is the difference between variable declaration using Let and var?, the behavior of let is different from var, note how nay the problem occurs:

let name = "10kg" / 10;

console.log("variável name:", name);
console.log("typeof name:", typeof name);

The same will happen with const, will not access properties of window.

However note that certain properties may be configurable (non-configurable), whether or not with let will not solve, causing error:

Syntaxerror: redeclaration of non-configurable global Property Location

let location = "10kg" / 10;

console.log("variável location:", location);
console.log("typeof location:", typeof location);

Therefore a better way out to avoid certain accidents is to isolate the scope, such as with IIFE or use let in a block ({...}) (see the following examples).

Using IIFE (Immediately Invoked Function Expression)

Before we had the let there was already a "technique" to avoid the main scope, which also helps prevent other unrelated scripts from conflicting in the main scope, thus:

(function () {
    var name = "10kg" / 10;
    var location = "10kg" / 10;

    console.log("variável name:", name);
    console.log("typeof name:", typeof name);

    console.log("variável location:", location);
    console.log("typeof location:", typeof location);
})();

Of course, that’s not the same thing as let, I’m just quoting as a means of isolating the scope, in these answers some answers talk more about it:

Answers of the site on the subject:

Using block and let

If you want to run scripts only in modern browsers without worrying about backward compatibility, then you can combine block ({...}) with let, may set variables without affecting the overall scope

{
    let name = "10kg" / 10;
    let location = "10kg" / 10;

    console.log("variável name:", name);
    console.log("typeof name:", typeof name);

    console.log("variável location:", location);
    console.log("typeof location:", typeof location);
}

This example will work in Internet Explorer 11, but will not work in previous ones like IE8, IE9 and IE10.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.