Cómo evitar no-param-reassign al configurar una propiedad en un objeto DOM

94

Tengo un método cuyo objetivo principal es establecer una propiedad en un objeto DOM

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

Utilizo el estilo de código de AirBnB que hace que ESLint arroje un no-param-reassign error:

error Asignación al parámetro de función 'el' no-param-reassign

¿Cómo puedo manipular un objeto DOM pasado como argumento mientras se ajusta al estilo de código de AirBnB?

Alguien sugirió usar /* eslint react/prop-types: 0 */refiriéndose a otro problema pero si no me equivoco, esto se aplica bien para reaccionar, pero no para la manipulación DOM nativa.

Además, no creo que cambiar el estilo del código sea una respuesta. Creo que uno de los beneficios de usar un estilo estándar es tener un código consistente en todos los proyectos y cambiar las reglas a voluntad se siente como un mal uso de un estilo de código importante como el de AirBnB.

Para que conste, le pregunté a AirBnB en GitHub, cuál creen que es el camino a seguir en estos casos en el número 766 .

Lukas
fuente
Nah. En primer lugar, eso significaría deshabilitar esto para todas las demás ocurrencias en las que esta regla tiene sentido. En segundo lugar, creo que o sigues una guía de estilo o no. Al menos si se trata de una guía de estilo seguida por muchos desarrolladores en todo tipo de proyectos.
Lukas
2
Pero estás preguntando cómo no obedecer la guía de estilo, porque estás haciendo lo que está tratando de evitar. En cualquier caso, simplemente desactívelo para esa función
Mathletics
@Mathletics No, la regla me parece sensata, pero simplemente no funciona para este caso específico. Me preguntaba si hay alguna manera de hacer esto siguiendo las reglas.
Lukas
No importa cómo lo exprese, la operación que desea entra en conflicto con la regla. Dicho esto, parece un problema XY; No adjuntaría propiedades directamente a los nodos DOM de esa manera.
Mathletics

Respuestas:

100

Como sugiere @Mathletics, puede deshabilitar la regla por completo agregando esto a su .eslintrc.jsonarchivo:

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

O puede deshabilitar la regla específicamente para propiedades de parámetros

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

Alternativamente, puede deshabilitar la regla para esa función

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

O solo para esa línea

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

También puede consultar esta publicación de blog sobre cómo deshabilitar las reglas de ESLint específicamente para adaptarse a la guía de estilo de AirBnB.

sfletche
fuente
1
Gracias. Parece que la mayoría de las personas consideran que modificar el linter es la mejor manera de hacerlo. Aplicar esto para una sola línea parece ser la mejor compensación para mí en este momento.
Lukas
2
Eso realmente tiene sentido, es decir, para proyectos de nodejs express, donde a veces es posible que desee modificar de res.sessioninmediato
David
Si el problema es solo con la configuración de propiedades de los parámetros de función como se indica en la pregunta, la respuesta de Gyandeep a continuación es mucho mejor.
Prashanth Chandra
85

Como explica este artículo , esta regla está destinada a evitar la mutación del argumentsobjeto . Si asigna un parámetro y luego intenta acceder a algunos de los parámetros a través delarguments objeto, puede generar resultados inesperados.

Puede mantener la regla intacta y mantener el estilo AirBnB usando otra variable para obtener una referencia al elemento DOM y luego modificar eso:

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

En JS, los objetos (incluidos los nodos DOM) se pasan por referencia, por lo que aquí ely theElementson referencias al mismo nodo DOM, pero la modificación theElementno muta el argumentsobjeto, ya que arguments[0]sigue siendo solo una referencia a ese elemento DOM.

Este enfoque se insinúa en la documentación de la regla :

Ejemplos de código correcto para esta regla:

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

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

Personalmente, solo usaría el "no-param-reassign": ["error", { "props": false }]enfoque en un par de otras respuestas mencionadas. La modificación de una propiedad del parámetro no cambia a qué se refiere ese parámetro y no debería generar los tipos de problemas que esta regla está tratando de evitar.

