在 DOM 对象上设置属性时如何避免 no-param-reassign

Posted

技术标签:

【中文标题】在 DOM 对象上设置属性时如何避免 no-param-reassign【英文标题】:How to avoid no-param-reassign when setting a property on a DOM object 【发布时间】:2016-06-08 20:17:15 【问题描述】:

我有一个主要目的是在 DOM 对象上设置属性的方法

function (el) 
  el.expando = ;

我使用 AirBnB 的代码风格,这使得 ESLint 抛出 no-param-reassign 错误:

错误赋值给函数参数'el' no-param-reassign

如何操作作为参数传递的 DOM 对象,同时符合 AirBnB 的代码样式?

有人建议使用/* eslint react/prop-types: 0 */ 指代another issue,但如果我没记错的话,这适用于react,但不适用于本机DOM 操作。

我也不认为改变代码风格是一个答案。我相信使用标准样式的好处之一是在项目之间具有一致的代码,并且随意更改规则感觉就像对 AirBnB 等主要代码样式的滥用。

为了记录,我在 GitHub 上询问了 AirBnB,他们认为在这些情况下该怎么办in issue #766。

【问题讨论】:

不。首先,这意味着在该规则有意义的所有其他事件中禁用它。其次,我相信您要么遵循样式指南,要么不遵循。至少如果它是各种项目的许多开发人员遵循的风格指南。 但是你在问如何遵守风格指南,因为你正在做它试图阻止的事情。无论如何,只需disable it for that function How to disable ESLint react/prop-types rule in a fil?的可能重复 @Mathletics 不,我觉得这条规则很有意义,但它不适用于这种特定情况。我想知道是否有办法按照规则来做到这一点。 不管怎么说,你想要的操作都与规则冲突。也就是说,这似乎是一个 XY 问题。我不会像那样将属性直接附加到 DOM 节点。 【参考方案1】:

正如@Mathletics 建议的那样,您可以通过将其添加到您的.eslintrc.json 文件中来完全disable the rule:

"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

【讨论】:

谢谢。似乎大多数人发现修改 linter 是最好的方法。对我来说,将其应用于单行似乎是最好的折衷方案。 这真的很有意义,即对于 nodejs express 项目,有时您可能想立即修改 res.session 如果问题仅在于设置问题中所述的函数参数的属性,那么 Gyandeep 下面的答案要好得多。 谢谢@hiehiuehue:看起来他们把它拿下来了。删除链接。【参考方案2】:

作为this article explains,此规则旨在避免arguments object 发生变异。如果您分配给一个参数,然后尝试通过arguments 对象访问某些参数,则可能会导致意外结果。

您可以通过使用另一个变量来获取对 DOM 元素的引用,然后对其进行修改,从而保持规则不变并保持 AirBnB 样式:

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

在JS中对象(包括DOM节点)是通过引用传递的,所以这里eltheElement是对同一个DOM节点的引用,但是修改theElement不会改变arguments对象,因为@987654333 @ 仍然只是对该 DOM 元素的引用。

documentation for the rule 中暗示了这种方法:

此规则的正确代码示例:

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

function foo(bar) 
    var baz = bar;

就我个人而言,我只会使用"no-param-reassign": ["error", "props": false ] 方法提到的其他几个答案。修改作为参数传递的对象的属性不会更改对象引用,因此不应遇到此规则试图避免的问题。

【讨论】:

这应该是公认的答案,而不是规避行为的方法。由于这个答案和官方 ESLint 文档中所述的 Patric Bacon 指出了在某些情况下可能发生的明显问题:spin.atomicobject.com/2011/04/10/… 这个答案应该是公认的答案,因为它指向官方文档并且解释得很好。大多数其他答案就像关闭火警一样! 您可能会得到“局部变量 'theElement' 是多余的”。 修改参数的属性不会改变该参数所指的内容。,我认为对象是通过引用传递的!能详细点吗? 您在这里试图避免的“问题”实际上并不是问题。你永远不应该使用arguments 对象。相反,您应该使用rest parameters。因此可以安全地忽略 no-param-reassign。【参考方案3】:

您可以在 .eslintrc 文件中覆盖此规则,并为此类参数属性禁用它


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

这种方式规则仍然有效,但不会对属性发出警告。 更多信息:http://eslint.org/docs/rules/no-param-reassign

【讨论】:

这个答案不是完全包含在接受的吗? @DanDascalescu 在接受的答案下方有一条评论指向这个答案,所以也许它在某个时候被编辑过更全面?【参考方案4】:

no-param-reassign 警告对于常用函数是有意义的,但对于一个经典的 Array.forEach 循环,您打算改变它的数组是不合适的。

但是,为了解决这个问题,您也可以将Array.map 与新对象一起使用(如果您像我一样,不喜欢使用 cmets 发出打盹警告):

someArray = someArray.map((_item) => 
    let item = Object.assign(, _item); // decouple instance
    item.foo = "bar"; // assign a property
    return item; // replace original with new instance
);

【讨论】:

【参考方案5】:
function (el) 
  el.setAttribute('expando', );

其他一切都只是丑陋的黑客。

【讨论】:

【参考方案6】:

那些希望有选择地停用此规则的人可能会对proposed new option 的no-param-reassign 规则感兴趣,该规则将允许对象名称的“白名单”与哪些参数重新分配应被忽略。

【讨论】:

由于缺乏代表点,以上是作为答案而不是评论发布的。【参考方案7】:

您还可以使用 lodash assignIn 来改变对象。 assignIn(obj, someNewObj );

https://lodash.com/docs/4.17.2#assignIn

【讨论】:

【参考方案8】:

关注documentation:

function (el) 
  const element = el
  element.expando = 

【讨论】:

【参考方案9】:

如果您真的不想禁用规则,则可以使用更新的替代方法,例如:

function (el) 
  Object.defineProperty(el, 'expando',
    value: ,
    writable: true,
    configurable: true,
    enumerable: true
  );

参考:https://developer.mozilla.org/en-US/docs/Web/javascript/Reference/Global_Objects/Object/defineProperty

【讨论】:

【参考方案10】:

您可以使用方法来更新数据。例如。 “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;
);

【讨论】:

【参考方案11】:

根据 eslint (https://eslint.org/docs/2.0.0/rules/no-param-reassign) 的文档,我使用.eslintrc.js 文件中的以下书面配置解决了这个问题。

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

【讨论】:

【参考方案12】:

你可以使用:

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

【讨论】:

这不只是修改副本吗(这有什么价值)? 这并不是一个真正的解决方案,因为这意味着通过创建一个新对象来避免重新分配参数,而我明确需要不创建新对象而是修改原始对象。跨度> 我不喜欢修改参数,但是如果你这样做的话,你也可以使用 Object.defineProperty(),这样 linter 不会给你一个错误。 这根本行不通。您正在制作变量的副本,将其属性复制到新对象上,修改属性然后不返回它,因此没有任何反应。即使您确实返回了它,您也将返回一个对象,而不是像传入的那样的 DOM 元素。最重要的是,Object.assign 用于从对象复制到目标对象。尝试从这样的 DOM 元素中复制会导致空对象。 Plus Object.assign 如果您尝试使用循环引用(例如套接字连接)重新分配 Object 上的属性,则将无法正常工作。 Object.assign 默认是浅拷贝,深克隆因为性能下降非常不受欢迎。

以上是关于在 DOM 对象上设置属性时如何避免 no-param-reassign的主要内容,如果未能解决你的问题,请参考以下文章

DOM 文档对象模型

javascript教程系列43: DOM对象的dataset属性方式

如何在尚未在 DOM 中的元素上使用 jQuery 设置数据属性?

如何在 JS 和 DOM 中创建元素、设置属性、使用 innerHTML 和 appendChild

创建句柄对象数组作为对象属性时如何避免Matlab花费指数时间

回流与重绘