Comparatif : de Java à JavaScript / TypeScript

Ce guide présente une comparaison de la syntaxe entre Java (8 minimum) et JavaScript (ES6/ES2015 minimum) / TypeScript.

Vous trouverez d’autres guides et une explication plus générale ici.

Pourquoi TypeScript ? En tant que développeur Java, vous allez adorer, et on vous explique pourquoi ici. Ce guide précise clairement quand une fonctionnalité est propre à TypeScript. Tout le reste est du JavaScript standard.

Déclaration des données

En JavaScript, les variables peuvent être déclarées dans l’espace global et les valeurs sont toujours modifiables. Depuis l’ES6, utilisez uniquement l’instruction let.


String myData = "java";
myData = "new"; // Error

view raw

variable.java

hosted with ❤ by GitHub


let myData = 'js';
myData = 'new'; // OK

view raw

variable.js

hosted with ❤ by GitHub

L’ES6 a introduit les constantes en JavaScript. Des valeurs complexes peuvent être utilisées et donc manipulées.


final String MY_DATA = "java";

view raw

final.java

hosted with ❤ by GitHub


const MY_DATA = 'js';
const MY_USER = new User(); // OK
MY_USER.name = 'New name';

view raw

constant.js

hosted with ❤ by GitHub

Types de données simples

En JavaScript natif, le typage des données est dynamique (une variable peut changer de type à n’importe quel moment), et vous n’avez pas besoin de spécifier le type (il est inféré). TypeScript ajoute un typage explicite et statique. Tous les nombres sont de même type en JavaScript.


boolean userMan = true;
int userAge = 81;
float userAverage = 10.5;
String userName = "Henri Bergson";

view raw

types.java

hosted with ❤ by GitHub


let userMan: boolean = true;
let userAge: number = 81;
let userAverage: number = 10.5;
let userName: string = 'Henri Bergson';

view raw

types.ts

hosted with ❤ by GitHub

En plus de null, JavaScript contient le type undefined, et NaN (Not a Number). Ce sont des erreurs, ne les utilisez donc pas.

Détails sur les chaînes de caractères

Vous pouvez utiliser indifféremment les guillemets simples ou doubles pour les chaînes de caractères. L’ES6 a introduit les template literals : de nouveaux guillemets, les backticks, pour l’interpolation des variables et dans lesquels les sauts de ligne sont autorisés. Evitez la concaténation classique en JavaScript, cela porte à confusion avec les additions et peut aboutir à des erreurs de types.


String userFullName = userFirstName + " " + userLastName;


let userFullName: string = `${userFirstName} ${userLastName}`;

C’est aussi pratique pour gérer les guillemets simples et doubles dans une même chaîne.


let HTMLTemplate: string = `<p class="content">My name's Henri !</p>`;

Listes de données

La taille des tableaux est toujours dynamique en JavaScript.


List<String> userBooks = new ArrayList<>();
userBooks.add("Book 1");
userBooks.get(0);
userBooks.size();

view raw

list.java

hosted with ❤ by GitHub


let userBooks: string[] = [`Book 1`, `Book 2`];
userBooks.push(`Book 3`);
userBooks[0];
userBooks.length;

view raw

array.ts

hosted with ❤ by GitHub

Les hash maps sont appelés des objets en JavaScript, avec des index de type chaîne de caractères.


Map<String, String> user = new HashMap<>();
user.put("firstName", "Henri");
user.put("lastName", "Bergson");
user.get("firstName");

view raw

hashmap.java

hosted with ❤ by GitHub


let user = {
firstName: `Henri`,
lastName: `Bergson`
};
user.firstName;

view raw

object.js

hosted with ❤ by GitHub

Comme les objets JavaScript sont comme des instances littérales, TypeScript vous permet d’utiliser les interfaces pour typer les objets.


interface User {
age: number;
name: {
first: string,
last: string
};
}
let user: User = {
age: 81,
name: {
first: `Henri`,
last: `Bergson`
}
};

view raw

interface.ts

hosted with ❤ by GitHub

L’ES6 a introduit de nouveaux types de collections : MapSetWeakMapWeakSet. Vous serez peut-être aussi intéressés par la librairie JavaScript Immutable.

Décomposition

