Bagaimana menghindari no-param-reassign saat menyetel properti pada objek DOM

97

Saya memiliki metode yang tujuan utamanya adalah menyetel properti pada objek DOM

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

Saya menggunakan gaya kode AirBnB yang membuat ESLint membuat no-param-reassignkesalahan:

error Assignment to function parameter 'el' no-param-reassign

Bagaimana cara memanipulasi objek DOM yang diteruskan sebagai argumen sambil menyesuaikan gaya kode AirBnB?

Seseorang menyarankan untuk menggunakan /* eslint react/prop-types: 0 */merujuk ke masalah lain tetapi jika saya tidak salah, ini berlaku dengan baik untuk bereaksi, tetapi tidak untuk manipulasi DOM asli.

Saya juga tidak berpikir mengubah gaya kode adalah sebuah jawaban. Saya percaya salah satu manfaat menggunakan gaya standar adalah memiliki kode yang konsisten di seluruh proyek dan mengubah aturan sesuka hati terasa seperti penyalahgunaan gaya kode utama seperti milik AirBnB.

Sebagai catatan, saya bertanya pada AirBnB di GitHub, menurut mereka apa yang harus dilakukan dalam kasus ini di edisi # 766 .

Lukas
sumber
Nah. Pertama, itu berarti menonaktifkan ini untuk semua kejadian lain di mana aturan ini masuk akal. Kedua, saya yakin Anda mengikuti panduan gaya atau tidak. Setidaknya jika itu adalah panduan gaya yang diikuti oleh banyak pengembang di semua jenis proyek.
Lukas
2
Tetapi Anda bertanya bagaimana tidak mematuhi panduan gaya, karena Anda melakukan hal yang coba dicegahnya. Bagaimanapun, nonaktifkan saja untuk fungsi itu
Mathletics
@Mathletics Tidak, menurut saya aturan ini masuk akal, tetapi itu tidak berlaku untuk kasus khusus ini. Saya bertanya-tanya apakah ada cara untuk melakukan ini dengan bermain sesuai aturan.
Lukas
Tidak peduli bagaimana Anda mengucapkannya, operasi yang Anda inginkan bertentangan dengan aturan. Yang mengatakan, sepertinya masalah XY; Saya tidak akan melampirkan properti langsung ke simpul DOM seperti itu.
Mathletics

Jawaban:

102

Seperti yang disarankan @Mathletics, Anda dapat menonaktifkan aturan sepenuhnya dengan menambahkan ini ke .eslintrc.jsonfile Anda :

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

Atau Anda dapat menonaktifkan aturan khusus untuk properti param

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

Atau, Anda dapat menonaktifkan aturan untuk fungsi itu

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

Atau hanya untuk jalur itu

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

Anda juga dapat melihat posting blog ini tentang menonaktifkan aturan ESLint secara khusus untuk mengakomodasi panduan gaya AirBnB.

sfletche
sumber
1
Terima kasih. Tampaknya kebanyakan orang menganggap bahwa memodifikasi linter adalah cara terbaik untuk melakukannya. Menerapkan ini untuk satu baris sepertinya trade off terbaik untuk saya saat ini.
Lukas
2
Itu benar-benar masuk akal, yaitu untuk proyek nodejs express, di mana terkadang Anda mungkin ingin res.sessionlangsung memodifikasinya
David
Jika masalahnya hanya pada pengaturan properti parameter fungsi seperti yang dinyatakan dalam pertanyaan, jawaban Gyandeep di bawah ini jauh lebih baik.
Prashanth Chandra
88

Seperti yang dijelaskan artikel ini , aturan ini dimaksudkan untuk menghindari mutasi argumentsobjek . Jika Anda menetapkan ke parameter dan kemudian mencoba dan mengakses beberapa parameter melalui argumentsobjek, ini dapat menyebabkan hasil yang tidak diharapkan.

Anda bisa menjaga aturan tetap utuh dan mempertahankan gaya AirBnB dengan menggunakan variabel lain untuk mendapatkan referensi ke elemen DOM dan kemudian mengubahnya:

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

Dalam objek JS (termasuk node DOM) diteruskan oleh referensi, jadi di sini eldan theElementadalah referensi ke node DOM yang sama, tetapi memodifikasi theElementtidak mengubah argumentsobjek karena arguments[0]tetap hanya referensi ke elemen DOM tersebut.

Pendekatan ini diisyaratkan dalam dokumentasi untuk aturan tersebut :

Contoh kode yang benar untuk aturan ini:

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

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

Secara pribadi, saya hanya akan menggunakan "no-param-reassign": ["error", { "props": false }]pendekatan beberapa jawaban lain yang disebutkan. Memodifikasi properti parameter tidak mengubah apa yang dirujuk parameter tersebut dan tidak boleh mengalami jenis masalah yang coba dihindari aturan ini.

