js中没有引用传递
在JavaScript中,参数传递的方式可以分为按值传递和按引用传递,但这个分类稍微有些误导。
更准确的说法是,所有参数都是按值传递的,但对于对象(包括数组和函数)来说,传递的是对象引用的副本。
这意味着如果你传递一个对象给函数,并且在函数内部修改了该对象的属性,那么这些改变会影响到原始对象,因为函数内部和外部的变量都指向同一个对象实例。
然而,如果你尝试在函数内部重新赋值这个引用(例如,将其指向一个新的对象),这种改变不会影响到原始的对象引用,因为只是改变了副本引用所指向的位置。
下面的例子可以帮助解释这一点:
function changeObject(obj) {
obj.property = 42; // 修改对象的属性会影响原始对象
obj = {}; // 尝试重新赋值obj,这不会影响到原始对象
obj.newProperty = "new"; // 这个新属性只会在新的空对象上创建
}
let myObj = {property: 0};
changeObject(myObj);
console.log(myObj.property); // 输出42
在这个例子中,myObj
的 property
属性被函数改变为 42,但是当尝试将 obj
重新赋值为一个新的空对象时,这个改变并不影响 myObj
,所以 newProperty
不会出现在 myObj
上。
ES6的模块导入导出,实际上是引用传递?
ES6模块系统中的导入(import)和导出(export)机制在处理变量、函数或类时,确实是以一种类似于引用传递的方式工作。但是,这并不完全等同于传统的引用传递概念,而更确切地说是通过绑定(binding)来实现的。
当你从一个模块中导出一个值并将其导入到另一个模块时,你实际上是在两个模块之间创建了一个对同一出口的绑定。这意味着如果导出的是一个可变对象(例如对象、数组或函数),那么对这个对象所做的任何变更都会反映在所有导入了该对象的地方,因为它们都指向同一个内存位置。然而,对于原始赋值操作(如重新分配一个新值给导入的变量),这种变化不会影响到其他模块,因为导入的只是导出值的一个绑定,而不是直接的引用。
这里有一个例子来说明:
// moduleA.js
export let counter = 0;
export function increase() {
counter++;
}
// moduleB.js
import { counter, increase } from './moduleA.js';
console.log(counter); // 输出0
increase();
console.log(counter); // 输出1
counter = 42; // 尝试重新赋值,这不会改变moduleA中的counter
在这个例子中,moduleB.js
导入了 counter
和 increase
函数。当调用 increase
函数时,它改变了 moduleA.js
中的 counter
的值,因此在 moduleB.js
中也能看到这个变化。
但是,如果你尝试在 moduleB.js
中重新赋值 counter
,这并不会影响 moduleA.js
中的 counter
的值,因为这只是一个局部的重新赋值操作,并不会更新原来的绑定。
需要注意的是,如果你导出的是一个不可变的原始类型(如数字、字符串、布尔值等),那么你实际上是复制了这个值,而不是创建了一个共享的引用。对于这些类型的值,更改将不会跨模块传播。