Как избежать переназначения без параметров при установке свойства для объекта 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.