L’ES6 permet de déstructurer les tableaux, c’est-à-dire extraire les valeurs dans différentes variables. Cela n’existe pas sous cette forme en Java.


let myList: number[] = [1, 2, 3];
let [data1, data2, data3] = myList;

Dans le même esprit, l’opérateur spread permet de diffuser les valeurs d’un tableau en plusieurs valeurs successives.


let myOptions: int[] = [1, 2];
function test(option1: int, option2: int): void {}
test(myOptions);
let defaultConfig: string[] = ['data1', 'data2'];
let userConfig: string[] = ['data3', 'data4'];
let finalConfig: string[] = [
defaultConfig,
userConfig
];

view raw

spread.ts

hosted with ❤ by GitHub

On peut aussi décomposer des objets de façon similaire.


let user = {
firstName: `Henri`,
lastName: `Bergson`
};
let { firstName: myName } = user;
myName; // `Henri`

Souvent, vous voudrez créer une variable portant le même nom que la propriété. Auquel cas vous pouvez raccourcir à :


let user = {
firstName: `Henri`,
lastName: `Bergson`
};
let { firstName } = user;
firstName; // `Henri`

Et si la propriété n’existe pas dans l’objet ? Vous pouvez prévoir une valeur par défaut.


let user = {
firstName: `Henri`,
lastName: `Bergson`
};
let { firstName = `default`, age = 0 } = user;
firstName; // `Henri`
age; // 0

Blocs

Même syntaxe pour les conditions.

Depuis l’ES6, grâce à let, la portée des variables est limitée au bloc en cours.


for (int i = 0; i < 10; i++) {}

view raw

loop.java

hosted with ❤ by GitHub


for (var i: number = 0; i < 10; i++) {}
i; // 10, error prone
for (let i: number = 0; i < 10; i++) {}
i; // undefined

view raw

loop.ts

hosted with ❤ by GitHub

Les itérations sont simplifiées en ES6. N’indiquez pas le type de value en TypeScript (il est inféré).


for (String value: userBooks) {}

view raw

iteration.java

hosted with ❤ by GitHub


for (let value of userBooks) {}

view raw

iteration.js

hosted with ❤ by GitHub

Une autre possibilité pour les itérations complexes (avec les valeurs et les index, seulement pour les tableaux).


for (int i = 0; i < books.size(); i++) {
books.get(i);
}

view raw

iteration.java

hosted with ❤ by GitHub


userBooks.forEach((value, index) => {});

view raw

iteration.js

hosted with ❤ by GitHub

Fonctions

En JavaScript, vous avez accès aux portées parentes directement.


String myData = "java";
void myMethod() {
myData; // error
}

view raw

scope.java

hosted with ❤ by GitHub


let myData: string = 'js';
function myMethod(): void {
myData; // 'js'
}

view raw

scope.ts

hosted with ❤ by GitHub

Pas de surcharge en JavaScript (une fonction ne peut avoir qu’une seule signature), et les paramètres sont toujours facultatifs. L’ES6 a introduit les valeurs par défaut. TypeScript permet de rendre automatiquement les paramètres sans valeur par défaut obligatoires (c’est une différence majeure avec du JavaScript natif).


void myMethod(String required) {
myMethod(required, "default");
}
void myMethod(String required, String optional) {}

view raw

params.java

hosted with ❤ by GitHub


function myMethod(required: string, optional: string = 'default'): void {}

view raw

params.ts

hosted with ❤ by GitHub

Vous pouvez aussi avoir un nombre indéfini de paramètres.


