Як уникнути перепризначення 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.