Як уникнути перепризначення no-param при встановленні властивості для об'єкта DOM


94

У мене є метод, головне призначення якого - встановити властивість для об'єкта DOM

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

Я використовую стиль коду AirBnB, що змушує ESLint видавати no-param-reassignпомилку:

Помилка Призначення параметру функції 'el' no-param-re assign

Як я можу маніпулювати об’єктом DOM, переданим як аргумент, відповідаючи стилю коду AirBnB?

Хтось запропонував використовувати /* eslint react/prop-types: 0 */посилання на іншу проблему, але якщо я не помиляюся, це добре застосовується для реакції, але не для маніпуляцій з рідною DOM.

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

Для протоколу я запитав AirBnB на GitHub, яким вони вважають шлях у цих випадках у номері 766 .


Ні По-перше, це означало б вимкнути це для всіх інших випадків, коли це правило має сенс. По-друге, я вірю, що ви або дотримуєтесь керівництва стилем, або ні. Принаймні, якщо це керівництво стилем, яким дотримуються багато розробників у всіх видах проектів.
Лукас

2
Але ви запитуєте, як не підкорятися керівництву стилем, бо ви робите те, що він намагається запобігти. У будь-якому випадку, просто вимкніть його для цієї функції
Mathletics


@Mathletics No Я вважаю правило сенсибельним, але воно просто не працює для цього конкретного випадку. Мені було цікаво, чи є спосіб зробити це, граючи за правилами.
Лукас

Незалежно від того, як ви це вимовите, операція, яку ви хочете, суперечить правилу. Тим не менш, це здається проблемою XY; Я б не прикріплював властивості безпосередньо до DOM-вузлів так.
Математика

Відповіді:


100

Як пропонує @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 висловити проекти, де іноді ви можете захотіти змінити res.sessionвідразу
David

Якщо проблема полягає лише у встановленні властивостей параметрів функції, як зазначено у питанні, відповідь Gyandeep нижче є набагато кращою.
Прашант Чандра

85

Як пояснюється в цій статті , це правило призначене для уникнення мутації 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 }]підходом з кількома згаданими відповідями. Змінення властивості параметра не змінює те, на що посилається цей параметр, і не повинно натрапляти на типи проблем, яких намагається уникнути це правило.


5
Це повинна бути прийнята відповідь, а не спосіб обійти поведінку. Оскільки ця відповідь і Патрік Бекон, як зазначено в офіційній документації ESLint, вказують на явну проблему, яка може трапитися з нею за певних сценаріїв: spin.atomicobject.com/2011/04/10/…
Ремі,

1
Ця відповідь повинна бути прийнятою відповіддю, оскільки вона вказує на офіційну документацію та добре пояснюється. Більшість інших відповідей - як вимкнення пожежної сигналізації!
Хамід Парчамі

Ви можете отримати "Місцева змінна 'theElement' зайва".
Phạm Tuấn Anh

Яку схему імен ви б використали для цих нових посилань? Я абсолютно ненавиджу ставити "Моє" перед речами тут, але насправді важко і навіть протиінтуїтивно перейменовувати вже влучно названі параметри при створенні нового посилання.
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
Хіба ця відповідь не повністю включена в прийняту?
Дан Даскалеску,

1
@DanDascalescu Під прийнятою відповіддю є коментар, який вказує на цей, тож, можливо, він колись був відредагований, щоб бути більш вичерпним?
bigsee

11

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
});

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

Все інше - це просто потворні хаки.


2

Бажаючих вибірково деактивувати це правило може зацікавити запропонована нова опція для no-param-reassignправила, яка дозволить "білий список" імен об'єктів, відносно яких перепризначення параметрів слід ігнорувати.


Вище було розміщено як відповідь, а не як коментар, через відсутність пунктів репутації.
RH Becker




-1

Ви можете використовувати:

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

1
Чи це не змінює лише копію (наскільки це цінно)?
2540625

1
Це насправді не є рішенням, оскільки це означає уникнення перепризначення параметрів шляхом створення нового об'єкта, тоді як мені явно потрібно не створювати новий об'єкт, а модифікувати початковий.
Лукас

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

Це взагалі не спрацювало. Ви робите копію змінної, копіюєте властивості з неї на новий об’єкт, модифікуєте властивість, а потім не повертаєте її, тому нічого не відбувається. Навіть якщо ви його повернули, ви повертаєте об'єкт, а не елемент DOM, як те, що було передано. Крім того, Object.assignце копіювання з об'єкта на цільовий об'єкт. Спроба копіювати з елемента DOM подібним чином призводить до порожнього об’єкта.
марний код

Плюс Object.assignне працюватиме належним чином, якщо ви намагаєтеся змінити властивість об’єкта за допомогою кругових посилань (наприклад, підключення до сокета). Object.assignза замовчуванням - це неглибока копія, а глибоке клонування дуже недоброзичливе через хіт продуктивності.
ILikeTacos 01.03.18

-1

Якщо ви хочете змінити будь-яке значення всередині масиву об’єктів, ви можете використовувати

array.forEach(a => ({ ...a, expando: {} }))
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.