Come evitare la riassegnazione dei parametri quando si imposta una proprietà su un oggetto DOM


94

Ho un metodo il cui scopo principale è impostare una proprietà su un oggetto DOM

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

Uso lo stile del codice di AirBnB che fa sì che ESLint generi un no-param-reassignerrore:

errore Assegnazione al parametro funzione 'el' no-param-reassign

Come posso manipolare un oggetto DOM passato come argomento mentre conformo lo stile del codice di AirBnB?

Qualcuno ha suggerito di usare /* eslint react/prop-types: 0 */riferendosi a un altro problema, ma se non sbaglio questo vale per React, ma non per la manipolazione DOM nativa.

Inoltre non credo che cambiare lo stile del codice sia una risposta. Credo che uno dei vantaggi dell'utilizzo di uno stile standard sia avere un codice coerente tra i progetti e cambiare le regole a piacimento sembra un uso improprio di uno stile di codice importante come quello di AirBnB.

Per la cronaca, ho chiesto ad AirBnB su GitHub, quale pensano sia la strada da percorrere in questi casi nel numero 766 .


Nah. In primo luogo, ciò significherebbe disabilitare questo per tutti gli altri casi in cui questa regola ha senso. In secondo luogo, credo che tu segua una guida di stile oppure no. Almeno se si tratta di una guida di stile seguita da molti sviluppatori in tutti i tipi di progetti.
Lukas

2
Ma stai chiedendo come non obbedire alla guida di stile, perché stai facendo la cosa che sta cercando di impedire. In ogni caso, disabilitalo per quella funzione
Mathletics


@ Mathletics No, trovo la regola sensata, ma semplicemente non funziona per questo caso specifico. Mi chiedevo se ci fosse un modo per farlo seguendo le regole.
Lukas

Non importa come la dici, l'operazione che desideri è in conflitto con la regola. Detto questo, sembra un problema XY; Non collegherei le proprietà direttamente ai nodi DOM in questo modo.
Mathletics

Risposte:


100

Come suggerisce @Mathletics, puoi disabilitare completamente la regola aggiungendo questo al tuo .eslintrc.jsonfile:

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

Oppure puoi disabilitare la regola specificamente per le proprietà param

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

In alternativa, puoi disabilitare la regola per quella funzione

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

O solo per quella linea

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

Potresti anche controllare questo post del blog sulla disabilitazione delle regole ESLint appositamente per ospitare la guida di stile di AirBnB.


1
Grazie. Sembra che la maggior parte delle persone ritenga che modificare il linter sia il modo migliore per procedere. Applicare questo per una singola riga sembra il miglior compromesso per me in questo momento.
Lukas

2
Questo ha davvero senso, ad esempio per i progetti nodejs express, dove a volte potresti voler modificare res.sessionimmediatamente
David

Se il problema riguarda solo l'impostazione delle proprietà dei parametri di funzione come indicato nella domanda, la risposta di Gyandeep di seguito è molto migliore.
Prashanth Chandra

85

Come spiega questo articolo , questa regola ha lo scopo di evitare di mutare l' argumentsoggetto . Se si assegna un parametro e poi si tenta di accedere ad alcuni parametri tramite l' argumentsoggetto, si possono ottenere risultati imprevisti.

È possibile mantenere intatta la regola e mantenere lo stile AirBnB utilizzando un'altra variabile per ottenere un riferimento all'elemento DOM e quindi modificarlo:

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

In JS gli oggetti (inclusi i nodi DOM) vengono passati per riferimento, quindi qui ele theElementsono riferimenti allo stesso nodo DOM, ma la modifica theElementnon muta l' argumentsoggetto poiché arguments[0]rimane solo un riferimento a quell'elemento DOM.

Questo approccio è accennato nella documentazione per la regola :

Esempi di codice corretto per questa regola:

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

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

Personalmente, userei semplicemente l' "no-param-reassign": ["error", { "props": false }]approccio menzionato da un paio di altre risposte. La modifica di una proprietà del parametro non muta ciò a cui si riferisce quel parametro e non dovrebbe incorrere nei tipi di problemi che questa regola sta cercando di evitare.


