Home

blackshh

纸上得来终觉浅,绝知此事要躬行。

Blog About Email Github

JavaScript 函数传参是按地址还是按值传递?

先从一道题入手

var setPerson = function(person){
    person.name = "kevin";
    person = {name:"rick"};
};
var person = {name:"alan"};
setPerson(person);
alert(person.name);

这道题一开始我以为结果会是 “rick”,后来觉得不会这么简单,会不会涉及到变量提升,
其实这个题结果是 “kevin”,惊不惊喜,意不意外?

想要弄懂这道题,必须要从Js的函数传参说起,这里有一个提问“Js函数是按值传递还是按地址传递?”
《js高级程序设计》上是这样叙述参数传递的:
所有函数的参数都是按值传递的,也就是说把函数外部的值复制给函数内部的参数,就和把值从一个变量复制到另一个变量一样。
这里有一个误区就是如果参数是对象(Object)的话,在一些情况下看起来好像是按地址传递的,比如:

var person = {
    name : "Tom"
};
function obj(peo){
    peo.name = "Jerry";
}
var result = obj(person);
console.log(person.name);// Jerry

通过函数里面对 peo.name 的修改,外部的person对象的name属性也发生了变化,这乍一看感觉参数就是按照引用传递的。
那我们再来看看这个例子:

var person = {
    name : "Tom"
};
function obj(peo){
    peo = {
        name : "Jerry"
    };
}
var result = obj(person);
console.log(person.name);// Tom

在这个例子中,person对象通过函数传递给peo,在函数内peo被重新赋值,如果是按地址传递,那person应该也被重新赋值了。
但结果中person.name 还是”Tom”,从这里就可以看出Js函数其实不是按地址传递的。但是本文中第二个例子是怎么回事呢?
想要弄明白这一点,就必须去了解“JS数据类型存储”。

JS有哪些数据类型?
JS包含量大数据类型,一种是基本数据类型(String、Number、Boolean、undefined、null);另外一种是引用类型(Object)。

数据的存储方式有哪些?

* 栈区:存放函数的参数值,局部变量的值(先进后出)
* 堆区:由程序员分配释放,分配方式类似链表(任意顺序)
* 全局区: 全局变量和静态变量
* 文字常量区: 常量
* 程序代码区:函数二进制码

JS中的基础类型和引用类型是怎么存储的?

基础类型的数据存储在栈区

var name = "Tom

引用类型的数据存储在堆区

var a = new Object()

了解到这里文章开始的那道题就很简单了,让我们回顾一下:

var setPerson = function(person){
    person.name = "kevin";
    person = {name:"rick"};
};
var person = {name:"alan"};
setPerson(person);
alert(person.name);

首先定义了一个person对象,栈内存中存了一个变量名person,它的值是person这个对象实际内存在堆内存中的地址,接下来执行setPerson,这里是把person对象的值传递给了形参,也就是把person对象在堆内存中的地址给赋给形参,接下来执行 person.name = “kevin”,修改堆内存中person对象name值,然后执行 person = {name:”rick”} 。这句话分为两部:第一,在堆内存中新建一个{name:”rick”}对象;第二,把形参重新指向了这个新的对象。
所以在alert(person.name)时,输出的是外侧person对象的name,结果是“kevin”。

总结

这道题还是很不错的,考查了几个基础的知识点,这些在实际开发中也是很有用的,如果你不了解Js函数的传值
在开发可能会掉进坑里。


blackshh

2018-07-21

Blog About Email Github