Comment éviter la réassignation sans paramètre lors de la définition d'une propriété sur un objet DOM

94

J'ai une méthode dont le but principal est de définir une propriété sur un objet DOM

function (el) {
  el.expando = {};
}

J'utilise le style de code d'AirBnB qui fait qu'ESLint génère une no-param-reassignerreur:

erreur Affectation au paramètre de fonction 'el' no-param-réassigner

Comment puis-je manipuler un objet DOM passé en argument tout en conformant le style de code d'AirBnB?

Quelqu'un a suggéré d'utiliser une /* eslint react/prop-types: 0 */référence à un autre problème, mais si je ne me trompe pas, cela s'applique bien à react, mais pas à la manipulation native du DOM.

Je ne pense pas non plus que changer le style de code soit une réponse. Je pense que l'un des avantages de l'utilisation d'un style standard est d'avoir un code cohérent dans tous les projets et de changer les règles à volonté ressemble à une mauvaise utilisation d'un style de code majeur comme celui d'AirBnB.

Pour mémoire, j'ai demandé à AirBnB sur GitHub ce qu'ils pensent être la voie à suivre dans ces cas dans le numéro 766 .

Lukas
la source
Non. Premièrement, cela signifierait désactiver cette option pour toutes les autres occurrences où cette règle a du sens. Deuxièmement, je crois que vous suivez un guide de style ou non. Du moins s'il s'agit d'un guide de style suivi par de nombreux développeurs à travers toutes sortes de projets.
Lukas
2
Mais vous vous demandez comment ne pas obéir au guide de style, car vous faites ce qu'il essaie d'empêcher. Dans tous les cas, désactivez-le
Mathletics
@Mathletics Non, je trouve la règle sensée, mais elle ne fonctionne tout simplement pas pour ce cas précis. Je me demandais s'il y avait un moyen de faire cela en respectant les règles.
Lukas
Peu importe comment vous le dites, l'opération que vous souhaitez est en conflit avec la règle. Cela dit, cela semble être un problème XY; Je n'attacherais pas de propriétés directement aux nœuds DOM comme ça.
Mathletics

Réponses:

100

Comme @Mathletics le suggère, vous pouvez désactiver complètement la règle en l'ajoutant à votre .eslintrc.jsonfichier:

"rules": {
  "no-param-reassign": 0
}

Ou vous pouvez désactiver la règle spécifiquement pour les propriétés des paramètres

"rules": {
  "no-param-reassign": [2, { "props": false }]
}

Vous pouvez également désactiver la règle pour cette fonction

/* eslint-disable no-param-reassign */
function (el) {
  el.expando = {};
}
/* eslint-enable no-param-reassign */

Ou pour cette ligne seulement

function (el) {
  el.expando = {}; // eslint-disable-line no-param-reassign
}

Vous pouvez également consulter cet article de blog sur la désactivation des règles ESLint spécifiquement pour s'adapter au guide de style d'AirBnB.

sfletche
la source
1
Je vous remercie. Il semble que la plupart des gens trouvent que modifier le linter est la meilleure façon de procéder. Appliquer cela pour une seule ligne semble être le meilleur compromis pour moi en ce moment.
Lukas
2
Cela a vraiment du sens, c'est-à-dire pour les projets express nodejs, où parfois vous voudrez peut-être modifier res.sessiontout de suite
David
Si le problème concerne uniquement la définition des propriétés des paramètres de fonction comme indiqué dans la question, la réponse de Gyandeep ci-dessous est bien meilleure.
Prashanth Chandra
85

Comme cet article l'explique , cette règle vise à éviter la mutation de l' argumentsobjet . Si vous affectez à un paramètre, puis essayez d'accéder à certains paramètres via l' argumentsobjet, cela peut conduire à des résultats inattendus.

Vous pouvez conserver la règle intacte et conserver le style AirBnB en utilisant une autre variable pour obtenir une référence à l'élément DOM, puis modifier cela:

function (el) {
  var theElement = el;
  theElement.expando = {};
}

Dans JS, les objets (y compris les nœuds DOM) sont passés par référence, donc ici elet theElementsont des références au même nœud DOM, mais la modification theElementne mute pas l' argumentsobjet puisque arguments[0]reste juste une référence à cet élément DOM.

Cette approche est suggérée dans la documentation de la règle :

Exemples de code correct pour cette règle:

/*eslint no-param-reassign: "error"*/

function foo(bar) {
    var baz = bar;
}

Personnellement, j'utiliserais simplement l' "no-param-reassign": ["error", { "props": false }]approche de quelques autres réponses mentionnées. La modification d'une propriété du paramètre ne modifie pas ce à quoi ce paramètre fait référence et ne devrait pas rencontrer les types de problèmes que cette règle tente d'éviter.

