Dart e JavaScript: descubra as diferenças

Dart e JavaScript: descubra as diferenças
Victor Costa Santos
Victor Costa Santos

Compartilhe

Se você já mergulhou no mundo da programação, certamente já se deparou com a comparação entre linguagens de programação, especialmente quando se trata de Dart e JavaScript.

Escrever código que seja fácil de ler e adaptar pode ser complicado, certo? Como pessoa desenvolvedora, é importante entender como diferentes linguagens lidam com aspectos básicos, como sintaxe, tipagem e estruturas de controle.

Dart e JavaScript, embora populares, têm maneiras diferentes de fazer as coisas. Neste artigo, vamos explorar essas diferenças, comparando desde a declaração de variáveis até o uso de funções de ordem superior.

Pronto para descobrir qual dessas linguagens combina melhor com o seu próximo projeto? Vamos lá!

Sintaxe e tipagem

Tipagem

Quando falamos de tipagem, estamos falando das regras que definem como os dados são manipulados e como as operações são realizadas em uma linguagem de programação, seja para armazenar valores, realizar operações ou interagir entre si.

Dart: o Dart é uma linguagem fortemente tipada, o que significa que o tipo de cada variável é verificado de forma rigorosa durante a compilação. Isso aumenta a robustez e segurança, pois ajuda a prevenir erros de tipo antes mesmo que o código seja executado.

JavaScript: já o JavaScript não se preocupa com tipagem forte. Ele foca na flexibilidade, permitindo que as variáveis mudem de tipo conforme necessário.

Isso significa que uma variável que começa como um número pode, de repente, virar uma string, e o JavaScript tentará fazer a conversão automática. Porém, essas conversões podem ser difíceis de entender e causar surpresas se você não estiver atento. .

Declaração de variáveis

Quando falamos de variáveis, o Dart tem uma boa variedade de opções: começando com int para números inteiros, double para números com casas decimais, String para texto, e bool para valores verdadeiros ou falsos.

Se você não quiser se preocupar tanto com o tipo específico, também pode usar var, que permite que o Dart faça a inferência do tipo com base no valor inicial atribuído. Exemplo de declarações:


// Números inteiros
int idade = 30;

// Números com casas decimais
double altura = 1.75;

// Texto
String nome = "João";
String cidade = 'São Paulo'; // Aspas simples ou duplas são válidas

// Booleanos
bool estaChovendo = true;
bool estaFrio = false;

// Usando var (inferência de tipo)
var numeroFavorito = 7; // O compilador infere/”entende” que é um int
var mensagem = "Olá, mundo!"; // O compilador infere que é uma String

JavaScript: no mundo do JavaScript, as variáveis são mais dinâmicas. Você tem três opções para declarar variáveis: var, let e const.

O var é o veterano do grupo, com escopo global. Já o let funciona de maneira semelhante ao var, mas com a vantagem de ter escopo de bloco, ou seja, a variável só existe dentro do bloco de código onde foi declarada.

Isso torna o let uma escolha mais segura e previsível para variáveis que podem mudar. E para valores que você quer manter constantes, como o valor do PI, o const é a melhor opção.

Para entender melhor as diferenças entre var, let e const, recomendo dar uma olhada neste artigo da Alura.

Exemplo de código

// Usando var
var idade = 25;

idade = "25 anos de idade" // a troca do tipo não causa nenhum erro durante a execução

// Usando let
let nome = "Victor";

nome = 42 // a troca do tipo não causa nenhum erro durante a execução

// Usando const
const PI = 3.14159;

// Tentando mudar uma constante (gera erro)
PI = 3.14; // Erro: Assignment to constant variable.

Funções

Quando se trata de declarar e utilizar funções, Dart e JavaScript têm abordagens diferentes, mas ambos oferecem bastante flexibilidade.

Dart: no Dart, as funções seguem uma estrutura tradicional, onde você define o tipo de retorno, o nome da função e os parâmetros com seus tipos.

No entanto, a tipagem explícita dos parâmetros de entrada e do retorno não é obrigatória. Se você não declarar os tipos, o Dart usará a inferência de tipo para determinar automaticamente. Isso reforça a ideia de linguagem fortemente tipada.

