Jak uniknąć ponownego przypisywania parametrów podczas ustawiania właściwości obiektu DOM

98

Mam metodę, której głównym celem jest ustawienie właściwości obiektu DOM

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

Używam stylu kodu AirBnB, co sprawia, że ​​ESLint no-param-reassignwyświetla błąd:

error Przypisanie do parametru funkcji „el” no-param-re assigning

Jak mogę manipulować obiektem DOM przekazanym jako argument, zachowując zgodność ze stylem kodu AirBnB?

Ktoś zasugerował użycie w /* eslint react/prop-types: 0 */odniesieniu do innego problemu, ale jeśli się nie mylę, to odnosi się to dobrze do reagowania, ale nie do manipulacji natywnym DOM.

Nie sądzę też, żeby zmiana stylu kodu była odpowiedzią. Uważam, że jedną z zalet używania standardowego stylu jest posiadanie spójnego kodu we wszystkich projektach, a zmiana zasad do woli wydaje się być nadużyciem głównego stylu kodu, takiego jak AirBnB.

Dla przypomnienia, zapytałem AirBnB na GitHubie, co ich zdaniem jest dobrym rozwiązaniem w tych przypadkach w numerze 766 .

Lukas
źródło
Nie. Po pierwsze, oznaczałoby to wyłączenie tego dla wszystkich innych wystąpień, w których ta reguła ma sens. Po drugie, uważam, że albo postępujesz zgodnie ze wskazówkami dotyczącymi stylu, albo nie. Przynajmniej jeśli jest to przewodnik po stylu, za którym podąża wielu programistów we wszystkich rodzajach projektów.
Lukas,
2
Ale pytasz, jak nie stosować się do przewodnika stylisty, ponieważ robisz to, czemu próbuje zapobiec. W każdym razie wyłącz ją dla tej funkcji
Mathletics
@Mathletics Nie Uważam, że reguła ma sens, ale po prostu nie działa w tym konkretnym przypadku. Zastanawiałem się, czy można to zrobić, grając zgodnie z zasadami.
Lukas,
Bez względu na to, jak to wyrazisz, żądana operacja jest w konflikcie z regułą. To powiedziawszy, wygląda na to, że problem XY; Nie dołączałbym właściwości bezpośrednio do węzłów DOM w ten sposób.
Mathletics

Odpowiedzi:

103

Jak sugeruje @Mathletics, możesz całkowicie wyłączyć regułę , dodając to do swojego .eslintrc.jsonpliku:

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

Możesz też wyłączyć regułę specjalnie dla właściwości parametrów

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

Alternatywnie możesz wyłączyć regułę dla tej funkcji

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

Albo tylko dla tej linii

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

Możesz również zapoznać się z tym wpisem na blogu dotyczącym wyłączania reguł ESLint, aby dostosować się do przewodnika stylistycznego AirBnB.

sfletche
źródło
1
Dziękuję Ci. Wygląda na to, że większość ludzi uważa modyfikację lintera za najlepszy sposób. Zastosowanie tego do pojedynczej linii wydaje mi się teraz najlepszym kompromisem.
Lukas
2
To naprawdę ma sens, np. W przypadku projektów nodejs express, gdzie czasami możesz chcieć zmodyfikować res.sessionod razu
David
Jeśli problem dotyczy tylko ustawienia właściwości parametrów funkcji, jak podano w pytaniu, odpowiedź Gyandeepa poniżej jest znacznie lepsza.
Prashanth Chandra
88

Jak wyjaśnia ten artykuł , ta reguła ma na celu uniknięcie mutacji argumentsobiektu . Jeśli przypiszesz parametr, a następnie spróbujesz uzyskać dostęp do niektórych parametrów za pośrednictwem argumentsobiektu, może to prowadzić do nieoczekiwanych wyników.

Możesz zachować regułę nienaruszoną i zachować styl AirBnB, używając innej zmiennej w celu uzyskania odniesienia do elementu DOM, a następnie zmodyfikuj to:

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

W JS obiekty (w tym węzły DOM) są przekazywane przez odniesienie, więc tutaj eli theElementsą referencjami do tego samego węzła DOM, ale modyfikowanie theElementnie powoduje mutacji argumentsobiektu, ponieważ arguments[0]pozostaje tylko odniesieniem do tego elementu DOM.

Takie podejście jest zasugerowane w dokumentacji reguły :

Przykłady poprawnego kodu dla tej reguły:

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

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

Osobiście użyłbym tylko "no-param-reassign": ["error", { "props": false }]kilku innych wymienionych odpowiedzi. Modyfikacja właściwości parametru nie powoduje mutacji tego, do czego odnosi się ten parametr i nie powinna powodować problemów, których ta reguła stara się uniknąć.

