Python pour débutants : Syntaxe de base et structures de données
Introduction Python est l'un des langages de programmation les plus accessibles et puissants pour débuter…
JavaScript a considérablement évolué depuis ES6 (ECMAScript 2015). Comprendre ces nouvelles fonctionnalités est essentiel pour travailler avec les frameworks modernes comme React, Vue ou Angular. Cet article vous guidera à travers les trois piliers du JavaScript moderne.
// ❌ Problème avec var : hoisting et scope de fonction
function exempleVar() {
console.log(count); // undefined (pas d'erreur!)
var count = 5;
if (true) {
var count = 10; // Même variable!
console.log(count); // 10
}
console.log(count); // 10 (modifié dans le if)
}
// ✅ let : block scope et pas de hoisting
function exempleLet() {
// console.log(count); // ReferenceError!
let count = 5;
if (true) {
let count = 10; // Variable différente
console.log(count); // 10
}
console.log(count); // 5 (non affecté)
}
// ✅ const : impossible de réassigner
const APIURL = 'https://api.example.com';
// APIURL = 'autre'; // TypeError!
// ⚠️ Les objets/arrays sont mutables
const user = { name: 'Alice' };
user.name = 'Bob'; // ✅ OK
user.age = 30; // ✅ OK
// user = {}; // ❌ TypeError!
const numbers = [1, 2, 3];
numbers.push(4); // ✅ OK
// numbers = []; // ❌ TypeError!
// ✅ Bonne pratique
const maxUsers = 100;
const users = [];
let currentPage = 1;
function loadUsers() {
currentPage++; // let permet la modification
users.push(...fetchUsers(currentPage)); // const permet mutation
}
// Fonction traditionnelle
function add(a, b) {
return a + b;
}
// Arrow function équivalente
const add = (a, b) => {
return a + b;
};
// Return implicite (sans accolades)
const add = (a, b) => a + b;
// Un seul paramètre : parenthèses optionnelles
const square = x => x x;
// Pas de paramètres : parenthèses obligatoires
const getRandom = () => Math.random();
const products = [
{ name: 'Laptop', price: 999 },
{ name: 'Mouse', price: 29 },
{ name: 'Keyboard', price: 79 }
];
// ❌ Ancienne méthode
const names = products.map(function(product) {
return product.name;
});
// ✅ Méthode moderne
const names = products.map(product => product.name);
// Filtrage et transformation
const expensiveProducts = products
.filter(p => p.price > 50)
.map(p => ({ ...p, discount: p.price 0.1 }));
// Réduction
const total = products.reduce((sum, p) => sum + p.price, 0);
console.log(total); // 1107
this// ❌ Problème avec fonction traditionnelle
class Timer {
constructor() {
this.seconds = 0;
}
startOld() {
setInterval(function() {
this.seconds++; // ❌ this = window!
console.log(this.seconds); // NaN
}, 1000);
}
}
// ✅ Solution avec arrow function
class Timer {
constructor() {
this.seconds = 0;
}
start() {
setInterval(() => {
this.seconds++; // ✅ this = instance Timer
console.log(this.seconds); // 1, 2, 3...
}, 1000);
}
}
// Event handlers en React
const Button = () => {
const [count, setCount] = useState(0);
// ✅ Arrow function conserve le contexte
const handleClick = () => {
setCount(count + 1);
};
return ;
};
// API calls
const fetchUser = async (userId) => {
const response = await fetch(/api/users/${userId});
return response.json();
};
// Promesses chainées
fetchUser(123)
.then(user => user.posts)
.then(posts => posts.filter(p => p.published))
.catch(error => console.error(error));
// ❌ Ancienne méthode
const user = {
firstName: 'Marie',
lastName: 'Dubois',
age: 28,
email: 'marie@example.com'
};
const firstName = user.firstName;
const lastName = user.lastName;
const email = user.email;
// ✅ Destructuring
const { firstName, lastName, email } = user;
// Renommer les variables
const { firstName: prenom, lastName: nom } = user;
console.log(prenom); // 'Marie'
// Valeurs par défaut
const { age, country = 'France' } = user;
console.log(country); // 'France'
// Destructuring imbriqué
const employee = {
name: 'Pierre',
position: {
title: 'Developer',
level: 'Senior',
department: 'Engineering'
}
};
const { position: { title, level } } = employee;
console.log(title); // 'Developer'
// ✅ API moderne et lisible
const createUser = ({ name, email, role = 'user' }) => {
return {
id: Date.now(),
name,
email,
role,
createdAt: new Date()
};
};
const newUser = createUser({
name: 'Sophie',
email: 'sophie@example.com'
});
// Destructuring avec rest operator
const updateUser = ({ id, ...updates }) => {
return fetch(/api/users/${id}, {
method: 'PATCH',
body: JSON.stringify(updates)
});
};
updateUser({ id: 123, name: 'New Name', age: 30 });
// Bases
const colors = ['red', 'green', 'blue', 'yellow'];
const [primary, secondary] = colors;
console.log(primary); // 'red'
console.log(secondary); // 'green'
// Ignorer des éléments
const [first, , third] = colors;
console.log(third); // 'blue'
// Rest operator
const [head, ...tail] = colors;
console.log(tail); // ['green', 'blue', 'yellow']
// Swap de variables
let a = 1;
let b = 2;
[a, b] = [b, a];
console.log(a, b); // 2, 1
// Avec des fonctions retournant des arrays
const useState = (initial) => {
let state = initial;
const setState = (newState) => { state = newState; };
return [state, setState];
};
const [count, setCount] = useState(0);
// useState
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
// useEffect avec cleanup
useEffect(() => {
const controller = new AbortController();
const fetchData = async () => {
try {
setLoading(true);
const response = await fetch('/api/data', {
signal: controller.signal
});
const data = await response.json();
setUser(data);
} catch (error) {
setError(error.message);
} finally {
setLoading(false);
}
};
fetchData();
return () => controller.abort();
}, []);
// UserCard.jsx
import { useState, useEffect } from 'react';
const UserCard = ({ userId, theme = 'light' }) => {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const fetchUser = async () => {
try {
const response = await fetch(/api/users/${userId});
const data = await response.json();
setUser(data);
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
};
fetchUser();
}, [userId]);
if (loading) return Chargement...;
if (error) return Erreur: {error};
if (!user) return null;
const { name, email, avatar, stats = {} } = user;
const { posts = 0, followers = 0 } = stats;
return (
user-card user-card--${theme}}>
## {name}
{email}
{posts} posts
{followers} followers
);
};
export default UserCard;
// types.ts
interface User {
id: number;
name: string;
email: string;
avatar?: string;
stats?: {
posts: number;
followers: number;
};
}
interface UserCardProps {
userId: number;
theme?: 'light' | 'dark';
}
// UserCard.tsx
import { useState, useEffect } from 'react';
import type { User, UserCardProps } from './types';
const UserCard = ({ userId, theme = 'light' }: UserCardProps) => {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const fetchUser = async (): Promise => {
try {
const response = await fetch(/api/users/${userId});
if (!response.ok) throw new Error('Failed to fetch');
const data: User = await response.json();
setUser(data);
} catch (err) {
setError(err instanceof Error ? err.message : 'Unknown error');
} finally {
setLoading(false);
}
};
fetchUser();
}, [userId]);
if (loading) return Chargement...;
if (error) return Erreur: {error};
if (!user) return null;
const { name, email, avatar, stats = {} } = user;
const { posts = 0, followers = 0 } = stats;
return (
user-card user-card--${theme}}>
{avatar &&
}
## {name}
{email}
{posts} posts
{followers} followers
);
};
export default UserCard;
// utils.test.js
describe('Destructuring et Arrow Functions', () => {
test('extraction de propriétés d'objet', () => {
const user = { name: 'Alice', age: 25 };
const { name, age } = user;
expect(name).toBe('Alice');
expect(age).toBe(25);
});
test('valeurs par défaut', () => {
const { country = 'France' } = {};
expect(country).toBe('France');
});
test('arrow functions avec map', () => {
const numbers = [1, 2, 3];
const doubled = numbers.map(n => n 2);
expect(doubled).toEqual([2, 4, 6]);
});
test('rest operator', () => {
const [first, ...rest] = [1, 2, 3, 4];
expect(first).toBe(1);
expect(rest).toEqual([2, 3, 4]);
});
});
// UserCard.test.jsx
import { render, screen, waitFor } from '@testing-library/react';
import UserCard from './UserCard';
describe('UserCard', () => {
beforeEach(() => {
global.fetch = jest.fn();
});
test('affiche le loading initial', () => {
render( );
expect(screen.getByText('Chargement...')).toBeInTheDocument();
});
test('affiche les données utilisateur', async () => {
const mockUser = {
id: 1,
name: 'Marie',
email: 'marie@example.com',
stats: { posts: 10, followers: 100 }
};
global.fetch.mockResolvedValueOnce({
ok: true,
json: async () => mockUser
});
render( );
await waitFor(() => {
expect(screen.getByText('Marie')).toBeInTheDocument();
expect(screen.getByText('marie@example.com')).toBeInTheDocument();
expect(screen.getByText('10 posts')).toBeInTheDocument();
});
});
test('gère les erreurs API', async () => {
global.fetch.mockRejectedValueOnce(new Error('Network error'));
render( );
await waitFor(() => {
expect(screen.getByText(/Erreur/)).toBeInTheDocument();
});
});
});
// performance-test.js
const iterations = 1000000;
// Test 1: let vs const (performance identique)
console.time('let');
for (let i = 0; i < iterations; i++) {
let x = i 2;
}
console.timeEnd('let'); // ~5ms
console.time('const');
for (let i = 0; i < iterations; i++) {
const x = i 2;
}
console.timeEnd('const'); // ~5ms
// Test 2: Arrow function vs regular function
const regularFunc = function(x) { return x 2; };
const arrowFunc = x => x * 2;
console.time('regular function');
for (let i = 0; i < iterations; i++) {
regularFunc(i);
}
console.timeEnd('regular function'); // ~8ms
console.time('arrow function');
for (let i = 0; i < iterations; i++) {
arrowFunc(i);
}
console.timeEnd('arrow function'); // ~7ms (légèrement plus rapide)
// Test 3: Destructuring vs propriété directe
const obj = { a: 1, b: 2, c: 3, d: 4 };
console.time('direct access');
for (let i = 0; i < iterations; i++) {
const a = obj.a;
const b = obj.b;
}
console.timeEnd('direct access'); // ~3ms
console.time('destructuring');
for (let i = 0; i < iterations; i++) {
const { a, b } = obj;
}
console.timeEnd('destructuring'); // ~4ms (légèrement plus lent, négligeable)
{
"env": {
"es2024": true,
"browser": true,
"node": true
},
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended"
],
"rules": {
"no-var": "error",
"prefer-const": "error",
"prefer-arrow-callback": "error",
"prefer-destructuring": ["error", {
"array": true,
"object": true
}],
"arrow-body-style": ["error", "as-needed"]
}
}
var utiliséconst par défaut, let seulement si mutation nécessaireObject.assign ou Array.concatMaîtriser ces trois concepts fondamentaux vous permettra d'écrire du JavaScript moderne, lisible et performant. Ces patterns sont utilisés partout dans l'écosystème React, Next.js, et tous les frameworks modernes.
const, parfois let, jamais varthis préservéCet article est vivant — corrections, contre-arguments et retours de production sont les bienvenus. Trois canaux, choisissez celui qui vous convient.