Como evitar no-param-reassign ao definir uma propriedade em um objeto DOM

94

Eu tenho um método cujo objetivo principal é definir uma propriedade em um objeto DOM

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

Eu uso o estilo de código do AirBnB, o que faz o ESLint gerar um no-param-reassignerro:

Erro de atribuição ao parâmetro de função 'el' no-param-reassign

Como posso manipular um objeto DOM passado como um argumento enquanto conforma o estilo de código do AirBnB?

Alguém sugeriu usar /* eslint react/prop-types: 0 */referindo-se a outro problema, mas se não me engano, isso se aplica bem para reagir, mas não para manipulação de DOM nativo.

Além disso, não acho que mudar o estilo do código seja uma resposta. Acredito que um dos benefícios de usar um estilo padrão é ter um código consistente entre os projetos e alterar as regras à vontade parece um uso indevido de um estilo de código importante como o do AirBnB.

Para registro, perguntei ao AirBnB no GitHub, o que eles acham que é o caminho a seguir nesses casos na edição # 766 .

Lukas
fonte
Nah. Em primeiro lugar, isso significaria desativar isso para todas as outras ocorrências em que essa regra faz sentido. Em segundo lugar, acredito que você segue um guia de estilo ou não. Pelo menos se for um guia de estilo seguido por muitos desenvolvedores em todos os tipos de projetos.
Lukas
2
Mas você está perguntando como não obedecer ao guia de estilo, porque está fazendo o que ele está tentando impedir. Em qualquer caso, basta desabilitá-lo para essa função
Mathletics
@Mathletics Não, acho a regra sensata, mas ela simplesmente não funciona para este caso específico. Eu queria saber se existe uma maneira de fazer isso seguindo as regras.
Lukas
Não importa o que você diga, a operação que você deseja está em conflito com a regra. Dito isso, parece um problema XY; Eu não anexaria propriedades diretamente aos nós DOM assim.
Mathletics

Respostas:

100

Como @Mathletics sugere, você pode desativar a regra inteiramente adicionando isto ao seu .eslintrc.jsonarquivo:

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

Ou você pode desativar a regra especificamente para propriedades param

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

Como alternativa, você pode desativar a regra para essa função

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

Ou apenas para essa linha

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

Você também pode verificar esta postagem do blog sobre a desativação das regras ESLint especificamente para acomodar o guia de estilo do AirBnB.

sfletche
fonte
1
Obrigado. Parece que a maioria das pessoas acha que modificar o linter é a melhor maneira de fazer. Aplicar isso para uma única linha parece ser a melhor opção para mim agora.
Lukas
2
Isso realmente faz sentido, por exemplo, para projetos expressos de nodejs, onde às vezes você pode querer modificar res.sessionimediatamente
David
Se o problema for apenas definir as propriedades dos parâmetros da função conforme declarado na pergunta, a resposta de Gyandeep abaixo é muito melhor.
Prashanth Chandra
85

Como este artigo explica , essa regra tem o objetivo de evitar a mutação do argumentsobjeto . Se você atribuir a um parâmetro e, em seguida, tentar acessar alguns dos parâmetros por meio do argumentsobjeto, isso pode levar a resultados inesperados.

Você pode manter a regra intacta e manter o estilo AirBnB usando outra variável para obter uma referência ao elemento DOM e, em seguida, modificá-lo:

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

Em JS, os objetos (incluindo nós DOM) são passados ​​por referência, então aqui ele theElementestão referências ao mesmo nó DOM, mas modificar theElementnão altera o argumentsobjeto, pois arguments[0]permanece apenas uma referência a esse elemento DOM.

Essa abordagem é sugerida na documentação da regra :

Exemplos de código correto para esta regra:

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

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

Pessoalmente, eu usaria apenas a "no-param-reassign": ["error", { "props": false }]abordagem de algumas outras respostas mencionadas. Modificar uma propriedade do parâmetro não altera o que esse parâmetro se refere e não deve gerar os tipos de problemas que esta regra está tentando evitar.