Bezużyteczny kod
źródło
6
To powinna być akceptowana odpowiedź, a nie sposób na obejście tego zachowania. Od tej odpowiedzi, a Patric Bacon, jak stwierdzono w oficjalnej dokumentacji ESLint, wskazuje na wyraźny problem, który może się z nim zdarzyć w niektórych scenariuszach: spin.atomicobject.com/2011/04/10/ ...
Remi
1
Ta odpowiedź powinna być akceptowaną odpowiedzią, ponieważ wskazuje na oficjalną dokumentację i jest dobrze wyjaśniona. Większość innych odpowiedzi to jak wyłączenie alarmu pożarowego!
Hamid Parchami
Możesz otrzymać "Zmienna lokalna 'theElement' is redundant".
Phạm Tuấn Anh
Jakiego schematu nazewnictwa użyłbyś dla tych nowych odniesień? Absolutnie nienawidzę umieszczać tutaj „Moje” na pierwszym miejscu, ale jest naprawdę trudne, a nawet sprzeczne z intuicją, zmienić nazwy już trafnie nazwanych parametrów podczas tworzenia nowego odniesienia.
GhostBytes
1
Modyfikacja właściwości parametru nie powoduje zmiany tego, do czego odnosi się ten parametr. , Myślałem, że obiekty są przekazywane przez odniesienie! Czy mógłbyś to rozwinąć?
mrmowji
20

Możesz nadpisać tę regułę w swoim .eslintrcpliku i wyłączyć ją dla takich właściwości parametrów

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

W ten sposób reguła jest nadal aktywna, ale nie będzie ostrzegać o właściwościach. Więcej informacji: http://eslint.org/docs/rules/no-param-re assign

Gyandeep
źródło
3
Czy ta odpowiedź nie jest w pełni zawarta w zaakceptowanej?
Dan Dascalescu
1
@DanDascalescu Pod zaakceptowaną odpowiedzią znajduje się komentarz wskazujący na tę odpowiedź, więc może został on kiedyś zredagowany, aby był bardziej wszechstronny?
bigsee
12

no-param-reassignOstrzeżenie sens dla typowych funkcji, ale za to klasycznyArray.forEach pętli nad tablicy którym zamierzasz go zmutować nie jest właściwe.

Aby jednak to obejść, możesz również użyć Array.mapnowego obiektu (jeśli jesteś podobny do mnie, nie lubisz odkładania ostrzeżeń z komentarzami):

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
źródło
5
function (el) {
  el.setAttribute('expando', {});
}

Wszystko inne to po prostu brzydkie hacki.

lawina 1
źródło
2

Ci, którzy chcą selektywnie dezaktywować tę regułę, mogą być zainteresowani proponowaną nową opcją dla no-param-reassignreguły, która umożliwiłaby „białą listę” nazw obiektów, w odniesieniu do których ponowne przypisanie parametrów powinno zostać zignorowane.

RH Becker
źródło
Powyższe zostało opublikowane jako odpowiedź, a nie komentarz, z powodu braku punktów rep.
RH Becker
1

Zgodnie z dokumentacją :

function (el) {
  const element = el
  element.expando = {}
}
Victor Santos
źródło
0

Możesz użyć metod aktualizacji danych. Na przykład. „res.status (404)” zamiast „res.statusCode = 404” znalazłem rozwiązanie. 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
źródło
-1

Możesz użyć:

(param) => {
  const data = Object.assign({}, param);
  data.element = 'some value';
}
Oliver
źródło
1
Czy to nie tylko modyfikuje kopię (jak jest to cenne)?
2540625
1
Tak naprawdę nie jest to rozwiązanie, ponieważ oznacza to unikanie ponownego przypisywania parametrów przez tworzenie nowego obiektu, podczas gdy ja jawnie nie muszę tworzyć nowego obiektu, ale zmodyfikować oryginalny.
Lukas
Wolę nie modyfikować parametrów, ale możesz także użyć Object.defineProperty (), jeśli robisz w ten sposób, linter nie zgłosi błędu.
Oliver
To w ogóle by nie zadziałało. Tworzysz kopię zmiennej, kopiujesz z niej właściwości do nowego obiektu, modyfikujesz właściwość, a następnie jej nie zwracasz, więc nic się nie dzieje. Nawet jeśli go zwróciłeś, zwracasz obiekt, a nie element DOM, taki jak ten, który został przekazany. Ponadto Object.assignsłuży do kopiowania z obiektu do obiektu docelowego. Próba skopiowania z takiego elementu DOM skutkuje pustym obiektem.
Bezużyteczny kod
Dodatkowo Object.assignnie będzie działać poprawnie, jeśli próbujesz ponownie przypisać właściwość Object z odwołaniami cyklicznymi (na przykład połączenie z gniazdem). Object.assigndomyślnie jest to płytka kopia, a głębokie klonowanie jest bardzo mile widziane z powodu wysokiej wydajności.
ILikeTacos
-1

Jeśli chcesz zmienić dowolną wartość w tablicy obiektów, możesz użyć

array.forEach(a => ({ ...a, expando: {} }))
A.Veryga
źródło