วิธีหลีกเลี่ยงการไม่กำหนดพารามิเตอร์ใหม่เมื่อตั้งค่าคุณสมบัติบนวัตถุ 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


ไม่. ประการแรกนั่นหมายถึงการปิดใช้งานสิ่งนี้สำหรับเหตุการณ์อื่น ๆ ทั้งหมดที่กฎนี้เหมาะสม ประการที่สองฉันเชื่อว่าคุณทำตามคำแนะนำสไตล์หรือไม่ อย่างน้อยถ้าเป็นแนวทางตามด้วยนักพัฒนาจำนวนมากในทุกโครงการ
Lukas

2
แต่คุณกำลังถามว่าจะไม่เชื่อฟัง styleguide ได้อย่างไรเพราะคุณกำลังทำในสิ่งที่พยายามป้องกัน ไม่ว่าในกรณีใดเพียงปิดการใช้งานสำหรับฟังก์ชันนั้น
Mathletics


@Mathletics ไม่ฉันพบว่ากฎมีความสมเหตุสมผล แต่ก็ใช้ไม่ได้กับกรณีนี้ ฉันสงสัยว่ามีวิธีการเล่นตามกฎหรือไม่
Lukas

ไม่ว่าคุณจะพูดอย่างไรการดำเนินการที่คุณต้องการขัดแย้งกับกฎ ที่กล่าวว่าดูเหมือนปัญหา XY; ฉันจะไม่แนบคุณสมบัติโดยตรงกับโหนด DOM แบบนั้น
Mathletics

คำตอบ:


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
ขอบคุณ. ดูเหมือนว่าคนส่วนใหญ่จะพบว่าการปรับเปลี่ยนเส้นเป็นวิธีที่ดีที่สุด การใช้สิ่งนี้สำหรับบรรทัดเดียวดูเหมือนจะเป็นการแลกเปลี่ยนที่ดีที่สุดสำหรับฉันในตอนนี้
Lukas

2
นั่นสมเหตุสมผลจริงๆสำหรับโครงการ nodejs express ซึ่งบางครั้งคุณอาจต้องการแก้ไขres.sessionทันที
David

หากปัญหาเกิดจากการตั้งค่าคุณสมบัติของพารามิเตอร์ฟังก์ชันตามที่ระบุไว้ในคำถามเท่านั้นคำตอบของ 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
นี่ควรเป็นคำตอบที่ได้รับการยอมรับไม่ใช่วิธีหลีกเลี่ยงพฤติกรรม เนื่องจากคำตอบนี้และ Patric Bacon ตามที่ระบุไว้ในเอกสาร ESLint อย่างเป็นทางการชี้ให้เห็นปัญหาที่ชัดเจนที่อาจเกิดขึ้นได้ในบางสถานการณ์: spin.atomicobject.com/2011/04/10/…
Remi

1
คำตอบนี้ควรเป็นคำตอบที่ได้รับการยอมรับเนื่องจากชี้ไปที่เอกสารอย่างเป็นทางการและมีการอธิบายอย่างดี คำตอบอื่น ๆ ส่วนใหญ่ก็เหมือนกับการปิดสัญญาณเตือนไฟไหม้!
Hamid Parchami

คุณอาจได้รับ "ตัวแปรภายใน" theElement "ซ้ำซ้อน"
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
คำตอบนี้ไม่รวมอยู่ในคำตอบที่ยอมรับอย่างสมบูรณ์หรือไม่?
Dan Dascalescu

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


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

1
นี่ไม่ใช่วิธีแก้ปัญหาจริงๆเพราะนี่หมายถึงการหลีกเลี่ยงการกำหนดพารามิเตอร์ใหม่โดยการสร้างวัตถุใหม่ในขณะที่ฉันต้องการอย่างชัดเจนที่จะไม่สร้างวัตถุใหม่ แต่แก้ไขวัตถุเดิม
Lukas

ฉันไม่ต้องการปรับเปลี่ยนพารามิเตอร์ แต่คุณสามารถใช้ Object.defineProperty () ได้เช่นกันหากคุณทำวิธีนี้ลินเตอร์จะไม่ทำให้คุณเกิดข้อผิดพลาด
Oliver

สิ่งนี้จะไม่ได้ผลเลย คุณกำลังทำสำเนาของตัวแปรคัดลอกคุณสมบัติจากมันไปยังวัตถุใหม่แก้ไขคุณสมบัติแล้วไม่ส่งคืนจึงไม่มีอะไรเกิดขึ้น แม้ว่าคุณจะส่งคืน แต่คุณกำลังส่งคืนอ็อบเจ็กต์ไม่ใช่องค์ประกอบ DOM เหมือนสิ่งที่ส่งผ่านนอกจากObject.assignนี้ยังมีไว้สำหรับการคัดลอกจากวัตถุไปยังวัตถุเป้าหมาย การพยายามคัดลอกจากองค์ประกอบ DOM เช่นนั้นจะส่งผลให้วัตถุว่างเปล่า
รหัสไร้ประโยชน์

Plus Object.assignจะไม่ทำงานอย่างเหมาะสมหากคุณกำลังพยายาม re-assing คุณสมบัติบน Object ด้วยการอ้างอิงแบบวงกลม (เช่นการเชื่อมต่อซ็อกเก็ต) Object.assignโดยค่าเริ่มต้นคือการคัดลอกแบบตื้นและการโคลนนิ่งแบบลึกจะทำให้ขมวดคิ้วมากเนื่องจากการตี
ILikeTacos

-1

หากคุณต้องการเปลี่ยนค่าใด ๆ ภายในอาร์เรย์วัตถุคุณสามารถใช้

array.forEach(a => ({ ...a, expando: {} }))
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.