返回

ECMAScript中变量的复制和函数参数的传递机制:透过现象看本质

前端

变量的复制和函数的参数传递是程序设计中经常遇到的基本概念,也是理解 ECMAScript 代码执行的关键所在。在 ECMAScript 中,变量的复制和函数的参数传递均遵循按值传递的原则,这意味着传递给函数的参数是栈内存中值的副本。这使得函数无法直接修改调用它的函数中的变量,同时,也确保了变量在函数之间的独立性。

变量的复制

在 ECMAScript 中,变量的复制实际上复制的是栈内存中的内容。对于原始值(例如数字、字符串和布尔值)来说,它们直接存储在栈内存中,因此复制操作非常简单,只需将栈内存中的值直接复制到另一个变量即可。例如:

let a = 10;
let b = a;

在上面的代码中,变量 ab 都指向栈内存中的同一个数字值 10。这意味着对 b 的任何修改都会同时影响 a

然而,对于引用值(例如对象和数组)来说,情况就有所不同了。引用值不直接存储在栈内存中,而是存储在堆内存中,而栈内存中只存储指向堆内存中对象的指针。因此,复制引用值时,实际上复制的是栈内存中的指针,而不是堆内存中的对象本身。例如:

let a = { name: 'John Doe' };
let b = a;

在上面的代码中,变量 ab 都指向堆内存中的同一个对象。这意味着对 b 的任何修改都会同时影响 a

函数的参数传递

在 ECMAScript 中,函数的参数传递遵从按值传递原则,这意味着传递给函数的参数是栈内存中值的副本。这使得函数无法直接修改调用它的函数中的变量,同时,也确保了变量在函数之间的独立性。例如:

function add(a, b) {
  return a + b;
}

let x = 10;
let y = 20;

let result = add(x, y);

在上面的代码中,add() 函数接受两个参数 ab,并且返回它们的和。当 add() 函数被调用时,栈内存中会创建两个新的变量 ab,并分别复制调用者提供的参数 xy 的值。这意味着 add() 函数只能修改栈内存中的 ab,而无法修改调用者提供的 xy 的值。

深拷贝与浅拷贝

在 ECMAScript 中,我们可以使用深拷贝或浅拷贝来复制对象或数组。深拷贝会复制对象或数组及其所有属性和元素,而浅拷贝只会复制对象或数组本身,而不复制其属性和元素。

let a = {
  name: 'John Doe',
  age: 30,
  address: {
    street: 'Main Street',
    city: 'New York',
    state: 'NY'
  }
};

let b = Object.assign({}, a); // 浅拷贝
let c = JSON.parse(JSON.stringify(a)); // 深拷贝

在上面的代码中,ba 的浅拷贝,这意味着 ba 都指向堆内存中的同一个对象。因此,对 b 的任何修改都会同时影响 a。而 ca 的深拷贝,这意味着 c 在堆内存中创建了一个新的对象,并复制了 a 的所有属性和元素。因此,对 c 的任何修改都不会影响 a

总结

在 ECMAScript 中,变量的复制和函数的参数传递均遵循按值传递原则,这意味着传递给函数的参数是栈内存中值的副本。对于原始值来说,复制操作非常简单,只需将栈内存中的值直接复制到另一个变量即可。对于引用值来说,复制操作实际上复制的是栈内存中的指针,而不是堆内存中的对象本身。函数无法直接修改调用它的函数中的变量,同时,也确保了变量在函数之间的独立性。我们可以使用深拷贝或浅拷贝来复制对象或数组,深拷贝会复制对象或数组及其所有属性和元素,而浅拷贝只会复制对象或数组本身,而不复制其属性和元素。