Maison interface Web js tutoriel Compréhension approfondie des paramètres et des fermetures des fonctions JavaScript

Compréhension approfondie des paramètres et des fermetures des fonctions JavaScript

Dec 22, 2016 pm 01:46 PM
js 函数参数 闭包

J'ai récemment appris les fonctions JavaScript. Les fonctions sont les objets de première classe de JavaScript. Si vous voulez bien apprendre JavaScript, vous devez avoir une compréhension approfondie des fonctions. J'ai organisé le processus d'apprentissage en articles, d'une part, pour approfondir ma compréhension de mes propres fonctions, et d'autre part, pour proposer aux lecteurs des moyens d'apprendre et d'éviter les détours. Il y a beaucoup de contenu, mais c'est le résumé des fonctions de l'auteur.

1. Paramètres de fonction

1.1 : Que sont les paramètres

1.2 : Omission des paramètres

1.3 : Valeurs des paramètres par défaut

1.4 : Méthode de passage des paramètres

1.5 : Paramètres de même nom

1.6 : Objet arguments

2. Fermeture

2.1 : Définition de la fermeture

 2.2 : Expression de fonction immédiatement invoquée (IIFE, Expression de fonction immédiatement invoquée)

1. Paramètres de fonction

1.1 : Quels sont les paramètres

Lors de la définition d'une fonction. , Parfois, il est nécessaire de transmettre des données supplémentaires à une fonction. Différentes données externes produiront des résultats différents. Ces données externes sont appelées paramètres.

function keith(a){
return a+a;
}
console.log(keith(3)); //6
Copier après la connexion

Dans le code ci-dessus, le paramètre a est passé à la fonction Keith et l'expression a a est renvoyée.

1.2 : Omission des paramètres

Les paramètres de fonction ne sont pas obligatoires, et la spécification JavaScript permet d'omettre les paramètres réels passés lors de l'appel.

function keith(a, b, c) {
return a;
}
console.log(keith(1, 2, 3)); //1
console.log(keith(1)); //1
console.log(keith()); // 'undefined'
Copier après la connexion

Dans le code ci-dessus, la fonction Keith définit trois paramètres, mais quel que soit le nombre de paramètres transmis lors de l'appel, JavaScript ne signalera pas d'erreur. La valeur par défaut des paramètres omis devient indéfinie. Quiconque comprend les définitions des fonctions et la portée de la fonction sait que l'attribut length d'une fonction renvoie le nombre de paramètres. Il convient de noter que l'attribut length n'a rien à voir avec le nombre de paramètres réels, mais renvoie uniquement le nombre de paramètres formels.