No entanto, é uma boa prática declarar os tipos explicitamente, como no exemplo abaixo usando int a e int b.

JavaScript:em JavaScript, as funções podem ser declaradas de várias maneiras. A forma mais comum é com function, onde você define o nome e os parâmetros da função. Mas se você quiser algo mais enxuto, as arrow functions são uma alternativa prática e direta.

No entanto, é importante considerar o contexto em que serão utilizadas, pois o this em uma arrow function é fixo, sempre apontando para o contexto onde ela foi definida, e não onde é executada.

Portanto, priorize o uso de arrow functions quando precisar garantir que o this mantenha o mesmo valor no momento da execução. Recomendo a leitura do artigo conhecendo Arrow Functions que explica mais sobre essas diferenças, deixo tambem um exemplo de código utilizando as duas formas de declarar funções.

// Usando function de forma tradicional
function somar(a, b) {
  return a + b;
}
console.log(somar(3, 5)); // 8

// Versão com arrow function
const somarArrow = (a, b) => a + b;
console.log(somarArrow(3, 5)); // 8

Estruturas de controle

Quando falamos de estruturas de controle, Dart e JavaScript tem uma sintaxe bastante semelhante, mas com algumas particularidades que vale a pena destacar, acompanhe comigo.

if e else

Ambas as linguagens utilizam if e else para executar código com base em condições. Se a condições for verdadeira, uma ação é executada.

A sintaxe é quase idêntica nas duas linguagens, facilitando a compreensão, como mostro abaixo:

Dart:

int numero = 10;

if (numero > 0) {
  print('Número positivo');
} else {
  print('Número negativo ou zero');
}

JavaScript:

let numero = 10;
if (numero > 0) {
  console.log('Número positivo');
} else {
  console.log('Número negativo ou zero');
}

for

O for é usado para repetir blocos de código com base em uma condição. Em Dart, é necessário declarar explicitamente o tipo dos dados, enquanto em JavaScript, o tipo é inferido automaticamente.

Dart

JavaScript:

const array = [1, 2, 3, 4];

for (let value of array) {
console.log(value);
} //saida 1 2 3 4

while

O laço while continua repetindo enquanto a condição for verdadeira. A implementação em Dart e JavaScript é bastante similar, como você pode ver a seguir.

Dart:

int contador = 0;
while (contador < 5) {
  print(contador);
  contador++;
}

JavaScript:

let contador = 0;
while (contador < 5) {
  console.log(contador);
  contador++;
}

switch

O switch permite lidar com múltiplas condições de forma organizada, testando diferentes casos e executando uma ação se a condição for atendida.

Em ambas as linguagens, Dart e JavaScript, o switch funciona de maneira bem semelhante.

Dart:

String cor = 'vermelho';
switch (cor) {
  case 'vermelho':
    print('A cor é vermelho');
    break;
  case 'azul':
    print('A cor é azul');
    break;
  default:
    print('Cor não reconhecida');
}

JavaScript:

let cor = 'vermelho';
switch (cor) {
  case 'vermelho':
    console.log('A cor é vermelho');
    break;
  case 'azul':
    console.log('A cor é azul');
    break;
  default:
    console.log('Cor não reconhecida');
}

Ambas as linguagens oferecem uma sintaxe familiar para quem já está acostumado com essas estruturas de controle.

A principal diferença está nos detalhes de implementação e na flexibilidade que cada linguagem oferece, especialmente em termos de tipagem e escopo.

Classes e orientação a objetos

Você já parou para pensar em como a gente pode modelar o mundo real em um código? É aí que entra a famosa programação orientada a objetos POO! Esse estilo de programação ajuda a gente a organizar o código de um jeito que faz sentido e é super próximo do que vemos na vida real.

Com a POO, não só deixamos nosso código mais arrumado, e alinhado com essa ideia de codificar algo no mundo real, mas também criamos modelos de código, que podemos reutilizar em outras partes do nosso projeto — ou até em projetos futuros, quem sabe!

