So vermeiden Sie eine Neuzuweisung ohne Parameter, wenn Sie eine Eigenschaft für ein DOM-Objekt festlegen

92

Ich habe eine Methode, deren Hauptzweck darin besteht, eine Eigenschaft für ein DOM-Objekt festzulegen

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

Ich verwende den Code-Stil von AirBnB, wodurch ESLint einen no-param-reassignFehler auslöst :

Fehler Zuordnung zum Funktionsparameter 'el' no-param-Neuzuweisung

Wie kann ich ein als Argument übergebenes DOM-Objekt manipulieren und dabei den Codestil von AirBnB anpassen?

Jemand schlug vor, /* eslint react/prop-types: 0 */auf ein anderes Problem zu verweisen, aber wenn ich mich nicht irre, gilt dies gut für die Reaktion, aber nicht für die native DOM-Manipulation.

Ich denke auch nicht, dass das Ändern des Codestils eine Antwort ist. Ich glaube, einer der Vorteile der Verwendung eines Standardstils besteht darin, dass projektübergreifender Code konsistent ist und das Ändern der Regeln nach Belieben wie ein Missbrauch eines wichtigen Codestils wie AirBnBs wirkt.

Für die Aufzeichnung habe ich AirBnB auf GitHub gefragt, was ihrer Meinung nach der richtige Weg in diesen Fällen in Ausgabe 766 ist .

Lukas
quelle
Nein, nein. Erstens würde dies bedeuten, dies für alle anderen Fälle zu deaktivieren, in denen diese Regel sinnvoll ist. Zweitens glaube ich, dass Sie entweder einem Styleguide folgen oder nicht. Zumindest wenn es sich um einen Styleguide handelt, dem viele Entwickler bei allen Arten von Projekten folgen.
Lukas
2
Aber Sie fragen sich, wie Sie dem Styleguide nicht gehorchen sollen, weil Sie das tun, was er zu verhindern versucht. In jedem Fall deaktivieren Sie es
Mathletics
@Mathletics Nein, ich finde die Regel sinnlich, aber sie funktioniert in diesem speziellen Fall einfach nicht. Ich habe mich gefragt, ob es eine Möglichkeit gibt, dies nach den Regeln zu tun.
Lukas
Unabhängig davon, wie Sie es ausdrücken, widerspricht die gewünschte Operation der Regel. Das heißt, es scheint ein XY-Problem zu sein; Ich würde Eigenschaften nicht direkt an solche DOM-Knoten anhängen.
Mathletics

Antworten:

100

Wie @Mathletics vorschlägt, können Sie die Regel vollständig deaktivieren, indem Sie sie Ihrer .eslintrc.jsonDatei hinzufügen :

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

Oder Sie können die Regel speziell für param-Eigenschaften deaktivieren

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

Alternativ können Sie die Regel für diese Funktion deaktivieren

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

Oder nur für diese Zeile

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

Sie können auch diesen Blog-Beitrag zum Deaktivieren von ESLint-Regeln lesen, um den AirBnB-Styleguide zu berücksichtigen.

sfletche
quelle
1
Danke dir. Es scheint, dass die meisten Leute es für den besten Weg halten, den Linter zu modifizieren. Dies für eine einzelne Zeile anzuwenden, scheint mir momentan der beste Kompromiss zu sein.
Lukas
2
Das ist wirklich sinnvoll, dh für NodeJS Express-Projekte, bei denen Sie manchmal res.sessionsofort Änderungen vornehmen möchten
David
Wenn das Problem nur darin besteht, die Eigenschaften der Funktionsparameter wie in der Frage angegeben einzustellen, ist die Antwort von Gyandeep unten viel besser.
Prashanth Chandra
80

Wie in diesem Artikel erläutert , soll mit dieser Regel eine Mutation des argumentsObjekts vermieden werden . Wenn Sie einem Parameter zuweisen und dann versuchen, über das argumentsObjekt auf einige der Parameter zuzugreifen , kann dies zu unerwarteten Ergebnissen führen.

Sie können die Regel beibehalten und den AirBnB-Stil beibehalten, indem Sie eine andere Variable verwenden, um einen Verweis auf das DOM-Element abzurufen, und dann Folgendes ändern:

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

In JS werden Objekte (einschließlich DOM-Knoten) als Referenz übergeben, also hier elund theElementVerweise auf denselben DOM-Knoten, aber das Ändern theElementmutiert das argumentsObjekt nicht, da es arguments[0]nur eine Referenz auf dieses DOM-Element bleibt.

Dieser Ansatz wird in der Dokumentation zur Regel angedeutet :

Beispiele für korrekten Code für diese Regel:

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

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

Persönlich würde ich nur "no-param-reassign": ["error", { "props": false }]einige andere Antworten verwenden. Das Ändern einer Eigenschaft des Parameters ändert nicht, worauf sich dieser Parameter bezieht, und sollte nicht auf die Art von Problemen stoßen, die diese Regel zu vermeiden versucht.

