Compare commits

...

2 Commits

6 changed files with 468 additions and 3 deletions

View File

@ -123,6 +123,10 @@ export const navigation: NavigationSection[] = [
{ title: "Syntaxe", href: "/docs/javascript/syntaxe" },
{ title: "Instructions", href: "/docs/javascript/instructions" },
{ title: "Types de données", href: "/docs/javascript/types" },
{
title: "Fonctions et portée",
href: "/docs/javascript/fonctions-et-portee",
},
],
},
{

View File

@ -70,3 +70,13 @@ On va donc aborder les sujets suivants :
- Le principe d'asynchrone
Chaque article de cette série sera conçu pour être facilement compréhensible, avec des exemples pratiques et une explication des concepts.
<Callout type="warning" title="Facilement compréhensible !== Facile">
Facilement compréhensible ne veut pas dire que c'est facile à comprendre !
Il y a beaucoup de concepts à assimiler et certains peuvent faire mal au crâne.
Prends ton temps et n'hésite pas à revenir en arrière si tu ne comprends pas quelque chose.
L'idée est de ne surtout pas se précipiter sur les notions suivantes tant que tu n'as pas compris celles abordées dans l'article.
Expérimente et joue avec le code pour plus facilement assimiler !
</Callout>

View File

@ -0,0 +1,157 @@
---
title: Les fonctions et la portée
description: Découvrons ensemble les fonctions et la portée en JavaScript
tags: []
---
import Callout from "@/components/Callout";
import tabs from "./tabs";
Il est maintenant temps de s'attaquer à du sérieux, j'ai nommé : les **fonctions** et la **portée** en JavaScript.
## Les fonctions
Les fonctions sont des blocs de code réutilisables qui effectuent une tâche spécifique. Elles permettent d'organiser le code, de le rendre plus lisible et de réduire la duplication.
Elles peuvent prendre des **paramètres en entrée** et **retourner une valeur en sortie**.
On l'avait déjà vu dans l'article sur la syntaxe, mais il est important de le rappeler :
- **Fonction déclarée** : Utilise le mot-clé `function` suivi du nom de la fonction.
- **Fonction anonyme** : N'a pas de nom et est généralement utilisée comme argument pour une autre fonction.
- **Fonction fléchée** : Une syntaxe plus concise pour déclarer des fonctions.
<tabs.jsFunctions />
Si tu relis les premiers mots de cette section _(sur les fonctions)_, tu remarqueras que j'ai dit que les fonctions sont des blocs de code **réutilisables** qui effectuent une **tâche spécifique**.
C'est un peu vague, non ?
Disons qu'on comprend l'idée générale, mais qu'est-ce que ça veut dire au juste ?
### Utilisation des fonctions
Prenons un exemple simple, avec une fonction qui vérifie si un nombre est pair ou impair.
<tabs.jsIsEven />
Dans cet exemple, nous avons une fonction `isEven` qui prend un nombre en **paramètre** et retourne `true` si le nombre est pair, sinon elle retourne `false`.
On peut ensuite appeler cette fonction avec différents nombres pour vérifier s'ils sont pairs ou impairs.
<tabs.jsCallIsEven />
Dans cet exemple, nous avons appelé la fonction `isEven` avec les nombres 4 et 5 en tant qu'**arguments**.
<Callout type="note" title="Paramètres et arguments">
Les **paramètres** sont les variables déclarées dans la définition de la fonction.
Les **arguments** sont les valeurs passées à la fonction lors de son appel.
</Callout>
## La portée
La portée _(ou **scope** en anglais)_ fait référence à la visibilité des variables et des fonctions dans le code.
Elle détermine où une variable ou une fonction peut être utilisée dans le code.
Il existe trois types de portée en JavaScript :
- **Portée globale** _(global scope)_ : La variable est accessible partout dans le code.
- **Portée de bloc** _(block scope)_ : La variable est accessible uniquement à l'intérieur du bloc où elle a été déclarée.
- **Portée de fonction** _(function scope)_ : La variable est accessible uniquement à l'intérieur de la fonction où elle a été déclarée.
<Callout type="note" title="Portée de bloc">
La portée de bloc est introduite avec les mots-clés `let` et `const`.
Les variables déclarées avec `var` ont une portée fonctionnelle ou globale.
</Callout>
### Portée globale (global scope)
La portée globale est la portée la plus large.
Les variables déclarées en dehors de toute fonction ou bloc de code ont une portée globale.
Une portée globale signifie que la variable est accessible partout dans le code.
<Callout type="warning" title="Déclaration de variable globale">
Attention à **ne pas déclarer** de variables globales, sauf si c'est intentionnel et nécessaire !
Les variables globales peuvent entraîner des conflits de variables/fonctions _(remplacement)_ des variables existantes, notamment des variables de l'objet `window` dans le navigateur.
</Callout>
### Portée de bloc (block scope)
La portée de bloc est une portée qui est limitée au bloc de code dans lequel la variable a été déclarée.
Seules les variables déclarées avec `let` et `const` peuvent avoir une portée de bloc.
<Callout type="question" title="Limité au bloc de code ?">
Par "bloc de code", on parle de tout ce qui est entre accolades `{}` !
Ça peut être une fonction, une boucle, une condition, etc.
</Callout>
<tabs.jsBlockScope />
Dans cet exemple, nous avons :
- Une déclaration d'une variable `x` en dehors d'un bloc de code
- Une déclaration d'une variable `x` à l'intérieur d'un bloc de code _(condition)_
Maintenant, regardons ce qui se passe selon le mot-clé utilisé pour déclarer la variable `x` :
<tabs.jsBlockScopeExplanations />
On remarque que si on utilise `let` ou `const`, la variable `x` déclarée à l'intérieur du bloc de code n'est pas "la même" que celle déclarée à l'extérieur.
Elle est **locale** au bloc de code, et donc inaccessible en dehors de celui-ci.
En revanche, si on utilise `var`, la variable `x` déclarée à l'intérieur du bloc de code est **globale** et écrase la variable `x` déclarée à l'extérieur.
<Callout type="warning" title="Utilisation de var">
Rien que pour ça, il est préférable d'éviter d'utiliser `var` et de lui préférer `let` ou `const`.
</Callout>
### Portée de fonction (function scope)
Pour la portée de fonction, on parle de la portée des variables déclarées à l'intérieur d'une fonction.
Les trois mots-clés `var`, `let` et `const` peuvent être utilisés pour déclarer des variables avec une portée de fonction.
<tabs.jsFunctionScope />
Le fonctionnement est le même que pour la portée de bloc, avec cette fois-ci une portée limitée à la fonction _(y compris pour les variables déclarées avec `var`)_.
## Particularités de var
On a vu que `var` n'a pas la possibilité de déclarer des variables avec une portée de bloc, contrairement à `let` et `const`.
Mais il y a une autre particularité à prendre en compte :
- Les variables déclarées avec `var` sont **hoistées**.
Ça signifie que la déclaration de la variable est déplacée en haut de la portée dans laquelle elle a été déclarée.
- Les variables déclarées avec `let` et `const` ne sont pas hoistées.
<Callout type="warning" title="Hoisting">
Le hoisting peut entraîner des comportements inattendus si on essaie d'accéder à une variable avant sa déclaration.
Il est donc préférable de toujours déclarer les variables au début de leur portée.
</Callout>
Petit exemple pour illustrer ça :
<tabs.jsHoisting />
Dans cet exemple, on voit que la variable `x` est déclarée après son utilisation.
Cependant, grâce _(ou à cause, je te laisse choisir !)_ au hoisting, la déclaration de la variable `x` est déplacée en haut de la portée, ce qui permet d'accéder à sa valeur avant sa déclaration.
On peut donc dire que la variable `x` est **undefined** avant sa déclaration, mais elle existe déjà.
On peut donc l'utiliser avant sa déclaration _(enfin, on aura `undefined` comme valeur)_.
C'est un peu déroutant, non ?
<Callout type="warning" title="Utilisation de var">
Promis, c'est la dernière fois que je te dis de ne pas utiliser `var` !
Mais tu l'auras compris, `var` est vraiment très spécial et peut très vite devenir une source de bugs.
</Callout>
## Conclusion
Voilà, c'est "tout" pour cet article sur les fonctions et la portée en JavaScript !
Comme les articles précédents, ça fait beaucoup d'informations.
Encore une fois, prends le temps d'expérimenter et de jouer avec les notions abordées dans cet article avant de passer à la suite !

View File

@ -0,0 +1,294 @@
import { Snippet } from "@/components/Snippet";
const jsFunctionsSnippets = [
{
name: "Fonction déclarée",
codeLanguage: "js",
code: `function addition(a, b) {
return a + b;
}`,
},
{
name: "Fonction anonyme",
codeLanguage: "js",
code: `const addition = function(a, b) {
return a + b;
};`,
},
{
name: "Fonction fléchée avec retour explicite",
codeLanguage: "js",
code: `const addition = (a, b) => {
return a + b;
};`,
},
{
name: "Fonction fléchée avec retour implicite",
codeLanguage: "js",
code: "const addition = (a, b) => a + b;",
},
];
const jsIsEvenSnippets = [
{
name: "Fonction déclarée",
codeLanguage: "js",
code: `function isEven(number) {
return number % 2 === 0;
}`,
},
{
name: "Fonction anonyme",
codeLanguage: "js",
code: `const isEven = function(number) {
return number % 2 === 0;
};`,
},
{
name: "Fonction fléchée avec retour explicite",
codeLanguage: "js",
code: `const isEven = (number) => {
return number % 2 === 0;
};`,
},
{
name: "Fonction fléchée avec retour implicite",
codeLanguage: "js",
code: "const isEven = (number) => number % 2 === 0;",
},
];
const jsCallIsEvenSnippets = [
{
name: "Appel de la fonction isEven",
codeLanguage: "js",
code: `console.log(isEven(4)); // true
console.log(isEven(5)); // false`,
},
];
const jsBlockScopeSnippets = [
{
name: "Exemple avec let",
withLineNumbers: true,
codeLanguage: "js",
code: `let x = 10;
if (true) {
let x = 20;
console.log(x); // 20
}
console.log(x); // 10`,
},
{
name: "Exemple avec const",
withLineNumbers: true,
codeLanguage: "js",
code: `const x = 10;
if (true) {
const x = 20;
console.log(x); // 20
}
console.log(x); // 10`,
},
{
name: "Exemple avec var",
withLineNumbers: true,
codeLanguage: "js",
code: `var x = 10;
if (true) {
var x = 20;
console.log(x); // 20
}
console.log(x); // 20`,
},
];
const jsBlockScopeExplanations = [
{
name: "Utilisation de let",
children: (
<ul>
<li>
La variable <code>x</code> est déclarée avec <code>let</code> dans le
scope global.
</li>
<li>
Dans le bloc <code>if</code>, une nouvelle variable <code>x</code> est
déclarée, masquant la variable globale.
</li>
<li>
Lorsque nous affichons <code>x</code> à l'intérieur du bloc, il
renvoie la valeur de la variable locale (20).
</li>
<li>
Lorsque nous affichons <code>x</code> en dehors du bloc, il renvoie la
valeur de la variable globale (10).
</li>
</ul>
),
},
{
name: "Utilisation de const",
children: (
<ul>
<li>
La variable <code>x</code> est déclarée avec <code>const</code> dans
le scope global.
</li>
<li>
Dans le bloc <code>if</code>, une nouvelle variable <code>x</code> est
déclarée, masquant la variable globale.
</li>
<li>
Lorsque nous affichons <code>x</code> à l'intérieur du bloc, il
renvoie la valeur de la variable locale (20).
</li>
<li>
Lorsque nous affichons <code>x</code> en dehors du bloc, il renvoie la
valeur de la variable globale (10).
</li>
</ul>
),
},
{
name: "Utilisation de var",
children: (
<ul>
<li>
La variable <code>x</code> est déclarée avec <code>var</code> dans le
scope global.
</li>
<li>
Dans le bloc <code>if</code>, une nouvelle variable <code>x</code> est
déclarée, remplaçant la variable globale.
</li>
<li>
Lorsque nous affichons <code>x</code> à l'intérieur du bloc, il
renvoie la valeur de la variable globale (20).
</li>
<li>
Lorsque nous affichons <code>x</code> en dehors du bloc, il renvoie la
valeur de la variable globale (20).
</li>
</ul>
),
},
];
const jsFunctionScopeSnippets = [
{
name: "Exemple avec let",
withLineNumbers: true,
codeLanguage: "js",
code: `let x = 10;
function example() {
let x = 20;
let y = "Bonjour !";
if (true) {
let x = 30;
console.log(x); // 30
}
console.log(x); // 20
}
example();
console.log(x); // 10
console.log(y); // ReferenceError: y is not defined`,
},
{
name: "Exemple avec const",
withLineNumbers: true,
codeLanguage: "js",
code: `const x = 10;
function example() {
const x = 20;
const y = "Bonjour !";
if (true) {
const x = 30;
console.log(x); // 30
}
console.log(x); // 20
console.log(y); // Bonjour !
}
example();
console.log(x); // 10
console.log(y); // ReferenceError: y is not defined`,
},
{
name: "Exemple avec var",
withLineNumbers: true,
codeLanguage: "js",
code: `var x = 10;
function example() {
var x = 20;
var y = "Bonjour !";
if (true) {
var x = 30;
console.log(x); // 30
}
console.log(x); // 30
}
example();
console.log(x); // 10
console.log(y); // ReferenceError: y is not defined`,
},
];
const jsHoistingSnippets = [
{
name: "Exemple avec let",
withLineNumbers: true,
codeLanguage: "js",
code: `console.log(x); // ReferenceError: Cannot access 'x' before initialization
let x = 10;
console.log(x); // 10`,
},
{
name: "Exemple avec const",
withLineNumbers: true,
codeLanguage: "js",
code: `console.log(x); // ReferenceError: Cannot access 'x' before initialization
const x = 10;
console.log(x); // 10`,
},
{
name: "Exemple avec var",
withLineNumbers: true,
codeLanguage: "js",
code: `console.log(x); // undefined
var x = 10;
console.log(x); // 10`,
},
];
export default {
jsFunctions: () => <Snippet snippets={jsFunctionsSnippets} />,
jsIsEven: () => <Snippet snippets={jsIsEvenSnippets} />,
jsCallIsEven: () => <Snippet snippets={jsCallIsEvenSnippets} />,
jsBlockScope: () => <Snippet snippets={jsBlockScopeSnippets} />,
jsBlockScopeExplanations: () => (
<Snippet snippets={jsBlockScopeExplanations} />
),
jsFunctionScope: () => <Snippet snippets={jsFunctionScopeSnippets} />,
jsHoisting: () => <Snippet snippets={jsHoistingSnippets} />,
};

View File

@ -142,7 +142,7 @@ La fonction fléchée est une syntaxe plus concise et moderne pour déclarer des
Elle a un comportement particulier dans le contexte de retour de valeur, avec une syntaxe raccourcie pour les fonctions à une seule ligne.
<Callout type="question" title="Comment fonctionne le retour de valeur des fonctions fléchées ?">
Dans une fonction classique, on utilise le mot-clé `return` pour retourner une valeur.
Dans une fonction déclarée, on utilise le mot-clé `return` pour retourner une valeur.
Le fonctionnement est identique pour les fonctions fléchées, mais il est possible de profiter d'une syntaxe raccourcie !
Dans le cas d'une fonction fléchée à une seule ligne, il n'est pas nécessaire d'utiliser le mot-clé `return`.

View File

@ -34,7 +34,7 @@ var ville = "Paris";`,
const jsFunctionsSnippets = [
{
name: "Fonction classique",
name: "Fonction déclarée",
codeLanguage: "js",
code: `function addition(a, b) {
return a + b;