函数实参为对象时的陷阱
1. 正文
上周在实现某个弹层功能的时候,用到了rc-util里的 contains 方法函数, 结果 code-review 的时候同事对该代码提出了疑问:
export default function contains(root, n) {
let node = n;
while (node) {
if (node === root) {
return true;
}
node = node.parentNode;
}
return false;
}上述代码是 antd 内部抽象的一个工具方法,用来判断某个dom是否为另一个dom的祖先节点。
同事疑问的是 let node = n; 这段代码是不是多余的?
首先一开始的理解是 函数参数 n 是一个对象,一个dom节点对象。
如果用 node 保存 n 的值,防止 node = node.parentNode 这段代码执行的时候,会改变传入的实参 n 对应的值。
毕竟以下的代码我们都很熟悉:
function contains(root, n) {
if(n) {
n.a = 3
}
}
const A = {a:1};
const B = {a:2};
contains(A,B)
console.log(B) // {a:3}即当实参为对象时,函数内部是可以改变该对象的值从而影响函数之外的实参。
但是测试另外一段代码,发现和理解的不一样:
function contains(root, n) {
if(n) {
n = {a:3}
}
}
const A = {a:1};
const B = {a:2}
contains(A,B)
console.log(B) // {a:2}即 n.a = 3 和 n = {a:3} 这两段代码是不一样的。
网上也有相关资料,其实可以简单的理解为: 当函数一开始执行时,n 是指向实参 B 的一个引用.
n.a = 3 是在引用上再关联了一个属性,此时和 B 还是同一个引用,因此会改变实参B的值。
而 n = {a:3} 则使得 n 不再指向实参 B, 而是指向一个新对象{a:3},也就是 n 与 B 彻底断绝了关系,因此不会改变实参 B 的值。
是不是可以给蚂蚁的团队提个issue建议删除该代码,不过有这句代码也不会有什么bug 该行代码可能是为了符合 eslint 规范: 不对函数的参数进行赋值. 链接
2. 相关资料
Last updated
Was this helpful?