Skip to content

3. Os fundamentos do JavaScript

Nota: daqui em diante, o termo [Javascript] referir-se-á sempre à norma ECMAScript 6.

Dentro do projeto JavaScript anterior, crie uma pasta [bases]. Colocaremos aí os exemplos desta secção:

Image

3.1. script [bases-01]

Para apresentar os conceitos básicos do PHP7, utilizámos o seguinte código (ver parágrafo com o link):


<?php

// isto é um comentário
// variável utilizada sem ter sido declarada
$nom = "dupont";
// uma exibição no ecrã
print "nom=$nom\n";
// um array com elementos de tipos diferentes
$tableau = array("un", "deux", 3, 4);
// o seu número de elementos
$n = count($tableau);
// um ciclo
for ($i = 0; $i < $n; $i++) {
  print "tableau[$i]=$tableau[$i]\n";
}
// inicialização de duas variáveis com o conteúdo de um tabulero
list($chaine1, $chaine2) = array("chaine1", "chaine2");
// concatenação das duas cadeias
$chaine3 = $chaine1 . $chaine2;
// exibição do resultado
print "[$chaine1,$chaine2,$chaine3]\n";
// utilização de uma função
affiche($chaine1);
// o tipo de uma variável pode ser conhecido
afficheType("n", $n);
afficheType("chaine1", $chaine1);
afficheType("tableau", $tableau);
// o tipo de uma variável pode mudar durante a execução
$n = "a changé";
afficheType("n", $n);
// uma função pode devolver um resultado
$res1 = f1(4);
print "res1=$res1\n";
// uma função pode devolver um tabuleiro de valores
list($res1, $res2, $res3) = f2();
print "(res1,res2,res3)=[$res1,$res2,$res3]\n";
// esses valores poderiam ter sido recuperados numa matriz
$t = f2();
for ($i = 0; $i < count($t); $i++) {
  print "t[$i]=$t[$i]\n";
}
// testes
for ($i = 0; $i < count($t); $i++) {
  // apenas apresenta as cadeias de caracteres
  if (getType($t[$i]) === "string") {
    print "t[$i]=$t[$i]\n";
  }
}
// operadores de comparação == e ===
if("2"==2){
  print "avec l'opérateur ==, la chaîne 2 est égale à l'entier 2\n";
}else{
  print "avec l'opérateur ==, la chaîne 2 n'est pas égale à l'entier 2\n";
}
if("2"===2){
  print "avec l'opérateur ===, la chaîne 2 est égale à l'entier 2\n";
}
else{
  print "avec l'opérateur ===, la chaîne 2 n'est pas égale à l'entier 2\n";
}
// outros testes
for ($i = 0; $i < count($t); $i++) {
  // apenas apresenta os números inteiros >10
  if (getType($t[$i]) === "integer" and $t[$i] > 10) {
    print "t[$i]=$t[$i]\n";
  }
}
// um ciclo while
$t = [8, 5, 0, -2, 3, 4];
$i = 0;
$somme = 0;
while ($i < count($t) and $t[$i] > 0) {
  print "t[$i]=$t[$i]\n";
  $somme += $t[$i];   //$somme=$somme+$t[$i]
  $i++;               //$i=$i+1
}//enquanto
print "somme=$somme\n";

// fim do programa
exit;

//----------------------------------
function affiche($chaine) {
  // exibe $chaine
  print "chaine=$chaine\n";
}

//exibe
//----------------------------------
function afficheType($name, $variable) {
  // exibe o tipo de $variable
  print "type[variable $" . $name . "]=" . getType($variable) . "\n";
}

//afficheType
//----------------------------------
function f1($param) {
  // adiciona 10 a $param
  return $param + 10;
}

//----------------------------------
function f2() {
  // retorna 3 valores
  return array("un", 0, 100);
}
?>

Traduzido para JavaScript, isto resulta no seguinte código:


'use strict';
// isto é um comentário
// constante
const nom = "dupont";
// uma mensagem no ecrã
console.log("nom : ", nom);
// um array com elementos de tipos diferentes
const tableau = ["un", "deux", 3, 4];
// o seu número de elementos
let n = tableau.length;
// um ciclo
for (let i = 0; i < n; i++) {
  console.log("tableau[", i, "] = ", tableau[i]);
}
// inicialização de duas variáveis com o conteúdo de um tabela
let [chaine1, chaine2] = ["chaine1", "chaine2"];
// concatenação das duas cadeias
const chaine3 = chaine1 + chaine2;
// exibição do resultado
console.log([chaine1, chaine2, chaine3]);
// utilização de uma função
affiche(chaine1);
// o tipo de uma variável pode ser conhecido
afficheType("n", n);
afficheType("chaine1", chaine1);
afficheType("tableau", tableau);
// o tipo de uma variável pode mudar durante a execução
n = "a changé";
afficheType("n", n);
// uma função pode devolver um resultado
let res1 = f1(4);
console.log("res1=", res1);
// uma função pode devolver um tabuleiro de valores
let res2, res3;
[res1, res2, res3] = f2();
console.log("(res1,res2,res3)=", [res1, res2, res3]);
// esses valores poderiam ter sido recuperados numa matriz
let t = f2();
for (let i = 0; i < t.length; i++) {
  console.log("t[i]=", t[i]);
}
// testes
for (let i = 0; i < t.length; i++) {
  // apenas apresenta as cadeias de caracteres
  if (typeof (t[i]) === "string") {
    console.log("t[i]=", t[i]);
  }
}
// operadores de comparação == e ===
if ("2" == 2) {
  console.log("avec l'opérateur ==, la chaîne 2 est égale à l'entier 2");
} else {
  console.log("avec l'opérateur ==, la chaîne 2 n'est pas égale à l'entier 2");
}
if ("2" === 2) {
  console.log("avec l'opérateur ===, la chaîne 2 est égale à l'entier 2");
} else {
  console.log("avec l'opérateur ===, la chaîne 2 n'est pas égale à l'entier 2");
}
// outros testes
for (let i = 0; i < t.length; i++) {
  // apenas apresenta os números inteiros >10
  if (typeof (t[i]) === "number" && Math.floor(t[i]) === t[i] && t[i] > 10) {
    console.log("t[i]=", t[i]);
  }
}
// um ciclo while
t = [8, 5, 0, -2, 3, 4];
let i = 0;
let somme = 0;
while (i < t.length && t[i] > 0) {
  console.log("t[i]=", t[i]);
  somme += t[i];
  i++;
}
console.log("somme=", somme);

// o programa termina porque já não há código executável

//exibe
//----------------------------------
function affiche(chaine) {
  // exibe uma cadeia de caracteres
  console.log("chaine=", chaine);
}

//afficheType
//----------------------------------
function afficheType(name, variable) {
  // exibe o tipo de variável
  console.log("type[variable ", name, "]=", typeof (variable));
}

//----------------------------------
function f1(param) {
  // adiciona 10 ao parâmetro
  return param + 10;
}

//----------------------------------
function f2() {
  // retorna 3 valores
  return ["un", 0, 100];
}

Vamos comentar as diferenças entre os códigos PHP e ECMAScript 6 com a declaração [use strict] (linha 1):

  • a primeira diferença é que, em ECMAScript, as variáveis são declaradas com as seguintes palavras-chave:
    • [let] para declarar uma variável cujo valor pode alterar-se durante a execução do código;
    • [const] para declarar uma variável cujo valor não vai mudar (ou seja, uma constante) durante a execução do código;
    • também é possível utilizar a palavra-chave [var] em vez de [let]. Esta era a palavra-chave utilizada com ECMAScript 5. Não a utilizaremos neste curso;
  • linha 6: o método de visualização [console.log] pode apresentar todo o tipo de dados: cadeias de caracteres, números, valores booleanos, tabelas e objetos. O método PHP [print] não consegue apresentar tabelas e objetos de forma nativa. Na expressão [console.log], [console] é um objeto e [log] é um método desse objeto;
  • linha 8: as matrizes JavaScript são objetos referenciados por um ponteiro. Quando se escreve:

const tableau = ["un", "deux", 3, 4];

a variável [tableau] é um ponteiro para a matriz literal ["un", "deux", 3, 4]. Alterar o conteúdo da matriz não altera o seu ponteiro. Por isso, uma matriz será, na maioria das vezes, declarada com a palavra-chave [const]. Em PHP, uma matriz não é referenciada por um ponteiro. Trata-se de um valor literal;

  • linha 12: a variável de ciclo [i] é declarada (let) no ciclo. A palavra-chave [let] respeita o âmbito do bloco (código entre chaves). Assim, a variável [i] da linha 12 só é conhecida dentro do ciclo;
  • linha 18: o operador de concatenação de cadeias de caracteres é o operador + em JavaScript, . em PHP. Uma particularidade deste operador é que tem precedência sobre o operador + de adição. Assim:
    • em PHP, «1» + 2 resulta no número 3;
    • em JavaScript, «1» + 2 resulta na cadeia «12»;
  • linha 20: o [console.log] consegue apresentar tabelas;
  • linha 82: em JavaScript, não é possível indicar o tipo dos parâmetros de uma função;
  • linha 91: o operador [typeof] permite determinar o tipo de um valor. Existem quatro: número, cadeia de caracteres, booleano e objeto. Note-se que, em JavaScript, não existe o tipo [integer] nem o tipo [tableau]. Como já foi referido, as tabelas são manipuladas através de ponteiros e enquadram-se na categoria dos objetos;
  • linhas 50-59: tal como em PHP, o JavaScript tem dois operadores de comparação, == e ‘===’, com o mesmo significado que em PHP. O ESLint sinaliza, na maioria das vezes, o operador == como um possível erro. Deve utilizar-se sistematicamente o operador ‘===’;
  • linha 79: poderíamos ter utilizado a instrução [return], mas ESLint emite o aviso de que [return] só deve ser utilizado numa função;