Código inútil
fuente
5
Esta debería ser la respuesta aceptada, no una forma de eludir el comportamiento. Desde esta respuesta, y Patric Bacon como se indica en la documentación oficial de ESLint señala un problema claro que podría suceder con él en ciertos escenarios: spin.atomicobject.com/2011/04/10/…
Remi
1
Esta respuesta debería ser la respuesta aceptada, ya que apunta a la documentación oficial y está bien explicada. ¡La mayoría de las otras respuestas son como apagar la alarma de incendio!
Hamid Parchami
Puede obtener "La variable local 'theElement' es redundante".
Phạm Tuấn Anh
¿Qué tipo de esquema de nomenclatura utilizaría para estas nuevas referencias? Odio poner 'My' delante de las cosas aquí, pero es realmente difícil e incluso contrario a la intuición cambiar el nombre de los parámetros que ya tienen un nombre adecuado al crear una nueva referencia.
GhostBytes
Solo lo comprobé y arguments[0]se transformó. ¿Qué estoy haciendo mal? ... theElement.expando = { p: 2 }; return arguments[0].expando; ....
mrmowji
20

Puede anular esta regla dentro de su .eslintrcarchivo y deshabilitarla para propiedades de parámetros como esta

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

De esta forma, la regla sigue activa pero no advertirá sobre las propiedades. Más información: http://eslint.org/docs/rules/no-param-reassign

Gyandeep
fuente
3
¿No está esta respuesta completamente incluida en la aceptada?
Dan Dascalescu
1
@DanDascalescu Hay un comentario debajo de la respuesta aceptada que apunta a esta, entonces, ¿quizás fue editado en algún momento para ser más completo?
bigsee
11

La no-param-reassignadvertencia tiene sentido para funciones comunes, pero para un clásicoArray.forEach bucle sobre una matriz que tiene la intención de mutar, no es apropiado.

Sin embargo, para evitar esto, también puede usar Array.mapcon un nuevo objeto (si es como yo, no le gusta posponer advertencias con comentarios):

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

Todo lo demás son trucos feos.

avalancha1
fuente
2

Aquellos que deseen desactivar selectivamente esta regla podrían estar interesados ​​en una nueva opción propuesta para la no-param-reassignregla que permitiría una "lista blanca" de nombres de objetos con respecto a qué reasignación de parámetros debería ignorarse.

RH Becker
fuente
Lo anterior se publicó como una respuesta, en lugar de un comentario, debido a la falta de puntos de repetición.
RH Becker
1

Siguiendo la documentación :

function (el) {
  const element = el
  element.expando = {}
}
Víctor Santos
fuente
0

Puede utilizar métodos para actualizar datos. P.ej. "res.status (404)" en lugar de "res.statusCode = 404" encontré la solución. 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
fuente
-1

Puedes usar:

(param) => {
  const data = Object.assign({}, param);
  data.element = 'some value';
}
Oliver
fuente
1
¿No modifica esto solo la copia (qué valor tiene eso)?
2540625
1
Esto no es realmente una solución porque esto significa evitar la reasignación de parámetros creando un nuevo objeto, mientras que explícitamente no necesito crear un nuevo objeto sino modificar el original.
Lukas
Prefiero no modificar los parámetros, pero también puede usar Object.defineProperty () si lo hace de esta manera, el linter no le arrojará un error.
Oliver
Esto no funcionaría en absoluto. Está haciendo una copia de la variable, copiando propiedades de ella en un nuevo objeto, modificando una propiedad y luego no devolviéndola, así que no pasa nada. Incluso si lo devolvió, está devolviendo un objeto, no un elemento DOM como lo que se pasó. Además de eso, Object.assignes para copiar de un objeto a un objeto de destino. Intentar copiar de un elemento DOM como ese da como resultado un objeto vacío.
Código inútil
Además Object.assign, no funcionará correctamente si está intentando reafirmar una propiedad en un objeto con referencias circulares (una conexión de socket, por ejemplo). Object.assignpor defecto es una copia superficial, y la clonación profunda está muy mal vista debido al impacto en el rendimiento.
ILikeTacos
-1

Si desea cambiar cualquier valor dentro de una matriz de objetos, puede usar

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