Dart

Agora, deixa eu te contar sobre o Dart. Esse é um exemplo perfeito de linguagem que abraça a orientação a objetos com força total.

Dart foi criado já pensando em POO desde o início, o que faz com que o jeito de organizar e reutilizar código nessa linguagem seja bem natural, quase intuitivo.

Herança simples: imagine que você tem uma classe com tudo que precisa, mas quer fazer algumas melhorias ou adaptações. Com a herança simples, você pode criar uma nova classe baseada em uma já existente. Assim, você aproveita o que já foi feito e ainda tem liberdade para acrescentar ou mudar o que quiser. Tipo pegar um carro de corrida e turbinar do seu jeito!

Mixins: às vezes você quer que várias classes compartilhem funcionalidades sem complicar as coisas com herança múltipla (que, a propósito, o Dart não curte muito). É aí que os mixins entram em cena! Eles permitem que você “misture” funcionalidades em várias classes diferentes, sem precisar que uma classe herde diretamente da outra. É como se você pudesse colocar o poder de voar em diferentes super-heróis sem que eles sejam da mesma família.

Interfaces: e tem também as interfaces, que são tipo contratos que as classes têm que seguir. Quando você cria uma interface, está basicamente dizendo: “qualquer classe que seguir esse contrato precisa ter esses métodos aqui”. É uma maneira de garantir que diferentes classes falem a mesma língua, mesmo que cada uma tenha sua maneira única de fazer as coisas.

Para deixar tudo isso mais claro, se liga nesse exemplo de código:

Então, no exemplo acima, você vai encontrar duas classes: Animal e Cachorro. A classe Animal é a base, com uma propriedade nome e um método chamado emitirSom(), que faz o básico: imprime “Som de animal”. Isso funciona como um modelo genérico para qualquer animal.

Já a classe Cachorro herda tudo de Animal, mas com uma diferença importante: a gente sobrescreve o método emitirSom() para que, em vez de emitir um som genérico de animal, ele imprima “Latido”.

É como se você estivesse dizendo: “Beleza, todo cachorro é um animal, mas eles não fazem qualquer som — eles latem!”.

Na função main(), é onde você vê tudo isso funcionando. Primeiro, criamos um objeto Cachorro chamado meuCachorro com o nome “Melzinha”. Aí, quando pedimos pra imprimir o nome, você vai ver “Melzinha” aparecer.

E quando chamamos emitirSom() no meuCachorro, o Dart sabe que ele precisa usar a versão do método que foi sobrescrita na classe Cachorro, então o resultado é “Latido”.

Assim, você viu como a herança e a sobrescrita de métodos funcionam em Dart. Você começa com uma estrutura básica (como Animal), e depois pode construir em cima dela, adaptando e personalizando conforme necessário (como fizemos com Cachorro). Agora, é só praticar e experimentar com suas próprias classes!

JavaScript

Assim como no Dart, onde exploramos a orientação a objetos com herança, mixins e interface, o JavaScript também adota esse paradigma, mas com algumas diferenças que são interessantes de se conhecer.

No JavaScript, a herança é gerida através da cadeia de protótipos. Em JavaScript, cada objeto tem um protótipo, que é um objeto do qual ele herda métodos e propriedades.

Isso significa que, quando você acessa uma propriedade ou método de um objeto, o JavaScript verifica primeiro se o objeto tem essa propriedade ou método.

Se não tiver, ele procura no protótipo do objeto e continua subindo na cadeia de protótipos, até encontrar o que está procurando ou até chegar ao final da cadeia.

Com a introdução das classes no ES6, a sintaxe para herança ficou mais familiar e intuitiva.

Usando a palavra-chave extends, você pode criar uma classe que herda de outra. Isso torna a herança mais simples de entender e usar, embora o conceito subjacente de protótipos continue sendo o mesmo.

Um exemplo para analisarmos:

class Animal {
  constructor(nome) {
    this.nome = nome;
  }

  emitirSom() {
    console.log("Som de animal");
  }
}

class Cachorro extends Animal {
  emitirSom() {
    console.log("Latido");
  }
}

