Cách tránh gán lại no-param khi đặt thuộc tính trên đối tượng DOM


94

Tôi có một phương pháp với mục đích chính là đặt thuộc tính trên đối tượng DOM

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

Tôi sử dụng kiểu mã của AirBnB khiến ESLint no-param-reassigngặp lỗi:

lỗi Gán cho tham số hàm 'el' no-param-reassign

Làm cách nào để tôi có thể thao tác một đối tượng DOM được truyền dưới dạng đối số trong khi tuân thủ kiểu mã của AirBnB?

Ai đó đã đề xuất sử dụng /* eslint react/prop-types: 0 */đề cập đến vấn đề khác nhưng nếu tôi không nhầm thì điều này áp dụng tốt cho phản ứng, nhưng không áp dụng cho thao tác DOM gốc.

Ngoài ra, tôi không nghĩ rằng thay đổi kiểu mã là một câu trả lời. Tôi tin rằng một trong những lợi ích của việc sử dụng kiểu chuẩn là có mã nhất quán giữa các dự án và thay đổi các quy tắc theo ý muốn giống như việc sử dụng sai kiểu mã chính như của AirBnB.

Đối với hồ sơ, tôi đã hỏi AirBnB trên GitHub, họ nghĩ đâu là cách để thực hiện trong những trường hợp này trong số 766 .


Không. Thứ nhất, điều đó có nghĩa là vô hiệu hóa điều này cho tất cả các trường hợp khác khi quy tắc này có ý nghĩa. Thứ hai, tôi tin rằng bạn có thể làm theo hướng dẫn phong cách hoặc không. Ít nhất nếu nó là một hướng dẫn phong cách được nhiều nhà phát triển theo dõi trên tất cả các loại dự án.
Lukas

2
Nhưng bạn đang hỏi làm thế nào để không tuân theo hướng dẫn kiểu, bởi vì bạn đang làm điều mà nó đang cố gắng ngăn cản. Trong mọi trường hợp, chỉ cần vô hiệu hóa nó cho chức năng đó
Mathletics


@Mathletics Không Tôi thấy quy tắc này khá thú vị, nhưng nó không hoạt động cho trường hợp cụ thể này. Tôi đã tự hỏi nếu có một cách để làm điều này chơi theo các quy tắc.
Lukas

Bất kể bạn nói như thế nào, hoạt động bạn muốn sẽ xung đột với quy tắc. Điều đó nói rằng, nó có vẻ giống như một vấn đề XY; Tôi sẽ không đính kèm thuộc tính trực tiếp vào các nút DOM như vậy.
Mathletics

Câu trả lời:


100

Như @Mathletics đề xuất, bạn có thể tắt hoàn toàn quy tắc bằng cách thêm quy tắc này vào .eslintrc.jsontệp của mình :

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

Hoặc bạn có thể vô hiệu hóa quy tắc dành riêng cho thuộc tính tham số

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

Ngoài ra, bạn có thể tắt quy tắc cho chức năng đó

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

Hoặc chỉ cho dòng đó

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

Bạn cũng có thể xem bài đăng trên blog này về cách tắt các quy tắc ESLint cụ thể để phù hợp với hướng dẫn phong cách của AirBnB.


1
Cảm ơn bạn. Có vẻ như hầu hết mọi người đều thấy sửa đổi linter là cách tốt nhất để đi. Áp dụng điều này cho một dòng có vẻ như là sự đánh đổi tốt nhất đối với tôi lúc này.
Lukas

2
Đó thực sự có ý nghĩa tức là cho nodejs hiện dự án, nơi mà đôi khi bạn có thể muốn thay đổi res.sessionngay lập tức
David

Nếu vấn đề chỉ là thiết lập thuộc tính của các tham số hàm như đã nêu trong câu hỏi, câu trả lời của Gyandeep dưới đây tốt hơn nhiều.
Prashanth Chandra

85

Như bài viết này giải thích , quy tắc này nhằm tránh làm thay đổi argumentsđối tượng . Nếu bạn gán cho một tham số và sau đó thử và truy cập một số tham số thông qua argumentsđối tượng, nó có thể dẫn đến kết quả không mong muốn.

Bạn có thể giữ nguyên quy tắc và duy trì kiểu AirBnB bằng cách sử dụng một biến khác để nhận tham chiếu đến phần tử DOM và sau đó sửa đổi:

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

Trong các đối tượng JS (bao gồm cả các nút DOM) được truyền bằng tham chiếu, vì vậy đây eltheElementlà các tham chiếu đến cùng một nút DOM, nhưng việc sửa đổi theElementkhông làm thay đổi argumentsđối tượng vì arguments[0]vẫn chỉ là một tham chiếu đến phần tử DOM đó.

Cách tiếp cận này được gợi ý trong tài liệu cho quy tắc :

Ví dụ về mã đúng cho quy tắc này:

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

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

