JS-参数对象新增方法
通常情况下,不会对函数中传入的参数进行修改操作,但是在编写通用函数,对元素进行新增方法(事件)的时候,可能会使用对参数的修改从而实现在引用对象上新增方法(事件)。
基本方法
直接将要新增的方法(事件)添加到元素上:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15function addHandler(element, type, handler) {
element[`on${type}`] = handler
}
function hohoho() {
alert('ohHoHoHo');
}
const Btn = {
color: 'blue'
}
addHandler(Btn, 'Say', hohoho);
Btn.onSay();
输出结果为:onHoHoHo弹窗
该方法执行没问题,但是在ESLint中配置了禁止对函数参数再赋值 (no-param-reassign)时,上面代码会报错。no-param-reassign
规范如下:
对函数参数中的变量进行赋值可能会误导读者,导致混乱,也会改变 arguments 对象。通常,对函数参数进行赋值并非有意为之,更多的是程序员的书写错误做成的。
当函数参数被修改时,该规则也可能会失效。由此造成的副作用可能导致不直观的执行流程,使错误难以跟踪。
下面有两种方式可以算很取巧的避免检测……
- 临时对象方式–会多创建一个引用。
- defineProperty方法–会修改原对象属性。
临时对象
虽然函数参数传递都是按值传递,但是element还是会按引用访问同一个对象,所以可以通过将参数赋值给临时对象,在临时对象上增加属性来避免报错。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15function addHandler2(element, type, handler) {
const ele = element;
ele[`on${type}`] = handler
}
function hohoho() {
alert('ohHoHoHo');
}
const Btn2 = {
color: 'blue'
}
addHandler2(Btn2, 'Say', hohoho);
Btn2.onSay();
defineProperty方法
使用ES5提供的属性定义方法修改传入对象1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16function addHandler1(element, type, handler) {
Object.defineProperty(element, `on${type}`, {
value: handler
});
}
function hohoho() {
alert('ohHoHoHo');
}
const Btn1 = {
color: 'blue'
}
addHandler1(Btn1, 'Say', hohoho);
Btn1.onSay();
如果有必要,可以设置新增属性的configurable
、enumerable
、writable
,如果不指定,这三个都为false
。
思考
js中参数按值传递,该规则的目的可理解为避免误将普通变量参数赋值导致与代码预期不一致,或者是修改了对象参数导致arguments改变,使得可读性变差。可以参考aribnb issue #766
但另一方面,例如在js红宝书中建立通用方法,对元素增加绑定事件时,使用了直接修改参数的方法。虽然违背了该规则,但是没有造成明显弊端,对此可以单独配置在该方法中此规则失效。
参考文章
ESLint 禁止对函数参数再赋值 (no-param-reassign)
How to avoid no-param-reassign when setting a property on a DOM object
How to deal with DOM manipulation #766