void function myArrayPush(int... values) {
for (int i = 0; i < values.length; i++) {
}
myArrayPush(1, 2, 3);

view raw

rest.java

hosted with ❤ by GitHub


function myArrayPush(values: number[]): void {
for (let value of values) {}
}
myArrayPush(1, 2, 3);

view raw

rest.ts

hosted with ❤ by GitHub

Arrow functions

L’ES6 a introduit une syntaxe raccourcie pour les fonctions anonymes, appelée arrow functions. Utilisez-la systématiquement, car elle règle aussi un problème de contexte spécifique à JavaScript.


numbersList.stream().filter(value > value > 2);

view raw

arrow.java

hosted with ❤ by GitHub


numbersList.filter((value) => value > 2);

view raw

arrow.js

hosted with ❤ by GitHub

Méthodes natives

Quelques unes des méthodes de base. Notez que length est une propriété (et non une méthode) en JavaScript.


myEmail.indexOf("@");
myEmail.replaceAll("(.*)@(.*)", " at ");
myEmail.substring(0, 5);
myEmail.length();
Integer.parseInt("5");

view raw

methods.java

hosted with ❤ by GitHub


myEmail.strpos('@');
myEmail.replace('@', ' at ');
myEmail.substring(0, 5);
myEmail.length;
Number.parseInt('5', 10);

view raw

methods.js

hosted with ❤ by GitHub

Quand une fonction semble être appelée directement, comme setTimeout(), c’est parce que l’objet global est implicite : window.setTimeout().

Classes

L’ES6 a introduit la syntaxe des classes, pour simplifier la programmation orienté objet en JavaScript. Les propriétés sont déclarées directement dans le constructeur. Les propriétés pré-déclarées et les modificateurs de visibilité apparaîtront dans une prochaine version de JavaScript, mais TypeScript permet de les utiliser dès maintenant.


public class User {
public String firstName;
public User(String firstName) {
this.firstName = firstName;
}
public void sayHello() {}
}
User myUser = new User("Henri");
myUser.firstName;
myUser.sayHello();

view raw

class.java

hosted with ❤ by GitHub


class User {
public firstName: string; // TypeScript only
public constructor(firstName: string) {
this.firstName = firstName;
}
public sayHello(): void {}
}
let myUser: User = new User(`Henri`);
myUser.firstName;
myUser.sayHello();

view raw

class.ts

hosted with ❤ by GitHub

Lors d’un héritage en JavaScript, l’appel au constructeur parent est obligatoire dans le constructeur fils.


public class Editor extends User {
public Editor(String firstName) {
super(firstName);
}
public void sayHello() {
super.sayHello();
}
}


class Editor extends User {
public constructor(firstName: string) {
super(firstName);
}
public sayHello(): void {
super.sayHello();
}
}

view raw

inheritance.ts

hosted with ❤ by GitHub

Les getters et setters ont une syntaxe spéciale en JavaScript (mais vous pouvez aussi faire des accesseurs classiques). Ne pré-déclarez pas la propriété, JavaScript le fait automatiquement.


public class User {
protected String name;
public String getName() {
return this.name;
}
public void setName(String newName) {
this.name = newName;
}
}
User myUser = new User("Henri");
myUser.getName();
myUser.setName("New name");

view raw

accessors.java

hosted with ❤ by GitHub


class User {
protected _name: string;
public get name(): string {
return this._name;
}
public set name(newName: string) {
this._name = newName;
}
}
let myUser: User = new User(`Henri);
myUser.name;
myUser.name = `New name`;

view raw

accessors.ts

hosted with ❤ by GitHub

La syntaxe est la même pour les méthodes statiques.


class Utilities {
static filter(): void {}
}
Utilities.filter();

view raw

static.ts

hosted with ❤ by GitHub

TypeScript ajoute les classes abstraites et les interfaces.


public interface Movable {
public void move();
}
public class Vehicle implements Movable {
public void move() {}
}
public abstract class Test {}

view raw

interface.java

hosted with ❤ by GitHub


interface Movable {
move(): void;
}
class Vehicle implements Movable {
public move(): void {}
}
abstract class Test {}

view raw

interface.ts

hosted with ❤ by GitHub

Namespaces

L’encapsulation est gérée directement par le système de chargement depuis l’ES6 : s’il y a l’instruction export ou l’instruction import, alors vous n’êtes plus en portée globale. Soyez vigilants : l’extension’ .js est nécessaire dans les imports JavaScript, mais en TypeScript, comme vous devrez gérer à la fois des fichiers .ts en développement et des fichiers .js en production, il est préférable de configurer le système de chargement pour ajouter automatiquement la bonne extension.


// User.java
package accounts;
public class User {}
// script.java
import accounts.User;
User myUser = new User();

view raw

package.java

hosted with ❤ by GitHub


// module.js
export class User {}
// script.js
import { User } from './module.js';
let myUser = new User();

view raw

namespace.js

hosted with ❤ by GitHub

Revenir au sommaire des guides JavaScript