(Paramètres réels : paramètres passés lors de l'appel. Paramètres formels : paramètres passés lors de la définition.)

Mais il n'y a aucun moyen d'omettre uniquement les éléments avant et de conserver les éléments arrière. Si l'élément avant doit être omis, seul undéfini sera affiché.

function keith(a, b) {
return a;
}
console.log(keith(, 1)); //SyntaxError: expected expression, got ','
console.log(keith(undefined, 2)); //'undefined'
Copier après la connexion

Dans le code ci-dessus, si le premier paramètre est omis, le navigateur signalera une erreur. Si undefined est passé comme premier paramètre, aucune erreur ne sera signalée.

1.3 : Valeur par défaut

En JavaScript, la valeur par défaut des paramètres de fonction n'est pas définie. Cependant, il existe des situations dans lesquelles la définition de valeurs par défaut différentes est utile. La stratégie générale consiste à tester dans le corps de la fonction si la valeur du paramètre est indéfinie, à attribuer une valeur si c'est le cas et, dans le cas contraire, à renvoyer la valeur du paramètre réellement transmis.

function keith(a, b) {
(typeof b !== 'undefined') ? b = b: b = 1;
return a * b;
}
console.log(keith(15)); //15
console.log(keith(15, 2)) //30
Copier après la connexion

Dans le code ci-dessus, un jugement est rendu. Lorsque le paramètre b n'est pas transmis lors de l'appel, la valeur par défaut est 1.

À partir d'ECMAScript 6, les paramètres par défaut sont définis. Avec les paramètres par défaut, les vérifications dans le corps de la fonction ne sont plus nécessaires.

function keith(a, b = 1) {
return a * b;
}
console.log(keith(15)); //15
console.log(keith(15, 2)) //30
Copier après la connexion

1.4 : Méthode de transmission des paramètres

Il existe deux façons de transmettre les paramètres d'une fonction, l'une par valeur et l'autre par adresse.

Lorsque le paramètre de fonction est un type de données primitif (chaîne, valeur numérique, valeur booléenne), la méthode de transmission du paramètre se fait par valeur. En d'autres termes, la modification des valeurs des paramètres dans le corps de la fonction n'affectera pas l'extérieur de la fonction.

var a = 1;
function keith(num) {
num = 5;
}
keith(a);
console.log(a); //1
Copier après la connexion

Dans le code ci-dessus, la variable globale a est une valeur de type primitif, et la façon de transmettre la fonction Keith est par valeur. Par conséquent, à l'intérieur de la fonction, la valeur de a est une copie de la valeur d'origine, et quelle que soit la manière dont elle est modifiée, cela n'affectera pas la valeur d'origine.

Cependant, si le paramètre de fonction est une valeur de type composite (tableau, objet, autre fonction), la méthode de livraison est passée par référence. En d’autres termes, ce qui est transmis à la fonction est l’adresse de la valeur d’origine, donc la modification des paramètres à l’intérieur de la fonction affectera la valeur d’origine.

var arr = [2, 5];
function keith(Arr) {
Arr[0] = 3;
}
keith(arr);
console.log(arr[0]); //3
Copier après la connexion

Dans le code ci-dessus, ce qui est passé dans la fonction Keith est l'adresse de l'objet paramètre arr. Par conséquent, modifier la première valeur de arr à l’intérieur de la fonction affectera la valeur d’origine.

Notez que si ce qui est modifié à l'intérieur de la fonction n'est pas un certain attribut de l'objet paramètre, mais remplace l'intégralité du paramètre, la valeur d'origine ne sera pas affectée.

var arr = [2, 3, 5];
function keith(Arr) {
Arr = [1, 2, 3];
}
keith(arr);
console.log(arr); // [2,3,5]
Copier après la connexion

Dans le code ci-dessus, à l'intérieur de la fonction Keith, l'objet paramètre arr est complètement remplacé par une autre valeur. La valeur originale ne sera pas affectée pour le moment. En effet, il existe une relation d'affectation entre le paramètre formel (Arr) et le paramètre réel arr.

1.5 : Paramètres du même nom

S'il existe un paramètre du même nom, la valeur qui apparaît en dernier est prise. Si la valeur du dernier paramètre n'est pas fournie, la valeur. devient indéfini.

function keith(a, a) {
return a;
}
console.log(keith(1, 3)); //3
console.log(keith(1)); //undefined
Copier après la connexion

Si vous souhaitez accéder au premier paramètre du paramètre du même nom, utilisez l'objet arguments.

function keith(a, a) {
return arguments[0];
}
console.log(keith(2));  //2
Copier après la connexion

Objet arguments 1.6

Chaque fonction en JavaScript peut accéder à des arguments de variable spéciale. Cette variable maintient la liste de tous les arguments passés à cette fonction.

L'objet arguments contient tous les paramètres lorsque la fonction est exécutée. arguments[0] est le premier paramètre, arguments[1] est le deuxième paramètre, et ainsi de suite. Cet objet ne peut être utilisé qu'à l'intérieur du corps de la fonction.

Vous pouvez accéder à l'attribut length de l'objet arguments pour déterminer combien de paramètres sont inclus dans l'appel de fonction.

function keith(a, b, c) {
console.log(arguments[0]); //1
console.log(arguments[2]); //3
console.log(arguments.length); //4
}
keith(1, 2, 3, 4);
Copier après la connexion


La relation entre les objets arguments et les tableaux

arguments 对象不是一个数组(Array)。 尽管在语法上它有数组相关的属性 length,但它不从 Array.prototype 继承,实际上它是一个类数组对象。因此,无法对 arguments 变量使用标准的数组方法,比如 push, pop 或者 slice。但是可以使用数组中的length属性。

通常使用如下方法把arguments对象转换为数组。

var arr = Array.prototype.slice.call(arguments);

2.闭包

2.1:闭包定义

要理解闭包,需要先理解全局作用域和局部作用域的区别。函数内部可以访问全局作用域下定义的全局变量,而函数外部却无法访问到函数内部定义(局部作用域)的局部变量。

var a = 1;
function keith() {
 return a;
 var b = 2;
 }
 console.log(keith()); //1
 console.log(b); //ReferenceError: b is not defined
Copier après la connexion

上面代码中,全局变量a可以在函数keith内部访问。可是局部变量b却无法在函数外部访问。

如果需要得到函数内部的局部变量,只有通过在函数的内部,再定义一个函数。

function keith(){
var a=1;
function rascal(){
return a;
}
return rascal;
}
var result=keith();
console.log(result()); //1
function keith(){
var a=1;
return function(){
return a;
};
}
var result=keith();
console.log(result()) //1
Copier après la connexion

上面代码中,两种写法相同,唯一的区别是内部函数是否是匿名函数。函数rascal就在函数keith内部,这时keith内部的所有局部变量,对rascal都是可见的。但是反过来就不行,rascal内部的局部变量,对keith就是不可见的。这就是JavaScript语言特有的”链式作用域”结构(chain scope),子对象会一级一级地向上寻找所有父对象的变量。所以,父对象的所有变量,对子对象都是可见的,反之则不成立。函数keith的返回值就是函数rascal,由于rascal可以读取keith的内部变量,所以就可以在外部获得keith的内部变量了。

闭包就是函数rascal,即能够读取其他函数内部变量的函数。由于在JavaScript语言中,只有函数内部的子函数才能读取内部变量,因此可以把闭包简单理解成“定义在一个函数内部的函数”。闭包最大的特点,就是它可以“记住”诞生的环境,比如rascal记住了它诞生的环境keith,所以从rascal可以得到keith的内部变量。

闭包可以使得它诞生环境一直存在。看下面一个例子,闭包使得内部变量记住上一次调用时的运算结果。

function keith(num) {
return function() {
return num++;
};
}
var result = keith(2);
console.log(result()) //2
console.log(result()) //3
console.log(result()) //4
Copier après la connexion

上面代码中,参数num其实就相当于函数keith内部定义的局部变量。通过闭包,num的状态被保留了,每一次调用都是在上一次调用的基础上进行计算。从中可以看到,闭包result使得函数keith的内部环境,一直存在。

通过以上的例子,总结一下闭包的特点:

1:在一个函数内部定义另外一个函数,并且返回内部函数或者立即执行内部函数。

2:内部函数可以读取外部函数定义的局部变量

3:让局部变量始终保存在内存中。也就是说,闭包可以使得它诞生环境一直存在。

闭包的另一个用处,是封装对象的私有属性和私有方法。

function Keith(name) {
var age;
function setAge(n) {
age = n;
}
function getAge() {
return age;
}
return {
name: name,
setAge: setAge,
getAge: getAge
};
}
var person = Keith('keith');
person.setAge(21);
console.log(person.name); // 'keith'
console.log(person.getAge()); //21
Copier après la connexion

2.2:立即调用的函数表达式(IIFE)

通常情况下,只对匿名函数使用这种“立即执行的函数表达式”。它的目的有两个:一是不必为函数命名,避免了污染全局变量;二是IIFE内部形成了一个单独的作用域,可以封装一些外部无法读取的私有变量。

循环中的闭包

一个常见的错误出现在循环中使用闭包,假设我们需要在每次循环中调用循环序号

for(var i=0;i<10;i++){
setTimeout(function(){
console.log(i); //10
}, 1000)
}
Copier après la connexion

上面代码中,不会符合我们的预期,输出数字0-9。而是会输出数字10十次。

当匿名函数被调用的时候,匿名函数保持着对全局变量 i 的引用,也就是说会记住i循环时执行的结果。此时for循环结束,i 的值被修改成了10。

为了得到想要的效果,避免引用错误,我们应该使用IIFE来在每次循环中创建全局变量 i 的拷贝。

for(var i = 0; i < 10; i++) {
 (function(e) {
 setTimeout(function() {
 console.log(e); //1,2,3,....,10
 }, 1000);
 })(i);
 }
Copier après la connexion

外部的匿名函数会立即执行,并把 i 作为它的参数,此时函数内 e 变量就拥有了 i 的一个拷贝。当传递给 setTimeout 的匿名函数执行时,它就拥有了对 e 的引用,而这个值是不会被循环改变的。


Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn

Outils d'IA chauds

Undresser.AI Undress

Undresser.AI Undress

Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover

AI Clothes Remover

Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool

Undress AI Tool

Images de déshabillage gratuites

Clothoff.io

Clothoff.io

Dissolvant de vêtements AI

AI Hentai Generator

AI Hentai Generator

Générez AI Hentai gratuitement.

Article chaud

R.E.P.O. Crystals d'énergie expliqués et ce qu'ils font (cristal jaune)
3 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Meilleurs paramètres graphiques
3 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Comment réparer l'audio si vous n'entendez personne
3 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25: Comment déverrouiller tout dans Myrise
4 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌

Outils chauds

Bloc-notes++7.3.1

Bloc-notes++7.3.1

Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise

SublimeText3 version chinoise

Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1

Envoyer Studio 13.0.1

Puissant environnement de développement intégré PHP

Dreamweaver CS6

Dreamweaver CS6

Outils de développement Web visuel

SublimeText3 version Mac

SublimeText3 version Mac

Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Quelle est la signification de la fermeture dans l'expression lambda C++ ? Quelle est la signification de la fermeture dans l'expression lambda C++ ? Apr 17, 2024 pm 06:15 PM

En C++, une fermeture est une expression lambda qui peut accéder à des variables externes. Pour créer une fermeture, capturez la variable externe dans l'expression lambda. Les fermetures offrent des avantages tels que la réutilisabilité, la dissimulation des informations et une évaluation paresseuse. Ils sont utiles dans des situations réelles telles que les gestionnaires d'événements, où la fermeture peut toujours accéder aux variables externes même si elles sont détruites.

Comment implémenter la fermeture dans une expression C++ Lambda ? Comment implémenter la fermeture dans une expression C++ Lambda ? Jun 01, 2024 pm 05:50 PM

Les expressions C++ Lambda prennent en charge les fermetures, qui enregistrent les variables de portée de fonction et les rendent accessibles aux fonctions. La syntaxe est [capture-list](parameters)->return-type{function-body}. capture-list définit les variables à capturer. Vous pouvez utiliser [=] pour capturer toutes les variables locales par valeur, [&] pour capturer toutes les variables locales par référence, ou [variable1, variable2,...] pour capturer des variables spécifiques. Les expressions Lambda ne peuvent accéder qu'aux variables capturées mais ne peuvent pas modifier la valeur d'origine.

Quels sont les avantages et les inconvénients des fermetures dans les fonctions C++ ? Quels sont les avantages et les inconvénients des fermetures dans les fonctions C++ ? Apr 25, 2024 pm 01:33 PM

Une fermeture est une fonction imbriquée qui peut accéder aux variables dans la portée de la fonction externe. Ses avantages incluent l'encapsulation des données, la conservation de l'état et la flexibilité. Les inconvénients incluent la consommation de mémoire, l’impact sur les performances et la complexité du débogage. De plus, les fermetures peuvent créer des fonctions anonymes et les transmettre à d'autres fonctions sous forme de rappels ou d'arguments.

Explication détaillée des paramètres de fonction C++ : méthodes d'implémentation, avantages et inconvénients du passage de paramètres indéfinis Explication détaillée des paramètres de fonction C++ : méthodes d'implémentation, avantages et inconvénients du passage de paramètres indéfinis Apr 28, 2024 am 09:48 AM

Passage de paramètres indéfinis C++ : implémenté via l'opérateur..., qui accepte un certain nombre de paramètres supplémentaires. Les avantages incluent la flexibilité, l'évolutivité et le code simplifié. Les inconvénients incluent la surcharge de performances, les difficultés de débogage et la sécurité des types. Des exemples pratiques courants incluent printf() et std::cout, qui utilisent va_list pour gérer un nombre variable de paramètres.

L'impact des pointeurs de fonction et des fermetures sur les performances de Golang L'impact des pointeurs de fonction et des fermetures sur les performances de Golang Apr 15, 2024 am 10:36 AM

L'impact des pointeurs de fonction et des fermetures sur les performances de Go est le suivant : Pointeurs de fonction : légèrement plus lents que les appels directs, mais améliorent la lisibilité et la réutilisabilité. Fermetures : généralement plus lentes, mais encapsulent les données et le comportement. Cas pratique : les pointeurs de fonction peuvent optimiser les algorithmes de tri et les fermetures peuvent créer des gestionnaires d'événements, mais ils entraîneront des pertes de performances.

Comment les fermetures sont-elles implémentées en Java ? Comment les fermetures sont-elles implémentées en Java ? May 03, 2024 pm 12:48 PM

Les fermetures en Java permettent aux fonctions internes d'accéder aux variables de portée externe même si la fonction externe est terminée. Implémentée via des classes internes anonymes, la classe interne contient une référence à la classe externe et maintient les variables externes actives. Les fermetures augmentent la flexibilité du code, mais vous devez être conscient du risque de fuite de mémoire, car les références à des variables externes par des classes internes anonymes maintiennent ces variables en vie.

Explication détaillée des paramètres de la fonction C++ : essence et précautions du mécanisme sortant Explication détaillée des paramètres de la fonction C++ : essence et précautions du mécanisme sortant Apr 27, 2024 pm 12:00 PM

Il existe deux manières de transmettre des paramètres de fonction en C++ : l'appel par valeur (qui n'affecte pas les paramètres réels) et l'appel par référence (qui affecte les paramètres réels). Les paramètres sortants sont transmis par référence ou par pointeur, et la fonction peut transmettre la valeur à l'appelant en modifiant la variable pointée par la référence de paramètre ou le pointeur. Attention lors de l'utilisation : les paramètres sortants doivent être clairement déclarés, ne peuvent correspondre qu'à un seul paramètre réel et ne peuvent pas pointer vers des variables locales au sein de la fonction. Lors d'un appel en passant un pointeur, veillez à éviter les pointeurs sauvages.

Les tableaux peuvent-ils être utilisés comme paramètres de fonction ? Les tableaux peuvent-ils être utilisés comme paramètres de fonction ? Jun 04, 2024 pm 04:30 PM

Oui, dans de nombreux langages de programmation, les tableaux peuvent être utilisés comme paramètres de fonction, et la fonction effectuera des opérations sur les données qui y sont stockées. Par exemple, la fonction printArray en C++ peut imprimer les éléments d'un tableau, tandis que la fonction printArray en Python peut parcourir le tableau et imprimer ses éléments. Les modifications apportées au tableau par ces fonctions sont également reflétées dans le tableau d'origine dans la fonction appelante.

See all articles