Nesse trecho de código, temos duas classes em JavaScript: Animal e Cachorro. A classe Animal funciona como uma base geral, com uma propriedade nome e um método emitirSom(), que exibe "Som de animal".

Essa classe serve como um modelo genérico para qualquer tipo de animal que possamos criar, gato, pássaro, e por aí vai.

Ainda sobre o código, a classe Cachorro é uma extensão da classe Animal. Ao definir Cachorro como extends Animal, estamos dizendo que Cachorro herda tudo o que Animal tem, mas com a possibilidade de adicionar ou modificar comportamentos. Depois, sobrescrevemos o método emitirSom() para que, em vez de emitir o som genérico de animal, o Cachorro exiba "Latido".

É como se dissessemos: "Todo cachorro é um animal, mas ele tem um som específico que é o latido!", com essa lógica abrimos uma série de oportunidades para diversas situações.

Embora as classes tornem a programação orientada a objetos mais acessível e fácil de entender, a herança em JavaScript ainda se baseia em protótipos.

As classes ajudam a organizar o código de maneira mais clara, mas por trás das cenas, a herança funciona através da cadeia de protótipos. Se quiser entender mais sobre como isso funciona, dê uma olhada no artigo: Prototype: descubra como quase tudo no JavaScript é um Objeto.

Manipulação de dados

Quando falamos em manipular coleções de dados, uma tarefa comum em qualquer linguagem de programação, tanto Dart quanto JavaScript oferecem diferentes ferramentas para lidar com isso, desde listas e mapas até arrays e objetos.

Dart oferece três tipos principais de coleções: listas, mapas, e conjuntos.

As listas são semelhantes aos arrays do próprio JavaScript, e de outras linguagens e são usadas por padrão para armazenar elementos em uma sequência ordenada.

Exemplo de lista em Dart:

List<String> frutas = ['maçã', 'uva', 'laranja'];
print(frutas[0]);  // Saída: maçã

Os mapas em Dart funcionam como dicionários, permitindo armazenar pares de chave-valor, onde a chave é única.

Exemplo de mapa em Dart:

Map<String, int> estoque = {
  'maçã': 10,
  'uva': 5,
  'laranja': 3,
};
print(estoque['uva']);  // Saída: 5

Já os conjuntos são coleções de elementos únicos, úteis quando você precisa garantir que não tenha nenhum item duplicado.

Exemplo de conjunto em Dart:

Set<int> numeros = {1, 2, 3, 4, 4};
print(numeros.length);  // Saída: 4

Arrays e objetos em JavaScript

No JavaScript, as coleções de dados são gerenciadas principalmente através de arrays e objetos.

Os arrays são semelhantes às listas do Dart, armazenando elementos em uma sequência ordenada.

Exemplo de array em JavaScript:

let frutas = ['maçã', 'banana', 'laranja'];
console.log(frutas[0]);  // Saída: maçã

Os objetos funcionam de forma bem semelhante com os mapas de Dart.

Exemplo de objeto em JavaScript:

let estoque = {
  'maçã': 10,
  'uva': 5,
  'laranja': 3
};
console.log(estoque['uva']);  // Saída: 5

Resumindo, seja para organizar uma lista de frutas ou qualquer outra coisa, tanto Dart quanto JavaScript oferecem o que você precisa.

No Dart, você tem coleções dedicadas como listas, mapas e conjuntos. Já no JavaScript, os arrays e objetos dão conta do recado. No final das contas, apesar das diferenças, a forma como manipulamos os dados é muito parecida.

Funções de ordem superior

Funções de ordem superior são aquelas que podem receber outras funções como argumentos ou retornar uma função como resultado.

Elas são úteis porque permitem criar código que pode ser reutilizado em diferentes situações. Em Dart e JavaScript, algumas das funções de ordem superior mais comuns são map, filter e reduce. Vamos ver como a sintaxe funciona em cada uma delas:

map

