J'apprends JavaScript et je suis assez confus au sujet du tableau de propriétés arguments
.
J'ai une fonction qui prend un seul argument et le renvoie. Lorsque je passe le paramètre et le réaffecte en utilisant arguments[0] = value
, Il met à jour la valeur.
function a(b) {
arguments[0] = 2;
return b;
}
console.log(a(1)); //returns 2
Mais lorsque j'appelle la même fonction sans paramètres, elle renvoie undefined
.
function a(b) {
arguments[0] = 2;
return b;
}
console.log(a()); //returns undefined
Mais même si je passe undefined
, la valeur sera également mise à jour.
function a(b) {
arguments[0] = 2;
return b;
}
console.log(a(undefined)); //returns 2
Je pensais que si vous ne transmettez pas un paramètre à une fonction JavaScript, il le crée automatiquement et attribue la valeur à undefined
et après la mise à jour, il devrait refléter la valeur mise à jour, non?
a()
et a(undefined)
sont aussi la même chose, non?
L'affectation à arguments
indicies ne modifiera la valeur d'argument associée (appelons-la n
- ème argument) que si la fonction a été appelée avec au moins n
arguments. Les propriétés indexées numériquement de l'objet arguments
sont essentiellement setters (et getters):
Les italiques ci-dessous sont mes commentaires sur la façon dont le processus se rapporte à la question:
(Let)
args
(be) les arguments réels passés à la méthode interne [[Call]]
Soit
len
le nombre d'éléments dans args.Soit
indx
= _len - 1
_.Répéter pendant que _
indx >= 0
_, ( donc, la boucle ci-dessous ne s'exécutera pas si aucun argument n'est passé à la fonction:)( attribuer à l'argument objet en cours de création, appelé ici
map
:)
- Ajoutez
name
comme élément de la listemappedNames
.
- Soit
g
le résultat de l'appel de l'opération abstraiteMakeArgGetter
avec les argumentsname
etenv
.
- Soit
p
le résultat de l'appel de l'opération abstraiteMakeArgSetter
avec les argumentsname
etenv
.
- Appelez la méthode interne [[DefineOwnProperty]] de
map
en passant ToString (indx
), le descripteur de propriété {[[Set]]:p
, [[Get]]:g
, [[Configurable]]:true
} etfalse
comme arguments.
Donc, si la fonction est invoquée sans arguments, il n'y aura pas de setter sur _arguments[0]
_, donc la réaffecter ne changera pas le paramètre à l'index 0.
Le même genre de chose se produit également pour les autres indices - si vous appelez une fonction avec 1 paramètre, mais que la fonction accepte deux paramètres, l'affectation à _arguments[1]
_ ne changera pas le deuxième paramètre, car _arguments[1]
_ ne fait pas avoir un passeur:
_function fn(a, b) {
arguments[1] = 'bar';
console.log(b);
}
fn('foo');
_
Alors
a()
eta(undefined)
sont la même chose non?
n'est pas le cas, car le second se traduit par un objet arguments
avec un setter et un getter sur l'index 0, tandis que le premier ne le fait pas.
Notez que cette étrange interaction entre le arguments
et les paramètres de fonction n'est présente qu'en mode bâclé. En mode strict, les modifications apportées à arguments
n'auront aucun effet sur la valeur contenue dans un identificateur d'argument individuel:
_'use strict';
function a(b) {
arguments[0] = 2;
return b;
}
console.log(a(1)); //returns 1
_
ECMA 262 9.0 2018 décrit ce comportement dans 9.4.4 Arguments Objets exotiques avec
NOTE 1:
Les propriétés de données indexées sur un entier d'un objet exotique d'arguments dont les valeurs de nom numériques sont inférieures au nombre de paramètres formels de objet fonction partagent initialement leurs valeurs avec les liaisons d'argument correspondantes dans la fonction contexte d'exécution . Cela signifie que la modification de la propriété modifie la valeur correspondante de la liaison d'argument et vice-versa. Cette correspondance est rompue si une telle propriété est supprimée puis redéfinie ou si la propriété est transformée en propriété d'accesseur . Si l'objet arguments est un objet ordinaire, les valeurs de ses propriétés sont simplement une copie des arguments passés à la fonction et il n'y a pas de lien dynamique entre les valeurs de propriété et les valeurs de paramètre formelles.
En bref,
si dans 'sloppy mode'
, tous les arguments sont mappés à leurs variables nommées, si la longueur correspond au paramètre donné, ou
si dans 'strict mode'
, puis la liaison est perdue après la remise des arguments.
Ceci n'est lisible que dans une ancienne version de ECMA 262 7.0 2016 . Il décrit ce comportement dans 9.4.4 Arguments Objets exotiques avec
Note 1:
Pour les fonctions non strictes, les propriétés de données indexées entières d'un objet arguments dont les valeurs de nom numériques sont inférieures au nombre de paramètres formels de l'objet fonction correspondant partagent initialement leurs valeurs avec les liaisons d'argument correspondantes dans le contexte d'exécution de la fonction. Cela signifie que la modification de la propriété modifie la valeur correspondante de la liaison d'argument et vice-versa. Cette correspondance est rompue si une telle propriété est supprimée puis redéfinie ou si la propriété est transformée en propriété d'accesseur. Pour les fonctions en mode strict, les valeurs des propriétés de l'objet arguments sont simplement une copie des arguments passés à la fonction et il n'y a pas de lien dynamique entre les valeurs de propriété et les valeurs de paramètre formelles.
c'est parce que les arguments ce n'est pas comme un tableau, c'est un objet avec des clés de données indexées entières et une longueur de propriété, et si la longueur est égale à zéro, cela signifie que vous n'avez pas d'arguments
function a(b) {
arguments[0] = 2;
console.log(arguments.length)
return b;
}
a(1); // length 1 returns 2
console.log(a()); // length 0 returns undefined
Ma compréhension est que l'objet arguments ne suit que ce qui est passé dans la fonction. Comme vous n'avez rien transmis au départ, b
n'est pas lié et à ce stade arguments
n'est pas "suivi" b
. Ensuite, vous affectez une valeur à l'objet de type tableau initialisé mais vide arguments
et vous retournez enfin b, qui n'est pas défini.
Pour approfondir cela:
Si une fonction non stricte ne contient pas de paramètres de repos, par défaut ou déstructurés, les valeurs de l'objet arguments changent en synchronisation avec les valeurs des variables d'argument. Voir le code ci-dessous:
function func(a) {
arguments[0] = 99; // updating arguments[0] also updates a
console.log(a);
}
func(10); // 99
et
function func(a) {
a = 99; // updating a also updates arguments[0]
console.log(arguments[0]);
}
func(10); // 99
Lorsqu'une fonction non stricte contient des paramètres de repos, par défaut ou déstructurés, les valeurs de l'objet arguments ne suivent pas les valeurs des arguments. Au lieu de cela, ils reflètent les arguments fournis lors de l'appel de la fonction:
function func(a = 55) {
arguments[0] = 99; // updating arguments[0] does not also update a
console.log(a);
}
func(10); // 10
et
function func(a = 55) {
a = 99; // updating a does not also update arguments[0]
console.log(arguments[0]);
}
func(10); // 10
et
// An untracked default parameter
function func(a = 55) {
console.log(arguments[0]);
}
func(); // undefined
Source: documents Web MDN
Lorsque vous ne fournissez aucun paramètre, arguments
array a length
égal à 0. Ensuite, vous essayez de définir l'élément inexistant du tableau sur 2
ce qui provoque un retour non défini
Vous pouvez simplement tester cela avec cet extrait:
function a(b){
alert(arguments.length) // It will Prompt 0 when calling a() and 1 when calling a(undefined)
arguments[0] = 2;
return b;
}
Il s'agit de la définition de valeur non définie de la spécification javascript:
valeur primitive utilisée lorsqu'aucune valeur n'a été affectée à une variable.
donc si vous ne spécifiez pas le type de retour de fonction, il retournera non défini.
donc a() et a(undefined) ce n'est pas la même chose. retourner undefined est basé sur le type de retour est défini ou non).
pour plus de clarification similar_problem