5
Questa dovrebbe essere la risposta accettata, non un modo per aggirare il comportamento. Da questa risposta, e Patric Bacon, come dichiarato nella documentazione ufficiale di ESLint, sottolinea un chiaro problema che potrebbe verificarsi con esso in determinati scenari: spin.atomicobject.com/2011/04/10/…
Remi

1
Questa risposta dovrebbe essere la risposta accettata poiché punta alla documentazione ufficiale ed è ben spiegata. La maggior parte delle altre risposte sono come spegnere l'allarme antincendio!
Hamid Parchami

Potresti ottenere "La variabile locale 'theElement' è ridondante".
Phạm Tuấn Anh

Che tipo di schema di denominazione usereste per questi nuovi riferimenti? Odio assolutamente mettere "My" davanti alle cose qui, ma è davvero difficile e persino contro-intuitivo rinominare parametri già appropriatamente denominati quando si crea un nuovo riferimento.
GhostBytes

Ho appena controllato ed è arguments[0]stato mutato. Che cosa sto facendo di sbagliato? ... theElement.expando = { p: 2 }; return arguments[0].expando; ....
mrmowji

20

Puoi sovrascrivere questa regola all'interno del tuo .eslintrcfile e disabilitarla per proprietà param come questa

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

In questo modo la regola è ancora attiva ma non avviserà per le proprietà. Maggiori informazioni: http://eslint.org/docs/rules/no-param-reassign


3
Questa risposta non è completamente inclusa in quella accettata?
Dan Dascalescu

1
@DanDascalescu C'è un commento sotto la risposta accettata che punta a questo, quindi forse è stato modificato ad un certo punto per essere più completo?
bigsee

11

L' no-param-reassignavviso ha senso per le funzioni comuni, ma per un Array.forEachciclo classico su un array che si intende mutare non è appropriato.

Tuttavia, per aggirare questo problema, puoi anche usarlo Array.mapcon un nuovo oggetto (se sei come me, non mi piacciono gli avvisi di posticipazione con commenti):

someArray = someArray.map((_item) => {
    let item = Object.assign({}, _item); // decouple instance
    item.foo = "bar"; // assign a property
    return item; // replace original with new instance
});

3
function (el) {
  el.setAttribute('expando', {});
}

Tutto il resto è solo brutti hack.


2

Coloro che desiderano disattivare selettivamente questa regola potrebbero essere interessati a una nuova opzione proposta per la no-param-reassignregola che consentirebbe una "lista bianca" di nomi di oggetti rispetto a cui la riassegnazione dei parametri dovrebbe essere ignorata.


Sopra è stato pubblicato come risposta, piuttosto che come commento, a causa della mancanza di punti rep.
RH Becker




-1

Puoi usare:

(param) => {
  const data = Object.assign({}, param);
  data.element = 'some value';
}

1
Questo non modifica solo la copia (come è prezioso)?
2540625

1
Questa non è proprio una soluzione perché questo significa evitare la riassegnazione dei parametri creando un nuovo oggetto mentre ho esplicitamente bisogno di non creare un nuovo oggetto ma modificare quello originale.
Lukas

Preferisco non modificare i parametri, ma puoi anche usare Object.defineProperty () se lo fai in questo modo il linter non ti genererà un errore.
Oliver

Questo non funzionerebbe affatto. Stai facendo una copia della variabile, copiando le proprietà da essa su un nuovo oggetto, modificando una proprietà e quindi non restituendola, quindi non accade nulla. Anche se lo hai restituito, stai restituendo un oggetto, non l'elemento DOM come quello che è stato passato. Inoltre, Object.assignserve per copiare da un oggetto a un oggetto di destinazione. Il tentativo di copiare da un elemento DOM come quello risulta in un oggetto vuoto.
Codice inutile

Inoltre Object.assignnon funzionerà in modo appropriato se stai cercando di riassegnare una proprietà su Object con riferimenti circolari (ad esempio una connessione socket). Object.assignper impostazione predefinita è una copia superficiale e la clonazione profonda è molto disapprovata a causa del calo delle prestazioni.
ILikeTacos

-1

Se vuoi cambiare qualsiasi valore all'interno di un array di oggetti, puoi usare

array.forEach(a => ({ ...a, expando: {} }))
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.