Как избежать переназначения без параметров при установке свойства для объекта DOM


98

У меня есть метод, основная цель которого - установить свойство объекта DOM.

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

Я использую стиль кода AirBnB, из-за которого ESLint выдает no-param-reassignошибку:

ошибка Присваивание параметру функции 'el' no-param-reassign

Как я могу управлять объектом DOM, переданным в качестве аргумента, в соответствии со стилем кода AirBnB?

Кто-то предложил использовать /* eslint react/prop-types: 0 */ссылку на другую проблему, но, если я не ошибаюсь, это хорошо подходит для реакции, но не для собственных манипуляций с DOM.

Также я не думаю, что изменение стиля кода - это ответ. Я считаю, что одним из преимуществ использования стандартного стиля является наличие согласованного кода в разных проектах, а изменение правил по желанию кажется неправильным использованием основного стиля кода, такого как AirBnB.

Для протокола, я спросил AirBnB на GitHub, что они думают о том, как поступить в этих случаях в выпуске № 766 .


Неа. Во-первых, это будет означать отключение этого правила для всех остальных случаев, когда это правило имеет смысл. Во-вторых, я считаю, что вы либо следуете руководству по стилю, либо нет. По крайней мере, если это руководство по стилю, которому следуют многие разработчики для самых разных проектов.
Лукас

2
Но вы спрашиваете, как не подчиняться руководству по стилю, потому что вы делаете то, что оно пытается предотвратить. В любом случае, просто отключите его для этой функции
Матлетика


@Mathletics Нет, я считаю это правило разумным, но в данном конкретном случае оно просто не работает. Мне было интересно, есть ли способ сделать это, играя по правилам.
Лукас

Как ни крути, нужная операция противоречит правилу. Тем не менее, это похоже на проблему XY; Я бы не стал прикреплять свойства напрямую к таким узлам DOM.
Матлетика

Ответы:


103

Как предлагает @Mathletics, вы можете полностью отключить правило , добавив его в свой .eslintrc.jsonфайл:

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

Или вы можете отключить правило специально для свойств параметров

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

В качестве альтернативы вы можете отключить правило для этой функции

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

Или только для этой строки

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

Вы также можете проверить это сообщение в блоге об отключении правил ESLint специально для соответствия руководству по стилю AirBnB.


1
Спасибо. Кажется, большинство людей считают, что лучше всего модифицировать линтер. Применение этого для одной строки кажется мне сейчас лучшим компромиссом.
Лукас

2
Это действительно имеет смысл, например, для проектов nodejs express, в которые иногда может потребоваться внести изменения res.sessionпрямо сейчас
Дэвид

Если проблема заключается только в настройке свойств параметров функции, как указано в вопросе, ответ Gyandeep ниже намного лучше.
Prashanth Chandra

88

Как объясняется в этой статье , это правило предназначено для предотвращения изменения argumentsобъекта . Если вы назначаете параметр, а затем пытаетесь получить доступ к некоторым параметрам через argumentsобъект, это может привести к неожиданным результатам.

Вы можете сохранить правило без изменений и сохранить стиль AirBnB, используя другую переменную, чтобы получить ссылку на элемент DOM, а затем изменить ее:

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

В JS объекты (включая узлы DOM) передаются по ссылке, поэтому здесь elи theElementесть ссылки на один и тот же узел DOM, но изменение theElementне изменяет argumentsобъект, поскольку arguments[0]остается просто ссылкой на этот элемент DOM.

На этот подход намекают в документации к правилу :

Примеры правильного кода для этого правила:

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

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

Лично я бы просто использовал "no-param-reassign": ["error", { "props": false }]подход, упомянутый в нескольких других ответах. Изменение свойства параметра не изменяет то, на что указывает этот параметр, и не должно вызывать проблем, которых пытается избежать это правило.


6
Это должен быть принятый ответ, а не способ обойти поведение. Поскольку этот ответ и Патрик Бэкон, как указано в официальной документации ESLint, указывают на явную проблему, которая может возникнуть
Реми

1
Этот ответ должен быть принятым ответом, поскольку он указывает на официальную документацию и хорошо объяснен. Большинство других ответов похоже на отключение пожарной сигнализации!
Хамид

Вы можете получить сообщение «Локальная переменная 'theElement' избыточна».
Phạm Tuấn Anh

Какую схему именования вы бы использовали для этих новых ссылок? Я абсолютно ненавижу ставить здесь «My» перед вещами, но очень сложно и даже нелогично переименовывать уже правильно названные параметры при создании новой ссылки.
GhostBytes

Я только что проверил и arguments[0]мутировал. Что я делаю не так? ... theElement.expando = { p: 2 }; return arguments[0].expando; ....
mrmowji

20

Вы можете переопределить это правило внутри своего .eslintrcфайла и отключить его для таких свойств параметров, как это

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

Таким образом, правило остается активным, но не будет предупреждать о свойствах. Дополнительная информация: http://eslint.org/docs/rules/no-param-reassign


3
Разве этот ответ полностью не входит в принятый?
Дэн Даскалеску 08

1
@DanDascalescu.Под принятым ответом есть комментарий, указывающий на этот, так что, возможно, он был отредактирован в какой-то момент, чтобы быть более полным?
bigsee

12

no-param-reassignПредупреждение имеет смысл для общих функций, но для классического Array.forEachцикла по массиву , который вы собираетесь мутировать это не присваивать.

Однако, чтобы обойти это, вы также можете использовать Array.mapс новым объектом (если вы похожи на меня, не любите откладывать предупреждения с комментариями):

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

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

Все остальное - просто уродливые хаки.


2

Те, кто желает выборочно деактивировать это правило, могут быть заинтересованы в предлагаемой новой опции для no-param-reassignправила, которая разрешает «белый список» имен объектов, переназначение параметров которых следует игнорировать.


Выше было опубликовано как ответ, а не комментарий из-за отсутствия репутации.
RH Becker



0

Вы можете использовать методы для обновления данных. Например. «res.status (404)» вместо «res.statusCode = 404» Я нашел решение. 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;
});

-1

Ты можешь использовать:

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

1
Разве это не изменяет только копию (насколько это ценно)?
2540625 06

1
На самом деле это не решение, потому что это означает, что нужно избегать переназначения параметров путем создания нового объекта, в то время как мне явно нужно не создавать новый объект, а изменять исходный.
Лукас

Я предпочитаю не изменять параметры, но вы также можете использовать Object.defineProperty (), если вы сделаете так, линтер не выдаст вам ошибку.
Оливер

Это вообще не сработает. Вы делаете копию переменной, копируете из нее свойства на новый объект, изменяете свойство, а затем не возвращаете его, поэтому ничего не происходит. Даже если вы его вернули, вы возвращаете объект, а не элемент DOM, подобный тому, что был передан. Кроме того, Object.assignэто для копирования из объекта в целевой объект. Попытка скопировать из такого элемента DOM приводит к пустому объекту.
Useless Code

Plus Object.assignне будет работать должным образом, если вы пытаетесь повторно присвоить свойство объекта с круговыми ссылками (например, соединение сокета). Object.assignпо умолчанию это неглубокая копия, а глубокое клонирование очень не одобряется из-за снижения производительности.
ILikeTacos 01

-1

Если вы хотите изменить какое-либо значение внутри массива объектов, вы можете использовать

array.forEach(a => ({ ...a, expando: {} }))
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.