Kode Tidak Berguna
sumber
6
Ini harus menjadi jawaban yang diterima, bukan cara untuk menghindari perilaku tersebut. Karena jawaban ini, dan Patric Bacon sebagaimana dinyatakan dalam dokumentasi resmi ESLint menunjukkan masalah yang jelas yang dapat terjadi dengannya dalam skenario tertentu: spin.atomicobject.com/2011/04/10/…
Remi
1
Jawaban ini harus menjadi jawaban yang diterima karena menunjuk ke dokumentasi resmi dan dijelaskan dengan baik. Sebagian besar jawaban lainnya seperti mematikan alarm kebakaran!
Hamid Parchami
Anda mungkin mendapatkan "Variabel lokal 'theElement' adalah redundan".
Phạm Tuấn Anh
Jenis skema penamaan apa yang akan Anda gunakan untuk referensi baru ini? Saya benar-benar benci meletakkan 'Saya' di depan banyak hal di sini tetapi sangat sulit dan bahkan kontra-intuitif untuk mengganti nama parameter yang sudah diberi nama dengan tepat saat membuat referensi baru.
GhostBytes
Saya baru saja memeriksa dan arguments[0]dimutasi. Apa yang saya lakukan salah? ... theElement.expando = { p: 2 }; return arguments[0].expando; ....
mrmowji
20

Anda dapat mengganti aturan ini di dalam .eslintrcfile Anda dan menonaktifkannya untuk properti param seperti ini

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

Aturan cara ini masih aktif tetapi tidak akan memperingatkan untuk properti. Info lebih lanjut: http://eslint.org/docs/rules/no-param-reassign

Gyandeep
sumber
3
Bukankah jawaban ini sepenuhnya termasuk dalam jawaban yang diterima?
Dan Dascalescu
1
@DanDascalescu Ada komentar di bawah jawaban yang diterima yang menunjuk ke yang ini, jadi mungkin itu diedit pada beberapa hal agar lebih komprehensif?
lihat besar
11

The no-param-reassignperingatan masuk akal untuk fungsi-fungsi umum, tapi untuk klasikArray.forEach loop atas sebuah array yang Anda berniat untuk bermutasi itu tidak untuk tepat.

Namun, untuk menyiasati ini, Anda juga dapat menggunakan Array.mapdengan objek baru (jika Anda seperti saya, tidak suka menunda peringatan dengan komentar):

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

Yang lainnya hanyalah peretasan yang jelek.

longsoran salju 1
sumber
2

Mereka yang ingin menonaktifkan aturan ini secara selektif mungkin tertarik dengan opsi baru yang diusulkan untuk no-param-reassignaturan yang akan memungkinkan "daftar putih" nama objek sehubungan dengan penugasan ulang parameter mana yang harus diabaikan.

RH Becker
sumber
Di atas telah diposting sebagai jawaban, bukan komentar, karena kurangnya poin rep.
RH Becker
1

Berikut dokumentasinya :

function (el) {
  const element = el
  element.expando = {}
}
Victor Santos
sumber
0

Anda dapat menggunakan metode untuk memperbarui data. Misalnya. "res.status (404)" alih-alih "res.statusCode = 404" Saya menemukan solusinya. 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
sumber
-1

Kamu bisa memakai:

(param) => {
  const data = Object.assign({}, param);
  data.element = 'some value';
}
Oliver
sumber
1
Bukankah ini hanya mengubah salinan (seberapa berharganya)?
2540625
1
Ini sebenarnya bukan solusi karena ini berarti menghindari penugasan ulang param dengan membuat objek baru sementara saya secara eksplisit tidak perlu membuat objek baru tetapi memodifikasi yang asli.
Lukas
Saya lebih suka untuk tidak mengubah params, tetapi Anda juga dapat menggunakan Object.defineProperty () jika Anda melakukan cara ini linter tidak akan membuat Anda error.
Oliver
Ini tidak akan berhasil sama sekali. Anda membuat salinan dari variabel, menyalin properti darinya ke objek baru, mengubah properti dan kemudian tidak mengembalikannya, jadi tidak ada yang terjadi. Bahkan jika Anda mengembalikannya, Anda mengembalikan sebuah objek, bukan elemen DOM seperti yang diteruskan. Selain itu, Object.assignuntuk menyalin dari sebuah objek ke objek target. Mencoba menyalin dari elemen DOM seperti itu menghasilkan objek kosong.
Kode Tidak Berguna
Plus Object.assigntidak akan berfungsi dengan baik jika Anda mencoba untuk menilai kembali properti di Objek dengan referensi melingkar (koneksi soket misalnya). Object.assignsecara default adalah salinan yang dangkal, dan kloning yang dalam sangat tidak disukai karena kinerja yang buruk.
ILikeTacos
-1

Jika Anda ingin mengubah nilai apa pun di dalam larik objek, Anda dapat menggunakan

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