O map é o amigo que transforma cada item de uma lista ou array em algo novo, mantendo o mesmo tamanho. Por exemplo: imagine que você queira dobrar todos os números de uma coleção:

  • Dart:

    List<int> numeros = [1, 2, 3, 4, 5];
    var dobrados = numeros.map((n) => n * 2).toList();
    print(dobrados);  // Saída: [2, 4, 6, 8, 10]
  • JavaScript:

    let numeros = [1, 2, 3, 4, 5];
    let dobrados = numeros.map(n => n * 2);
    console.log(dobrados);  // Saída: [2, 4, 6, 8, 10]

filter

Com o filter, você escolhe o que quer manter na lista ou array. Digamos que você queira apenas os números pares:

  • Dart:

    var pares = [1, 2, 3, 4, 5].where((n) => n % 2 == 0).toList();
    print(pares);  // Saída: [2, 4]
  • JavaScript:

    let pares = [1, 2, 3, 4, 5].filter(n => n % 2 === 0);
    console.log(pares);  // Saída: [2, 4]

reduce

O reduce pega tudo o que tem em uma lista ou array e resume em um único valor. Suponhamos que queremos somar todos os números:

  • Dart:

    var soma = [1, 2, 3, 4, 5].reduce((a, b) => a + b);
    print(soma);  // Saída: 15
  • JavaScript:

    let soma = [1, 2, 3, 4, 5].reduce((a, b) => a + b, 0);
    console.log(soma);  // Saída: 15
    Banner da Escola de Mobile: Matricula-se na escola de Mobile. Junte-se a uma comunidade de mais de 500 mil estudantes. Na Alura você tem acesso a todos os cursos em uma única assinatura; tem novos lançamentos a cada semana; desafios práticos. Clique e saiba mais!

    Ambientes de execução e ferramentas

Quando se trata de onde e como você pode usar Dart e JavaScript, cada linguagem tem seu próprio universo de possibilidades.

Dart

Dart é conhecido principalmente por seu papel no desenvolvimento de aplicativos móveis, graças ao Flutter. Com Flutter, você pode criar aplicativos nativos para Android e iOS a partir de um único código-base, o que reduz o trabalho repetido e permite focar em outros objetivos, como escalabilidade da aplicação.

Essa flexibilidade fez com que Dart fosse adotado por grandes empresas, como Nubank; iFood; Alibaba; Ebay dentre outras.

Além disso, Dart pode ser compilado para JavaScript, permitindo a criação de aplicações web. Essa habilidade de trabalhar em diferentes plataformas faz do Dart uma opção prática.

JavaScript

JavaScript, por sua vez, é a linguagem veterana no desenvolvimento web. Ela é a responsável por dar vida às páginas, sendo executada diretamente nos navegadores. Se você já interagiu com uma página da web dinâmica, JavaScript estava por trás disso.

Em outras palavras, quando você navega pela internet, o JavaScript está sempre presente.

Mas não para por aí, com Node.js, JavaScript pode ser executado no lado do servidor, permitindo que você crie desde simples APIs até sistemas complexos, tudo usando a mesma linguagem que você já conhece do front-end.

Resumindo, enquanto Dart é uma boa escolha para desenvolver aplicativos móveis com Flutter e pode ser convertido para JavaScript na web, JavaScript é a base das páginas da web e também pode ser usado no servidor com Node.js. Sua popularidade e acessibilidade são indiscutíveis.

Pacotes e gerenciamento de dependências

À medida que seus projetos vão ganhando escala, não tem como escapar é inevitável que você precise de bibliotecas e ferramentas adicionais para facilitar o desenvolvimento, ser contrário a isso não é uma boa medida já que elas ajudam e muito no desenvolvimento.

É aí que entram os sistemas de gerenciamento de pacotes. Tanto Dart quanto JavaScript têm seus próprios métodos para lidar com isso, e cada um tem suas particularidades.

Dart

Em Dart (dardo em inglês) temos o Pub, o gerenciador de pacotes do Dart. Mas porque "Pub"?

A palavra "pub" em inglês se refere a um bar ou pub mesmo, num contexto inglês são lugares onde as pessoas se reúnem para socializar e compartilhar ideias ou jogar o famoso jogo de “dardo” (Dart).

