Executando verificação de segurança...
13

Comportamentos estranhos em JavaScript

Mamãe, não precisa mais trabalhar na fábrica, seu filho triunfou, ele é um gênio!

O Filho: “1” + 1 -> resultado: 11. oxi, era pra ser igual a 2

Quem nunca? kkk

haha, memes a parte, agora vamos entender por que acontece esse tipo de comportamento em JavaScript. Observe os seguintes exemplos de código:

exemplo 1: console.log(“1” - 1) // resultado: 0.

exemplo 2: console.log(“1” - “1”) // resultado: 0.

exemplo 3: console.log(“1” + 1) // resultado: 11. WTF?!

exemplo 4: console.log(“1” - “A”) // resultado: NaN.

Por que os dois primeros exemplos o resultado está correto e nos dois últimos exemplos dão um resultado “errado”?

A linguagem JavaScript é uma linguagem de tipagem dinâmica, isso significa que ela é uma linguagem flexível, a grosso modo, ela tenta fazer por conta própria o melhor que ela pode, para que o nosso programa não “quebre”. Como?

Observe que no exemplo 1, estamos tentando fazer uma subtração com o operador aritmético “-”, em JavaScript, esse operador só tem a função de subtrair, então quando JavaScript ler esse código ela diz: huuum… não tem como eu subtrair o tipo de dado string pelo tipo de dado number, qual o melhor que eu posso fazer nesse caso para que o programa não quebre? Vou tentar converter o valor da string em um number e aí sim fazer a operação. No segundo exemplo a mesma coisa, ela converte o valor das strings em um number e consegue fazer a operação esperada por nós.

Aí você me pergunta:
Ué?! 🤔 e por que nos dois últimos exemplos ela não converteu as strings para number?

Vamos lá, no exemplo 3 estamos tentando fazer uma adição com o operador aritmético “+”, aqui está o bug, em JavaScript, esse operador tem duas funções, adição e concatenação. Lembra que eu disse que JavaScript tenta fazer o melhor que ela pode para não deixar nosso programa quebrar? Então, no exemplo 3 ela diz: huuum… somar o tipo de dado string com o tipo de dado number, não é uma operação válida, acho que o programador está querendo concatenar (juntar) esses valores, vou converter o number em string e fazer a concatenação. Por isso o resultado é 11. Para termos o resultado 2 como gostaríamos, podemos converter a string em um number usando a classe global “Number”, dessa maneira: console.log(Number(“1”) + 1).

Já no último exemplo, como a única função do operador “-” é subtrair, JavaScript vai tentar converter as strings em number para fazer a subtração, o VALOR da string “1” é um number, mas o valor da string “A” não é um number, logo, o resultado dessa conversão será NaN (Not a Number), então a operação final que JavaScript vai tentar será: 1 - NaN, e qualquer operação matemática que tem NaN, resulta em NaN. Espero ter te ajudado a entender por que acontece esse tipo de comportamento em JavaScript.

JavaScript – O guia definitivo

E como eu aprendi isso? Aprendi isso quando li o livro “JavaScript – O guia definitivo por David Flanagan” (recomendo muito)

Conversão de tipos em JS

Carregando publicação patrocinada...
6

A linguagem JavaScript é uma linguagem de tipagem dinâmica, isso significa que ela é uma linguagem flexível, a grosso modo, ela tenta fazer por conta própria o melhor que ela pode, para que o nosso programa não “quebre”.

Tipagem dinâmica só quer dizer que uma variável pode mudar de tipo durante o programa. Por exemplo:

// variável recebe um número
var x = 1;
...
// depois, ela pode mudar para uma string
x = 'abc';