Cá nhân tôi sẽ chỉ sử dụng "no-param-reassign": ["error", { "props": false }]cách tiếp cận một vài câu trả lời khác đã đề cập. Việc sửa đổi một thuộc tính của tham số không làm thay đổi những gì tham số đó đề cập đến và sẽ không gặp phải các loại vấn đề mà quy tắc này đang cố gắng tránh.


5
Đây phải là câu trả lời được chấp nhận, không phải là một cách để phá vỡ hành vi. Vì câu trả lời này, và Patric Bacon như đã nêu trong tài liệu ESLint chính thức chỉ ra một vấn đề rõ ràng có thể xảy ra với nó trong một số trường hợp nhất định: spin.atomicobject.com/2011/04/10/…
Remi

1
Câu trả lời này phải là câu trả lời được chấp nhận vì nó chỉ đến tài liệu chính thức và được giải thích rõ ràng. Hầu hết các câu trả lời khác giống như tắt chuông báo cháy!
Hamid Parchami

Bạn có thể nhận được "Biến cục bộ 'theElement' là dư thừa".
Phạm Tuấn Anh

Bạn sẽ sử dụng kiểu đặt tên nào cho các tham chiếu mới này? Tôi thực sự ghét đặt 'My' trước những thứ ở đây nhưng thực sự khó và thậm chí phản trực quan để đổi tên các tham số đã được đặt tên phù hợp khi tạo một tham chiếu mới.
GhostBytes

Tôi vừa kiểm tra và arguments[0]đã bị đột biến. Tôi đang làm gì sai? ... theElement.expando = { p: 2 }; return arguments[0].expando; ....
mrmowji

20

Bạn có thể ghi đè quy tắc này bên trong .eslintrctệp của mình và vô hiệu hóa nó đối với các thuộc tính param như thế này

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

Quy tắc theo cách này vẫn hoạt động nhưng nó sẽ không cảnh báo cho các thuộc tính. Thông tin thêm: http://eslint.org/docs/rules/no-param-reassign


3
Câu trả lời này không hoàn toàn được bao gồm trong câu được chấp nhận sao?
Dan Dascalescu

1
@DanDascalescu Có một nhận xét bên dưới câu trả lời được chấp nhận trỏ đến câu trả lời này, vì vậy có lẽ nó đã được chỉnh sửa tại một số điểm để toàn diện hơn?
bigsee

11

Các no-param-reassign cảnh báo có ý nghĩa cho các chức năng thông thường, nhưng đối với một cổ điển Array.forEachvòng lặp trên một mảng mà bạn có ý định đột biến nó không phải là để chiếm đoạt.

Tuy nhiên, để giải quyết vấn đề này, bạn cũng có thể sử dụng Array.mapvới một đối tượng mới (nếu bạn giống tôi, không thích báo lại cảnh báo bằng nhận xét):

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', {});
}

Mọi thứ khác chỉ là những bản hack xấu xí.


2

Những người muốn hủy kích hoạt có chọn lọc quy tắc này có thể quan tâm đến một tùy chọn mới được đề xuất cho no-param-reassignquy tắc sẽ cho phép "danh sách trắng" các tên đối tượng liên quan đến việc gán lại tham số sẽ bị bỏ qua.


Trên đây được đăng như một câu trả lời, thay vì bình luận, do thiếu điểm đại diện.
RH Becker




-1

Bạn có thể dùng:

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

1
Điều này không chỉ sửa đổi bản sao (làm thế nào mà có giá trị)?
2540625

1
Đây thực sự không phải là một giải pháp vì điều này có nghĩa là tránh gán lại tham số bằng cách tạo một đối tượng mới trong khi tôi rõ ràng không cần tạo một đối tượng mới mà sửa đổi đối tượng ban đầu.
Lukas

Tôi không muốn sửa đổi các tham số, nhưng bạn cũng có thể sử dụng Object.defineProperty () nếu bạn làm theo cách này, linter sẽ không báo lỗi cho bạn.
Oliver

Điều này sẽ không hoạt động ở tất cả. Bạn đang tạo một bản sao của biến, sao chép các thuộc tính từ nó vào một đối tượng mới, sửa đổi một thuộc tính và sau đó không trả lại nó, vì vậy không có gì xảy ra. Ngay cả khi bạn đã trả lại nó, bạn đang trả về một đối tượng, không phải phần tử DOM như những gì đã được chuyển vào. Trên hết, Object.assignlà để sao chép từ một đối tượng sang một đối tượng đích. Cố gắng sao chép từ một phần tử DOM như vậy dẫn đến một đối tượng trống.
Mã vô dụng

Plus Object.assignsẽ không hoạt động thích hợp nếu bạn đang cố gắng đánh giá lại một thuộc tính trên Object với các tham chiếu vòng (ví dụ: kết nối socket). Object.assigntheo mặc định là một bản sao cạn và nhân bản sâu rất khó chịu vì ảnh hưởng đến hiệu suất.
ILikeTacos

-1

Nếu bạn muốn thay đổi bất kỳ giá trị nào bên trong một mảng đối tượng, bạn có thể sử dụng

array.forEach(a => ({ ...a, expando: {} }))
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.