Código inútil
fonte
5
Essa deve ser a resposta aceita, não uma forma de contornar o comportamento. Uma vez que esta resposta, e Patric Bacon, conforme declarado na documentação oficial da ESLint, aponta um problema claro que pode acontecer com ela em certos cenários: spin.atomicobject.com/2011/04/10/…
Remi
1
Esta resposta deve ser aceita, pois aponta para a documentação oficial e está bem explicada. A maioria das outras respostas é como desligar o alarme de incêndio!
Hamid Parchami de
Você pode obter "A variável local 'theElement' é redundante".
Phạm Tuấn Anh
Que tipo de esquema de nomenclatura você usaria para essas novas referências? Eu absolutamente odeio colocar 'Meu' na frente das coisas aqui, mas é muito difícil e até contra-intuitivo renomear parâmetros já nomeados apropriadamente ao criar uma nova referência.
GhostBytes
Acabei de verificar e arguments[0]foi mutado. O que estou fazendo de errado? ... theElement.expando = { p: 2 }; return arguments[0].expando; ....
Mrmowji
20

Você pode substituir esta regra dentro do seu .eslintrcarquivo e desativá-la para propriedades de parâmetros como este

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

Dessa forma, a regra ainda está ativa, mas não avisará para propriedades. Mais informações: http://eslint.org/docs/rules/no-param-reassign

Gyandeep
fonte
3
Essa resposta não está totalmente incluída na aceita?
Dan Dascalescu
1
@DanDascalescu Há um comentário abaixo da resposta aceita apontando para esta, então talvez ela tenha sido editada em algum momento para ser mais abrangente?
ver
11

O no-param-reassignaviso faz sentido para funções comuns, mas para um Array.forEachloop clássico sobre uma matriz que você pretende modificar, não é apropriado.

No entanto, para contornar isso, você também pode usar Array.mapcom um novo objeto (se você for como eu, não gosta de adiar avisos com comentários):

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

Todo o resto são apenas hacks feios.

avalanche1
fonte
2

Aqueles que desejam desativar esta regra seletivamente podem estar interessados ​​em uma nova opção proposta para a no-param-reassignregra que permitiria uma "lista branca" de nomes de objetos com relação a quais reatribuições de parâmetros deveriam ser ignoradas.

RH Becker
fonte
Acima foi postado como uma resposta, ao invés de um comentário, devido à falta de pontos de representação.
RH Becker
1

Seguindo a documentação :

function (el) {
  const element = el
  element.expando = {}
}
Vitor santos
fonte
0

Você pode usar métodos para atualizar dados. Por exemplo. "res.status (404)" em vez de "res.statusCode = 404" Encontrei a solução. 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
fonte
-1

Você pode usar:

(param) => {
  const data = Object.assign({}, param);
  data.element = 'some value';
}
Oliver
fonte
1
Isso não modifica apenas a cópia (como isso é valioso)?
2540625
1
Isso não é realmente uma solução, porque significa evitar a reatribuição de parâmetros criando um novo objeto, enquanto eu preciso explicitamente não criar um novo objeto, mas modificar o original.
Lukas
Prefiro não modificar os parâmetros, mas você também pode usar Object.defineProperty () se fizer isso, o linter não gerará um erro.
Oliver
Isso não funcionaria de forma alguma. Você está fazendo uma cópia da variável, copiando propriedades dela para um novo objeto, modificando uma propriedade e não a retornando, então nada acontece. Mesmo se você o retornou, está retornando um objeto, não um elemento DOM como o que foi passado. Além disso, Object.assigné para copiar de um objeto para um objeto de destino. Tentar copiar de um elemento DOM como esse resulta em um objeto vazio.
Código inútil de
Além disso Object.assign, não funcionará apropriadamente se você estiver tentando reajustar uma propriedade em Object com referências circulares (uma conexão de socket, por exemplo). Object.assignpor padrão, é uma cópia superficial, e a clonagem profunda é muito desaprovada por causa do impacto no desempenho.
ILikeTacos
-1

Se você quiser alterar qualquer valor dentro de uma matriz de objeto, você pode usar

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