web-dev-qa-db-fra.com

La modification de la valeur du paramètre de la fonction JavaScript à l'aide du tableau d'arguments ne fonctionne pas

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?

36
Amit Das

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):

http://es5.github.io/#x10.6

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]]

  1. Soit len le nombre d'éléments dans args.

  2. Soit indx = _len - 1_.

  3. 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 :)

    1. Ajoutez name comme élément de la liste mappedNames.
    1. Soit g le résultat de l'appel de l'opération abstraite MakeArgGetter avec les arguments name et env.
    1. Soit p le résultat de l'appel de l'opération abstraite MakeArgSetter avec les arguments name et env.
    1. Appelez la méthode interne [[DefineOwnProperty]] de map en passant ToString (indx), le descripteur de propriété {[[Set]]: p, [[Get]]: g, [[Configurable]]: true} et false 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() et a(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_
24
CertainPerformance

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.

6
Nina Scholz

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
1
Vadim Hulevich

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

1
Barzev

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; 
}
1
puffy.bun

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

1
sathish kumar