Vamos executar este código:

Image

Resultados da execução:


[Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe "c:\Temp\19-09-01\javascript\bases\bases-01.js"
nom : dupont
tableau[ 0 ] = un
tableau[ 1 ] = deux
tableau[ 2 ] = 3
tableau[ 3 ] = 4
[ 'chaine1', 'chaine2', 'chaine1chaine2' ]
chaine= chaine1
type[variable n ]= number
type[variable chaine1 ]= string
type[variable tableau ]= object
type[variable n ]= string
res1= 14
(res1,res2,res3)= [ 'un', 0, 100 ]
t[ 0 ]= un
t[ 1 ]= 0
t[ 2 ]= 100
t[ 0 ]= un
avec l'opérateur ==, la chaîne 2 est égale à l'entier 2
avec l'opérateur ===, la chaîne 2 n'est pas égale à l'entier 2
t[ 2 ]= 100
t[ 0 ]= 8
t[ 1 ]= 5
somme= 13

[Done] exited with code=0 in 0.316 seconds

No código escrito, ESLINT assinala dois erros:

Image

  • ao passar o cursor sobre a linha vermelha do aviso, aparece a mensagem de erro [3]. Aqui, ESLint não reconhece que se está a comparar duas constantes. Um dos dois operandos deveria ser uma variável;
  • em [4], uma opção [Quick Fix] permite ignorar o aviso caso se decida não corrigir o erro;

Image

  • em [5], é possível desativar o aviso para a linha atual ou para todo o ficheiro. É esta última opção que escolhemos aqui. A linha [6] é então gerada no início do ficheiro;

3.2. script [bases-02]

O script [bases-02] mostra a utilização das palavras-chave [let] e [const]:


'use strict';
// para inicializar uma variável, utiliza-se «let» ou «const»
// «let» para as variáveis
let x = 4;
x++;
console.log(x);
// const para as constantes
const y = 10;
x += y;
// proibido
y++;
  • a linha 11 provoca um erro na execução do [1-2]. Este erro é sinalizado pelo ESLint antes da execução do [3]:

Image

3.3. script [bases-03]

O script [bases-03] verifica o âmbito das variáveis em JavaScript:


'use strict';
// âmbito das variáveis
let count = 1;
function doSomething() {
  // «count» é aqui conhecido
  console.log("count=",count);
}
// chamada
doSomething();
  • a variável [count], declarada fora da função [doSomething], é, no entanto, reconhecida nessa função. Trata-se de uma diferença fundamental em relação a PHP;

Execução


[Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe "c:\Temp\19-09-01\javascript\bases\bases-03.js"
count= 1

[Done] exited with code=0 in 0.3 seconds

3.4. script [bases-04]

Uma variável local oculta uma variável global com o mesmo nome:


'use strict';
// âmbito das variáveis
const count = 1;
function doSomething() {
  // a variável local oculta a variável global
  const count = 2;
  console.log("count inside function=",count);
}
// variável global
console.log("count outside function=",count);
// variável local
doSomething();

Execução


[Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe "c:\Temp\19-09-01\javascript\bases\bases-04.js"
count outside function= 1
count inside function= 2

[Done] exited with code=0 in 0.246 seconds

3.5. script [bases-05]

Uma variável definida numa função não é reconhecida fora dessa função:


'use strict';
// âmbito das variáveis
function doSomething() {
  // variável local da função
  const count = 2;
  console.log("count inside function=", count);
}
// aqui, «count» não é conhecido
console.log("count outside function=", count);
doSomething();

ESLint declara um erro na linha 9:

Image

3.6. script [bases-06]

As palavras-chave [let] e [const] definem variáveis com âmbito [bloc] (código entre chaves), mas não a palavra-chave [var]:


'use strict';
// a palavra-chave [let] permite definir uma variável com âmbito de bloco
{
  // a variável [count] só é conhecida neste bloco
  let count = 1;
  console.log("count=", count);
}
// aqui, a variável [count] não é reconhecida
count++;

// a palavra-chave [const] permite definir uma variável com âmbito de bloco
{
  // a variável [count2] só é conhecida neste bloco
  const count2 = 1;
  console.log("count=", count2);
}
// aqui, a variável [count2] não é conhecida
count2++;

// a palavra-chave [var] não permite definir uma variável com âmbito de bloco
{
  // a variável [count3] será conhecida globalmente
  var count3 = 1;
  console.log("count=", count3);
}
// aqui, a variável [count3] é conhecida
count3++;

Comentários

  • linha 5: a variável [count] só é conhecida no bloco de código em que é declarada (linhas 3-7);
  • linha 14: a constante [count2] só é conhecida no bloco de código em que é declarada (linhas 12-16);
  • linha 23: a variável [count3] é conhecida fora do bloco de código em que é declarada (linhas 21-25);

ESLint declara os seguintes erros:

Image

Por estas razões relacionadas com o âmbito do bloco, passaremos a utilizar apenas as palavras-chave [let] e [const].

3.7. script [bases-07]

Os tipos de dados em JavaScript:


'use strict';

// tipo de dados jS
const var1 = 10;
const var2 = "abc";
const var3 = true;
const var4 = [1, 2, 3];
const var5 = {
  nom: 'axèle'
};
const var6 = function () {
  return +3;
}
// exibição dos tipos
console.log("typeof(var1)=", typeof (var1));
console.log("typeof(var2)=", typeof (var2));
console.log("typeof(var3)=", typeof (var3));
console.log("typeof(var4)=", typeof (var4));
console.log("typeof(var5)=", typeof (var5));
console.log("typeof(var6)=", typeof (var6));

Execução


[Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe "c:\Temp\19-09-01\javascript\bases\bases-07.js"
typeof(var1)= number
typeof(var2)= string
typeof(var3)= boolean
typeof(var4)= object
typeof(var5)= object
typeof(var6)= function

[Done] exited with code=0 in 0.26 seconds

Comentários

  • linha 7 (código): um array é um objeto. Como tal, [var4] é um ponteiro para o array, não o próprio array;
  • linha 8 (código): [var5] é um ponteiro para um objeto literal. Veremos que os objetos literais do JavaScript são muito semelhantes às instâncias de classe de PHP. Também são referenciados através de ponteiros;
  • linha 11 (código): uma variável pode ser do tipo [fonction] (linha 7 dos resultados);

3.8. script [bases-08]

Este script mostra as possíveis alterações de tipo em JavaScript.


'use strict';

// mudanças implícitas de tipos
// tipo --> bool
console.log("---------------[Conversion implicite vers un booléen]------------------------------");
showBool("abcd");
showBool("");
showBool([1, 2, 3]);
showBool([]);
showBool(null);
showBool(0.0);
showBool(0);
showBool(4.6);
showBool({});
showBool(undefined);

function showBool(data) {
  // a conversão de dados para booleano é feita automaticamente no teste seguinte
  console.log("[data=", data, "], [type(data)]=", typeof (data), "[valeur booléenne(data)]=", data ? true : false);
}

// mudanças implícitas de tipo pa ra um tipo numérico
console.log("---------------[Conversion implicite vers un nombre]------------------------------");
showNumber("12");
showNumber("45.67");
showNumber("abcd");

function showNumber(data) {
  // dados + 1 não funciona porque, nesse caso, o jS realiza uma concatenação de cadeias de caracteres em vez de uma adição
  const nombre = data * 1;
  console.log("[data=", data, "], [type(data)]=", typeof (data), "[nombre]=", nombre, "[type(nombre)]=", typeof (nombre));
}

// mudanças explícitas de tipo para um valor booleano
console.log("---------------[Conversion explicite vers un booléen]------------------------------");
showBool2("abcd");
showBool2("");
showBool2([1, 2, 3]);
showBool2([]);
showBool2(null);
showBool2(0.0);
showBool2(0);
showBool2(4.6);
showBool2({});
showBool2(undefined);

function showBool2(data) {
  // a conversão de «data» para booleano é feita explicitamente no teste que se segue
  console.log("[", data, "], [type(data)]=", typeof (data), "[valeur booléenne(data)]=", Boolean(data));
}
// mudanças explícitas de tipo para Number
console.log("---------------[Conversion explicite vers un nombre]------------------------------");
showNumber2("12.45");
showNumber2(67.8);
showNumber2(true);
showNumber2(null);

function showNumber2(data) {
  const nombre = Number(data);
  console.log("[data=", data, "], [type(data)]=", typeof (data), "[nombre]=", nombre, "[type(nombre)]=", typeof (nombre));
}

// para String
console.log("---------------[Conversion explicite vers un string]------------------------------");
showString(5);
showString(6.7);
showString(false);
showString(null);

function showString(data) {
  const chaîne = String(data);
  console.log("[data=", data, "], [type(data)]=", typeof (data), "[chaîne]=", chaîne, "[type(chaîne)]=", typeof (chaîne));
}

// algumas conversões implícitas inesperadas
console.log("---------------[Autres cas]------------------------------");
const string1 = '1000.78';
// concatenação de cadeias por predefinição
const data1 = string1 + 1.034;
console.log("data1=", data1, "type=", typeof (data1));
const data2 = 1.034 + string1;
console.log("data2=", data2, "type=", typeof (data2));
// conversão explícita para número
const data3 = Number(string1) + 1.034;
console.log("data3=", data3, "type=", typeof (data3));
// true é convertido no número 1
const data4 = true * 1.18;
console.log("data4=", data4, "type=", typeof (data4));
// false é convertido no número 0
const data5 = false * 1.18;
console.log("data5=", data5, "type=", typeof (data5));

Execução


[Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe "c:\Data\st-2019\dev\es6\javascript\bases\bases-08.js"
---------------[Conversion implicite vers un booléen]------------------------------
[data= abcd ], [type(data)]= string [valeur booléenne(data)]= true
[data= ], [type(data)]= string [valeur booléenne(data)]= false
[data= [ 1, 2, 3 ] ], [type(data)]= object [valeur booléenne(data)]= true
[data= [] ], [type(data)]= object [valeur booléenne(data)]= true
[data= null ], [type(data)]= object [valeur booléenne(data)]= false
[data= 0 ], [type(data)]= number [valeur booléenne(data)]= false
[data= 0 ], [type(data)]= number [valeur booléenne(data)]= false
[data= 4.6 ], [type(data)]= number [valeur booléenne(data)]= true
[data= {} ], [type(data)]= object [valeur booléenne(data)]= true
[data= undefined ], [type(data)]= undefined [valeur booléenne(data)]= false
---------------[Conversion implicite vers un nombre]------------------------------
[data= 12 ], [type(data)]= string [nombre]= 12 [type(nombre)]= number
[data= 45.67 ], [type(data)]= string [nombre]= 45.67 [type(nombre)]= number
[data= abcd ], [type(data)]= string [nombre]= NaN [type(nombre)]= number
---------------[Conversion explicite vers un booléen]------------------------------
[ abcd ], [type(data)]= string [valeur booléenne(data)]= true
[ ], [type(data)]= string [valeur booléenne(data)]= false
[ [ 1, 2, 3 ] ], [type(data)]= object [valeur booléenne(data)]= true
[ [] ], [type(data)]= object [valeur booléenne(data)]= true
[ null ], [type(data)]= object [valeur booléenne(data)]= false
[ 0 ], [type(data)]= number [valeur booléenne(data)]= false
[ 0 ], [type(data)]= number [valeur booléenne(data)]= false
[ 4.6 ], [type(data)]= number [valeur booléenne(data)]= true
[ {} ], [type(data)]= object [valeur booléenne(data)]= true
[ undefined ], [type(data)]= undefined [valeur booléenne(data)]= false
---------------[Conversion explicite vers un nombre]------------------------------
[data= 12.45 ], [type(data)]= string [nombre]= 12.45 [type(nombre)]= number
[data= 67.8 ], [type(data)]= number [nombre]= 67.8 [type(nombre)]= number
[data= true ], [type(data)]= boolean [nombre]= 1 [type(nombre)]= number
[data= null ], [type(data)]= object [nombre]= 0 [type(nombre)]= number
---------------[Conversion explicite vers un string]------------------------------
[data= 5 ], [type(data)]= number [chaîne]= 5 [type(chaîne)]= string
[data= 6.7 ], [type(data)]= number [chaîne]= 6.7 [type(chaîne)]= string
[data= false ], [type(data)]= boolean [chaîne]= false [type(chaîne)]= string
[data= null ], [type(data)]= object [chaîne]= null [type(chaîne)]= string
---------------[Autres cas]------------------------------
data1= 1000.781.034 type= string
data2= 1.0341000.78 type= string
data3= 1001.814 type= number
data4= 1.18 type= number
data5= 0 type= number