JavaScript函数的传参
JavaScript 中的函数传参是按值传递还是按引用传递呢?
ECMAScript 中所有函数的参数都是按值传递的。
摘自 JavaScript高级程序设计
下面我们看一段代码
function changeStuff(a, b, c) {
a = a * 10;
b.item = "changed";
c = {item: "changed"};
}
var num = 10;
var obj1 = {item: "unchanged"};
var obj2 = {item: "unchanged"};
changeStuff(num, obj1, obj2);
console.log('num: 'num);
console.log('obj1: 'obj1.item);
console.log('obj2: 'obj2.item);
复制代码
打印出来的值是:
num: 10
obj1: {item: "changed"}
obj2: {item: "unchanged"}
复制代码
说好的按值传递为什么 obj1 的值变了。
在继续了解 JavaScript 的函数是怎么传参之前,先简单了解一下 JavaScript 中是数据类型。
数据类型
JS中有7种数据类型,6种基本数据类型(Undefined, Null, Boolean, Number, String, Symbol)和一种复杂数据类型(Object)。
除 Object 以外的所有类型都是不可变的(值本身无法被改变)。
基本数据类型
基本数据类型就是数字、字符串、布尔值、还有两个比较特殊的 null 和 undefined,以及 ES6 新增的 symbol 。
- 基本数据类型的值是按值访问的;
- 基本类型的值是不可变的;
- 基本数据类型比较是按值进行比较。
引用数据类型
除了上面的六种数据类型之外,其他的都是引用类型,统称为 Object 类型,主要细分为Object、Array、Date、RegExpd等。
- 基本数据类型的值是按引用访问的;
- 引用数据类型是可变的;
- 引用数据类型是按引用访问的。
下面我们来看一段代码:
var obj1 = {name: "hello world"};
var obj2 = {name: "hello world"};
var obj3 = obj1;
console.log(obj1 === obj2); // 1
console.log(obj1 === obj3); // 2
obj3.name = "hello javascript";
console.log(obj1.name); // 3
复制代码
obj1 和 obj2 指向的是不同内存地址,obj1 和 obj3 指向的是同一个内存地址。
所以第一个打印的结果应该是 false ,obj1 和 obj2 的引用地址不同,第二个打印结果为 true,obj1 和 obj3 的引用地址相同。 第三个打印结果为 'hello javascript', 修改 obj3 其实就是修改了其指向的对象的值,所以 obj1 也发生了变化。
函数的传参
下面我们再来看看执行了 changeStuff 之后发生了什么吧。
changeStuff 执行之后就是对 changeStuff 中的三个形参进行了一次赋值操作,相当于:
a = num;
b = obj1;
c = obj2;
复制代码
(function (a) {
var a = 10;
console.log(1, a);
})(20);
(function () {
var a = 10;
console.log(2, a);
function a() {};
})();
(function (a) {
console.log(3, a);
function a() {};
})(20);
复制代码
你可以复制这段代码到浏览器的控制台中看一下执行结果,下面是执行结果:
1 10
2 10
3 ƒ a() {}
复制代码
由此三段代码可以看出来:
传入的参数是相当于声明在函数的最顶部,还在提升的函数之前。(后声明的变量的值覆盖了前面的值)
总结
ECMAScript 中所有函数的参数都是按值传递的,对于引用类型的值传递的是当前对象的引用,即一个堆内存的地址。