Pensando por esse ângulo, o Pub no Dart é como um ponto de encontro para pessoas desenvolvedoras, onde eles podem encontrar e compartilhar pacotes para seus projetos.

Assim como em um pub, a comunidade Dart é bastante ativa e colaborativa, sempre contribuindo para o desenvolvimento de novos pacotes e ferramentas.

JavaScript

Para JavaScript, o cenário é um pouco mais amplo. Aqui, você tem duas grandes opções: npm) e Yarn, além do pnpm .

O npm (Node Package Manager) é o mais antigo. Ele já vem integrado com o Node.js e é o “start” para a maioria dos pessoas desenvolvedoras. Com o npm, é possível instalar facilmente bibliotecas, gerenciar dependências e automatizar tarefas, o que o torna um verdadeiro canivete suíço para pessoas desenvolvedoras JavaScript. Sua vasta comunidade e a enorme quantidade de pacotes disponíveis no registro npm são alguns dos motivos de sua popularidade.

Também temos o Yarn, que trouxe algumas melhorias que o tornaram popular entre as pessoas desenvolvedoras. Ele se destaca pela sua rapidez e segurança na instalação de pacotes.

Além disso, o Yarn lida com dependências de forma cuidadosa, garantindo que todos os pacotes sejam instalados de maneira consistente, sem surpresas no meio do caminho.

Se você quiser se aprofundar e entender mais sobre as diferenças entre esses dois gerenciadores de pacotes do universo JS, vale a pena conferir o artigo sobre NPM vs Yarn.

Aparecendo como uma terceira via aos já conhecidos gerenciadores, o PNPM (Performant NPM) se destaca principalmente pela sua abordagem que utiliza um sistema de armazenamento em cache centralizado.

Que em vez de duplicar pacotes em cada projeto, ele armazena uma única cópia de cada pacote em um repositório global, criando links diretos para esses pacotes nos diretórios dos projetos.

Isso não só economiza espaço em disco, mas também melhora a velocidade de instalação, pois evita a necessidade de baixar e instalar pacotes repetidamente, sendo esses pontos de destaque para ele.

Conclusão

Chegamos ao final da nossa jornada entre linguagens de Peso-Pesado, Dart e JavaScript!

Ao longo deste artigo, exploramos as principais diferenças entre essas duas linguagens, abordando temas como tipagem, sintaxe, e estruturas de controle.

Vimos como Dart, com sua tipagem forte, oferece um ambiente mais seguro e previsível, enquanto o JavaScript se destaca pela flexibilidade e dinamismo.

Também mergulhamos nos ambientes de execução e ferramentas, mostrando que tanto o Pub quanto o npm e o Yarn têm muito a oferecer para facilitar a vida das pessoas desenvolvedoras.

No fim das contas, ambos têm seus pontos fortes, e a escolha entre eles depende das necessidades específicas do seu projeto.

De forma geral, foi uma disputa acirrada, mas não se preocupe, no mundo da programação, a linguagem que vence é a que melhor atende aos seus objetivos ou às necessidades do seu projeto.

Foi ótimo ter você conosco nessa exploração! Esperamos que esse guia tenha esclarecido as principais diferenças entre as linguagens.

Se você quiser mergulhar ainda mais fundo, que tal conhecer a formação de Dart e a formação de JavaScript aqui da Alura?

Com essas formações, você aprenderá desde a instalação à construção de projetos reais com essas ferramentas. Te espero lá. Abraços e até a próxima!

Victor Costa Santos
Victor Costa Santos

Olá, sou o Victor, estudante de jogos digitas pela FIAP, sou um entusiasta da tecnologia e apaixonado pela suas possibilidades, adoro ler e me informar sobre o que se passa no mundo, Jogar é claro, e ver filmes e séries que trazem reflexão sobre o seu eu, acredito que a tecnologia é o melhor meio para democratizar a educação e fazendo parte do Fórum da Escola Semente aqui na própria alura, eu acabo ajudando um pouco nessa transformação.

Veja outros artigos sobre Mobile