Last Surprise Lyn
  1. 1 Last Surprise Lyn
  2. 2 The Night We Stood Lyn
  3. 3 One Last You Jen Bird
  4. 4 Time Bomb Veela
  5. 5 Hypocrite Nush
  6. 6 Flower Of Life 发热巫女
  7. 7 Libertus Chen-U
  8. 8 かかってこいよ NakamuraEmi
  9. 9 Warcry mpi
  10. 10 Quiet Storm Lyn
  11. 11 Life Will Change Lyn
2016-12-31 20:13:14

剖析JavaScript中的传参策略

相信大家都或多或少在各种资料中看到JavaScript中的基本类型按值传参,对象按引用传参。但这句话真的是完全正确的吗?接下来我将逐步剖析其中的奥妙。


策略分类介绍

计算机科学中的传参策略可分为以下两类

  • 按值传递: 参数的值是传递值的拷贝,一般为参数分配了新的内存,两者值虽然相同,但相互不影响,生成独立的新值。
  • 按引用传递: 参数的值为传递值的引用地址,对参数的任何改变都会直接影响到原始值,也就是说参数相当于原始值的别名

那么在讨论JavaScript传参策略之前,我们必须知道,声明变量时存在两种不同的内存分配。

  • 原始值:存储在stack中的数据,访问时直接访问存储值的位置
  • 引用值:存储在stack中的指针,指向存储值在堆中的内存地址。

基本类型按原始值存储,对象按引用值存储。


JavaScript传参策略

首先我先下个结论,JavaScript中所有传参策略都是按值传递

那么为什么基本类型和引用类型仍然存在区别呢?其实是因为对象传参时,是一种按值传递的特殊类型——按共享传递。该策略本质上和按值传递相同,但传递的值却是原始值的引用地址。

以高程3上的一段经典代码为例

function setName(obj) {
    obj.name = 'Nicholas';
}
var person = new Object();
setName(person);
alert(person.name); //"Nicholas"

这段代码将person传参给obj,改变obj的name属性后person的name同时发生变化,看上去似乎是像按引用传递。

再看下面这段代码。

function setName(obj) {
    obj.name = 'Nicholas';
    obj = new Object();
    obj.name = 'Greg';
    }

    var person = new Object();
    setName(person);
    alert(person.name); //"Nicholas"

如果是按引用传递,person的name属性应该会变为Greg,实际上却没有变化,在这里用按共享传递的概念就可以很好的解释。

当person传参给obj时,两者分别在各自的stack位置中储存对象的引用地址,指向同一对象并将该对象的name属性设置为Nicholas。然后将新的对象的引用地址传递给obj,现在person和obj就各自拥有一份指向不同对象的引用地址了。所以可以分别改变属性而互不影响。

这样说下来可能还有点绕,我不妨下一个更直观的定义。

所谓按引用传递,就是传递变量本身,参数的指针指向变量名。按值传递,就是传递变量值,参数的指针指向实际变量。而这个实际变量的值如果是一个指针就是共享传递。

-- EOF --

添加在分类「 前端开发 」下,并被添加 「JavaScript」 标签。