Code inutile
la source
5
Cela devrait être la réponse acceptée, pas un moyen de contourner le comportement. Depuis cette réponse, et Patric Bacon comme indiqué dans la documentation officielle d'ESLint souligne un problème clair qui pourrait survenir avec elle dans certains scénarios: spin.atomicobject.com/2011/04/10/…
Remi
1
Cette réponse devrait être la réponse acceptée car elle pointe vers la documentation officielle et est bien expliquée. La plupart des autres réponses sont comme éteindre l'alarme incendie!
Hamid Parchami
Vous pouvez obtenir "La variable locale 'theElement' est redondante".
Phạm Tuấn Anh
Quel type de schéma de dénomination utiliseriez-vous pour ces nouvelles références? Je déteste absolument mettre «My» devant les choses ici, mais c'est vraiment difficile et même contre-intuitif de renommer des paramètres déjà bien nommés lors de la création d'une nouvelle référence.
GhostBytes
Je viens de vérifier et j'ai arguments[0]été muté. Qu'est-ce que je fais mal? ... theElement.expando = { p: 2 }; return arguments[0].expando; ....
mrmowji le
20

Vous pouvez remplacer cette règle dans votre .eslintrcfichier et la désactiver pour des propriétés de paramètres comme celle-ci

{
    "rules": {
        "no-param-reassign": [2, { 
            "props": false
        }]
    },
    "extends": "eslint-config-airbnb"
}

Cette règle de façon est toujours active mais elle n'avertit pas les propriétés. Plus d'infos: http://eslint.org/docs/rules/no-param-reassign

Gyandeep
la source
3
Cette réponse n'est-elle pas complètement incluse dans celle acceptée?
Dan Dascalescu
1
@DanDascalescu Il y a un commentaire sous la réponse acceptée indiquant celle-ci, alors peut-être a-t-elle été modifiée à un moment donné pour être plus complète?
bigsee
11

L' no-param-reassignavertissement a du sens pour les fonctions courantes, mais pour une Array.forEachboucle classique sur un tableau que vous avez l'intention de muter, il n'est pas approprié.

Cependant, pour contourner cela, vous pouvez également utiliser Array.mapavec un nouvel objet (si vous êtes comme moi, n'aimez pas répéter les avertissements avec des commentaires):

someArray = someArray.map((_item) => {
    let item = Object.assign({}, _item); // decouple instance
    item.foo = "bar"; // assign a property
    return item; // replace original with new instance
});
Justus Romijn
la source
3
function (el) {
  el.setAttribute('expando', {});
}

Tout le reste n'est que de vilains hacks.

avalanche1
la source
2

Ceux qui souhaitent désactiver sélectivement cette règle pourraient être intéressés par une nouvelle option proposée pour la no-param-reassignrègle qui autoriserait une «liste blanche» de noms d'objet par rapport à la réaffectation des paramètres à ignorer.

RH Becker
la source
Ci-dessus a été publié comme une réponse, plutôt que comme un commentaire, en raison du manque de points de répétition.
RH Becker
1

Suite à la documentation :

function (el) {
  const element = el
  element.expando = {}
}
Victor Santos
la source
0

Vous pouvez utiliser des méthodes pour mettre à jour les données. Par exemple. "res.status (404)" au lieu de "res.statusCode = 404" j'ai trouvé la solution. https://github.com/eslint/eslint/issues/6505#issuecomment-282325903

/*eslint no-param-reassign: ["error", { "props": true, "ignorePropertyModificationsFor": ["$scope"] }]*/

app.controller('MyCtrl', function($scope) {
  $scope.something = true;
});
Viktor Antishov
la source
-1

Vous pouvez utiliser:

(param) => {
  const data = Object.assign({}, param);
  data.element = 'some value';
}
Oliver
la source
1
Cela ne modifie-t-il pas uniquement la copie (quelle est sa valeur)?
2540625
1
Ce n'est pas vraiment une solution car cela signifie éviter la réaffectation des paramètres en créant un nouvel objet alors que j'ai explicitement besoin de ne pas créer un nouvel objet mais de modifier l'original.
Lukas
Je préfère ne pas modifier les paramètres, mais vous pouvez également utiliser Object.defineProperty () si vous faites de cette façon, le linter ne vous enverra pas d'erreur.
Oliver
Cela ne fonctionnerait pas du tout. Vous faites une copie de la variable, copiez les propriétés de celle-ci sur un nouvel objet, modifiez une propriété puis ne la renvoyez pas, donc rien ne se passe. Même si vous l'avez renvoyé, vous renvoyez un objet, pas l'élément DOM comme celui qui a été transmis. En plus de cela, il Object.assigns'agit de copier d'un objet vers un objet cible. Essayer de copier à partir d'un élément DOM comme celui-ci entraîne un objet vide.
Code inutile
Plus Object.assignne fonctionnera pas correctement si vous essayez de réassigner une propriété sur Object avec des références circulaires (une connexion socket par exemple). Object.assignpar défaut, il s'agit d'une copie superficielle, et le clonage profond est très mal vu en raison de la baisse des performances.
ILikeTacos
-1

Si vous souhaitez modifier une valeur dans un tableau d'objets, vous pouvez utiliser

array.forEach(a => ({ ...a, expando: {} }))
A.Veryga
la source