JavaScript 中给变量赋值

JavaScript 中给变量赋值

在JavaScript开发中,变量赋值是一个看似简单却容易让人误解的概念。很多开发者(包括曾经的我)可能会简单地认为所有变量赋值都是"复制"过程,或者都是"引用"过程。实际上,JavaScript中的变量赋值行为取决于数据类型。本文将详细解析JavaScript中不同数据类型的赋值机制,并通过代码示例和图表帮助你彻底理解这一重要概念。

内存模型图解

为了更直观地理解这些概念,让我们用Mermaid图表展示内存中的情况:

基本数据类型:复制过程

对于数字、字符串、布尔值等基本数据类型,JavaScript采用的是值复制的方式。

// 数字类型示例

var a = 3; // 声明变量a并赋值为3

var b = a; // 将a的值复制给b

b++; // b的值增加1

console.log(a); // 输出: 3 - a的值不受影响

console.log(b); // 输出: 4 - 只有b的值改变了

// 字符串类型示例

var c = 'string'; // 声明变量c并赋值为'string'

var d = c; // 将c的值复制给d

c += ' is String'; // 修改c的值

console.log(c); // 输出: 'string is String' - c的值已改变

console.log(d); // 输出: 'string' - d的值保持不变

从上面的例子可以看出,对于基本数据类型,变量赋值确实是创建了一个独立的副本,修改其中一个变量不会影响另一个变量。

引用数据类型:地址引用

对于对象(Object)和数组(Array)这样的引用数据类型,情况就不同了。JavaScript采用的是地址引用的方式。

// 数组类型示例

var arr = [1, 2, 3]; // 声明数组arr

var brr = arr; // brr和arr引用同一个数组

brr.push(4); // 通过brr修改数组

console.log(arr); // 输出: [1, 2, 3, 4] - arr也被修改了

console.log(brr); // 输出: [1, 2, 3, 4] - 两个变量指向同一个数组

// 对象类型示例

var obj = {a: 1, b: 2}; // 声明对象obj

var obj2 = obj; // obj2和obj引用同一个对象

obj.c = 3; // 通过obj添加新属性

console.log(obj); // 输出: {a: 1, b: 2, c: 3}

console.log(obj2); // 输出: {a: 1, b: 2, c: 3} - 两个变量指向同一个对象

这种情况下,变量实际上存储的是对内存中对象的引用(可以理解为地址),而不是对象本身的副本。因此,通过任何一个变量修改对象,都会影响到所有引用该对象的变量。

函数参数传递的特殊情况

当引用类型作为函数参数传递时,行为会有些微妙的变化:

var arr = [1, 2, 3]; // 原始数组

// 情况1:修改参数内部属性

function change(a) {

a.push(4); // 修改传入的数组

return a;

}

var brr = change(arr);

console.log(arr); // 输出: [1, 2, 3, 4] - 原数组被修改

console.log(brr); // 输出: [1, 2, 3, 4]

// 情况2:重新赋值参数

function set(a) {

a = [3, 2, 1]; // 给参数赋新值,改变了引用地址

return a;

}

var crr = set(arr);

console.log(arr); // 输出: [1, 2, 3, 4] - 原数组未被修改

console.log(crr); // 输出: [3, 2, 1] - 返回的是新数组

这里的关键区别在于:

如果只是修改参数内部的属性/元素,外部的变量会受到影响如果对参数进行重新赋值,则外部的变量不会受到影响,因为参数现在引用的是一个新的对象

实践:

基本数据类型(Number, String, Boolean等)赋值是值复制,修改不会相互影响引用数据类型(Object, Array等)赋值是地址引用,修改会相互影响函数参数传递:

修改参数内部属性会影响外部变量重新赋值参数不会影响外部变量

在实际开发中,为了避免意外的副作用,处理引用类型时可以考虑:

// 创建数组/对象的副本

var newArr = [...oldArr]; // 数组展开运算符

var newObj = {...oldObj}; // 对象展开运算符

var deepCopy = JSON.parse(JSON.stringify(complexObj)); // 深拷贝

// 函数内避免修改外部对象

function safeModify(obj) {

const localObj = {...obj}; // 创建副本

localObj.property = 'new value';

return localObj;

}

相关推荐

小米数据线保修期是多久?深度解析及维权指南
365彩票官方正版下载

小米数据线保修期是多久?深度解析及维权指南

📅 07-08 👁️ 3737
QQ宠物如何领养
365彩票官方正版下载

QQ宠物如何领养

📅 09-07 👁️ 6754
创维电视遥控器确认键是哪个,大家都通用的方法
BT365账户网址多少

创维电视遥控器确认键是哪个,大家都通用的方法

📅 07-09 👁️ 6952
什么是网络延迟
365彩票官方正版下载

什么是网络延迟

📅 09-20 👁️ 1002
家常炖梭鱼的做法
BT365账户网址多少

家常炖梭鱼的做法

📅 08-11 👁️ 396
所有火影忍者电影按顺序(完整指南)
365bet在线娱乐场

所有火影忍者电影按顺序(完整指南)

📅 08-02 👁️ 8025
洛克王国铁矿石可以买吗
BT365账户网址多少

洛克王国铁矿石可以买吗

📅 07-07 👁️ 9204
好看的丧尸片30部推荐排行榜
BT365账户网址多少

好看的丧尸片30部推荐排行榜

📅 07-28 👁️ 3861
TED演讲|我们为什么相爱?
365彩票官方正版下载

TED演讲|我们为什么相爱?

📅 08-20 👁️ 5495