本文章主要是想探索一下JavaScript中,对象类型的参数的传递方式
背景:
按值传递(call by value
)是最常用的求值策略:函数的形参是被调用时所传实参的副本。修改形参的值并不会影响实参。
按引用传递(call by reference
)时,函数的形参接收实参的隐式引用,而不再是副本。这意味着函数形参的值如果被修改,实参也会被修改。同时两者指向相同的值。
let set = new Set();
set.add({t:1});
set.has({t:1}); // false
let set = new Set();
let obj = {t:1};
set.add(obj);
set.has(obj); // ture
通过上面的代码可以显而易见的得出JavaScript
中对象类型的参数肯定不是值传递的。实际上,在JavaScript
中其它的数据的数据类型(undefined
、null
、Boolean
、String
、Number
)都是按值传递的。
再来看看对象的传递:
var obj = {x : 1};
function foo(o) {
o.x = 3;
}
foo(obj);
console.log(obj.x); // 3, 被修改了!
var obj = {x : 1};
function foo(o) {
o = 100;
}
foo(obj);
console.log(obj.x); // 仍然是1, obj并未被修改为100.
其实,对象类型的参数是按共享传递的(call by sharing
,也叫按对象传递、按对象共享传递)。
该策略的重点是:调用函数传参时,函数接受对象实参引用的副本(既不是按值传递的对象副本,也不是按引用传递的隐式引用)。 它和按引用传递的不同在于:在共享传递中对函数形参的赋值,不会影响实参的值。
总结:
基本类型是按值传递,而对于对象来说传入的是对象指向的地址,也可以认为其是特殊的按值传递。如果在函数内对对象的属性进行操作,实际就是对其指向对象的属性进行操作。但是,如果对其整体进行操作(比如:o = 100或者o = []),其实际是新定义了对象,实参的引用地址为新的对象的引用地址,与原来的引用没有任何关系,所以不会对原来的对象造成改变。
拓展:
那么怎么去判断两个对象相等呢?
最简单的办法是使用 JSON.stringify
将对象转换成字符串,然后再进行比较。