在Javascript中,有两种数据类型:原始类型(primitive types)和引用类型(reference types)。其中,原始类型包括undefined、null、boolean、number和string;引用类型则包括Object、Array、Function等。在使用JavaScript时,我们经常需要了解这些不同类型之间的传递方式。
原始类型与引用类型的区别
首先,我们来了解一下原始类型和引用类型的区别:
- 原始类型的值是存储在栈(stack)中的,而引用类型的值是存储在堆(heap)中的。
- 原始类型的变量直接保存值,而引用类型的变量保存的是一个地址,该地址指向堆中实际的对象。
由于这个区别,导致了原始类型和引用类型之间传递的方式也不同。
原始类型的传递方式
当我们将一个原始类型的值作为参数传递给函数或赋值给另一个变量时,该值会被复制到一个新的内存位置,其它变量只是对这个新的内存位置进行操作,不会影响原始值本身。例如:
let a = 1; let b = a; // 将a的值复制给b b = 2; // 修改b的值不会影响a的值 console.log(a); // 输出1
引用类型的传递方式
然而,当我们传递引用类型的值时,情况就有所不同了。因为引用类型的值是存储在堆中的,因此复制一个对象时,实际上并没有复制这个对象本身,而只是复制了一个指向该对象的引用。因此,当我们修改该对象时,所有指向该对象的引用都会发生相应的改变。例如:
let obj1 = { name: 'John', age: 20 }; let obj2 = obj1; // 复制obj1的引用给obj2 obj2.age = 30; // 修改obj2的属性,也会影响到obj1 console.log(obj1.age); // 输出30
如何避免引用类型的副作用
由于引用类型的传递方式可能会导致意外的副作用,因此在编写JavaScript代码时,需要特别注意。以下是一些避免引用类型副作用的方法:
使用Object.assign()进行对象复制。例如:
let obj1 = { name: 'John', age: 20 }; let obj2 = Object.assign({}, obj1); // 复制obj1的属性到新对象中 obj2.age = 30; // 只会修改obj2的属性 console.log(obj1.age); // 输出20
使用扩展运算符(...)进行对象复制。例如:
let obj1 = { name: 'John', age: 20 }; let obj2 = { ...obj1 }; // 复制obj1的属性到新对象中 obj2.age = 30; // 只会修改obj2的属性 console.log(obj1.age); // 输出20
使用Array.slice()或Array.concat()进行数组复制。例如:
let arr1 = [1, 2, 3]; let arr2 = arr1.slice(); // 复制arr1的元素到新数组中 arr2[0] = 4; // 只会修改arr2的元素 console.log(arr1[0]); // 输出1
使用Array.from()或扩展运算符(...)进行数组复制。例如:
let arr1 = [1, 2, 3]; let arr2 = Array.from(arr1); // 复制arr1的元素到新数组中 arr2[0] = 4; // 只会修改arr2的元素 console.log(arr1[0]); //
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/1561