Em linguagens com tipagem estática (como por exemplo C#, Java e C) isso não é possível: uma vez que a variável é declarada como sendo de um tipo, vc não pode mais mudá-lo.


Mas isso não tem a ver com esse comportamento do JavaScript. Python, por exemplo, também tem tipagem dinâmica, mas nenhuma das operações é possível:

# Ao contrário do JavaScript, em Python todas essas operações dão erro

# TypeError: unsupported operand type(s) for -: 'str' and 'int'
print("1" - 1)

# TypeError: unsupported operand type(s) for -: 'str' and 'str'
print("1" - "1")

# TypeError: can only concatenate str (not "int") to str
print("1" + 1)

# TypeError: unsupported operand type(s) for -: 'str' and 'str'
print("1" - "A")

Repare que em todos os casos ocorre um TypeError. No primeiro caso, é porque vc não pode subtrair um número de uma string. No segundo e quarto casos, não é possível subtrair duas strings. E no terceiro caso, ele não deixa concatenar uma string e um número.


A diferença entre JavaScript e Python, portanto, não é no estilo de tipagem (ambas possuem tipagem dinâmica). A diferença é que o JS faz type coercion (coerção de tipos): quando os operandos de um operador não são do mesmo tipo, um deles é convertido e só depois é feita a operação. Já em Python optaram por não fazer essas conversões automáticas, e em vez disso ocorre um erro.

As regras de type coercion do JavaScript são muitas, e bem confusas (e na minha opinião, muitas sequer fazem sentido prático). Daí gera esses casos bizarros, tanto que gerou pérolas como essa.

Enfim, existem várias fontes que documentam essas regras, então vou acrescentar mais uma: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators
Ali tem um bom resumo para cada operador, além de sempre ter um link para a especificação da linguagem (com uma explicação bem mais técnica e detalhada).


Sabendo disso, se vc quer fazer operações aritméticas, o ideal é sempre converter para número antes de fazer os cálculos. Foi sugerido usar Number, mas vc também pode usar parseInt ou parseFloat (caso seja números inteiros ou de ponto flutuante, respectivamente).

Apesar de funcionar da mesma forma para a maioria dos casos, existem algumas diferenças. Por exemplo, se tiver uma string vazia, Number converte para zero, e os demais retornam NaN:

console.log(Number(''));     // 0
console.log(parseInt(''));   // NaN
console.log(parseFloat('')); // NaN

O mesmo ocorre com null. Mas com undefined, todos retornam NaN.

E existem vários outros corner cases:

// parseInt e parseFloat ignoram a parte do texto que não é número
var s = '10 acabates';
console.log(Number(s));     // NaN
console.log(parseInt(s));   // 10
console.log(parseFloat(s)); // 10

// começa com "0x", valor é tratado como hexadecimal, exceto por parseFloat
var s = '0x1f';
console.log(Number(s));     // 31
console.log(parseInt(s));   // 31
console.log(parseFloat(s)); // 0

Além disso, parseInt também permite informar em qual base o valor está:

var s = '101';
// o padrão é base 10
console.log(parseInt(s));      // 101
// em binário
console.log(parseInt(s, 2));   // 5
// base 8
console.log(parseInt(s, 8));   // 65
// hexa
console.log(parseInt(s, 16));  // 257

Enfim, o importante é saber exatamente o que vc precisa, se vai aceitar as conversões automáticas, se tem strings vazias ou valores nulos, e o que fazer em cada caso. E aí escolher a conversão mais adequada antes de fazer os cálculos.

1

você enriqueceu a publicação e complementou com mais conhecimento. Esse é o objetivo da comunidade tabNews, compartilhar conhecimento útil. Obrigado.

1

Eu acho extremamente engraçado esses comportamentos duvidosos kkkk isso quando não zoa nosso projeto todo claro e a gente fica horas procurando algo bobo pra corrigir o_O mas de resto é bem interessanter ver como cada linguagem lida com peculiaridades

1
1

Muito bom. Agora me explica o resultado dessa expressão (se é verdadeiro ou falso), e o pq disso em JS.

Minha resposta honesta, sem perguntar a IA: eu tenho certeza absoluta que é false, mas honestamente não sei explicar tecnicamente o pq, não me lembro.

1
1

Por que os dois primeros exemplos o resultado está correto e nos dois últimos exemplos dão um resultado “errado”?

A linguagem JavaScript é uma linguagem de tipagem dinâmica, isso significa que ela é uma linguagem flexível, a grosso modo, ela tenta fazer por conta própria o melhor que ela pode, para que o nosso programa não “quebre”. Como?

Um detalhe é que isso não é apenas por javascript ter tipagem dinâmica, mas sim por ter tipagem fraca, uma linguagem com tipagem dinâmica mas forte é Lua:

-- exemplo 1:
print("1" - 1) -- resultado: 0.

--exemplo 2: 
print("1" - "1") -- resultado: 0.

-- exemplo 3:
print("1" + 1) // resultado: 2

-- exemplo 4: 
print("1" - "A") // resultado: Erro

E como é que faz 1+1 das 11? você usa concatenação com ..:

-- exemplo 1:
print(1 .. 1) // resultado: 11

Isso de "1"+1 ser 11 é uma falha de desing do javascript que foi percebido tarde demais, então ela não faz "o melhor" ela só foi mal projetada mesmo