Nutzloser Code
quelle
5
Dies sollte die akzeptierte Antwort sein und kein Weg, um das Verhalten zu umgehen. Seit dieser Antwort weist Patric Bacon, wie in der offiziellen ESLint-Dokumentation angegeben, auf ein klares Problem hin, das in bestimmten Szenarien auftreten kann: spin.atomicobject.com/2011/04/10/…
Remi
1
Diese Antwort sollte die akzeptierte Antwort sein, da sie auf die offizielle Dokumentation verweist und gut erklärt ist. Die meisten anderen Antworten sind wie das Ausschalten des Feueralarms!
Hamid Parchami
Möglicherweise erhalten Sie "Lokale Variable 'theElement' ist redundant".
Phạm Tuấn Anh
Welche Art von Namensschema würden Sie für diese neuen Referenzen verwenden? Ich hasse es absolut, 'My' hier vor die Dinge zu stellen, aber es ist wirklich schwierig und sogar kontraintuitiv, bereits treffend benannte Parameter beim Erstellen einer neuen Referenz umzubenennen.
GhostBytes
Ich habe gerade nachgesehen und arguments[0]war mutiert. Was mache ich falsch? ... theElement.expando = { p: 2 }; return arguments[0].expando; ....
Mrmowji
20

Sie können diese Regel in Ihrer .eslintrcDatei überschreiben und für solche Parametereigenschaften deaktivieren

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

Auf diese Weise ist die Regel weiterhin aktiv, warnt jedoch nicht vor Eigenschaften. Weitere Informationen: http://eslint.org/docs/rules/no-param-reassign

Gyandeep
quelle
3
Ist diese Antwort nicht vollständig in der akzeptierten enthalten?
Dan Dascalescu
1
@DanDascalescu Unter der akzeptierten Antwort befindet sich ein Kommentar, der auf diese Antwort verweist. Vielleicht wurde er irgendwann bearbeitet, um umfassender zu sein?
Bigsee
11

Die no-param-reassignWarnung ist für allgemeine Funktionen sinnvoll, aber für eine klassische Array.forEachSchleife über ein Array, das Sie mutieren möchten, ist sie nicht geeignet.

Um dies zu Array.mapumgehen , können Sie es jedoch auch mit einem neuen Objekt verwenden (wenn Sie wie ich sind, mögen Sie es nicht, Warnungen mit Kommentaren zu dösen):

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
quelle
3
function (el) {
  el.setAttribute('expando', {});
}

Alles andere sind nur hässliche Hacks.

Lawine1
quelle
2

Diejenigen, die diese Regel selektiv deaktivieren möchten, könnten an einer vorgeschlagenen neuen Option für die no-param-reassignRegel interessiert sein , die eine "weiße Liste" von Objektnamen ermöglicht, in Bezug auf die die Neuzuweisung von Parametern ignoriert werden sollte.

RH Becker
quelle
Oben wurde aufgrund fehlender Wiederholungspunkte eher als Antwort als als Kommentar gepostet.
RH Becker
1

Befolgen Sie die Dokumentation :

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

Sie können Methoden zum Aktualisieren von Daten verwenden. Z.B. "res.status (404)" anstelle von "res.statusCode = 404" Ich habe die Lösung gefunden. 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
quelle
-1

Sie können verwenden:

(param) => {
  const data = Object.assign({}, param);
  data.element = 'some value';
}
Oliver
quelle
1
Ändert dies nicht nur die Kopie (wie ist das wertvoll)?
2540625
1
Dies ist keine wirkliche Lösung, da dies bedeutet , dass die Neuzuweisung von Parametern durch Erstellen eines neuen Objekts vermieden wird, während ich ausdrücklich kein neues Objekt erstellen, sondern das ursprüngliche Objekt ändern muss.
Lukas
Ich ziehe es vor, keine Parameter zu ändern, aber Sie können auch Object.defineProperty () verwenden, wenn Sie dies auf diese Weise tun, wird der Linter Ihnen keinen Fehler geben.
Oliver
Das würde überhaupt nicht funktionieren. Sie erstellen eine Kopie der Variablen, kopieren Eigenschaften von ihr auf ein neues Objekt, ändern eine Eigenschaft und geben sie dann nicht zurück, sodass nichts passiert. Selbst wenn Sie es zurückgegeben haben, geben Sie ein Objekt zurück, nicht das a-DOM-Element, wie es übergeben wurde. Darüber hinaus Object.assigndient es zum Kopieren von einem Objekt auf ein Zielobjekt. Der Versuch, aus einem solchen DOM-Element zu kopieren, führt zu einem leeren Objekt.
Nutzloser Code
Plus Object.assignfunktioniert nicht ordnungsgemäß, wenn Sie versuchen, eine Eigenschaft für Object mit Zirkelverweisen (z. B. eine Socket-Verbindung) neu zuzuweisen. Object.assignStandardmäßig handelt es sich um eine flache Kopie, und das tiefe Klonen ist aufgrund des Leistungseinbruchs sehr verpönt.
ILikeTacos
-1

Wenn Sie einen Wert innerhalb eines Objektarrays ändern möchten, können Sie verwenden

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