JavaScript 变量:理解基元和引用类型

 

两种基本类型的数据存储在 javascript 中的变量中:基元引用类型。了解这两种类型之间的区别对于内存管理以及调节数据的共享、存储和更改至关重要。本文深入探讨了它们之间的区别,提供了现实世界的示例,并研究了有效处理这两种类型的方法。


1.基元与引用类型

原语

最简单的数据类型称为基元。它们直接将不可更改的数据存储在变量中。 javascript 支持的基本类型如下:

  • 字符串:“你好”
  • 数量:42
  • 布尔值:真或假
  • 未定义
  • 符号
  • bigint

主要特征:

  • 不可变:它们的值不能直接改变。
  • 按值存储。
参考类型

另一方面,引用类型存储对象的内存位置。变量不是存储实际值,而是保存对内存地址的引用。示例包括:

  • 对象:{名称:'爱丽丝'}
  • 数组:[1,2,3]
  • 函数: function() { console.log('hello'); }
  • 日期:新日期()

主要特征:

  • 可变:它们的内容可以修改。
  • 存储通过引用

2.实际操作中的基元和引用类型

// primitive example
let a = 10;
let b = a;
b = 20;
console.log(a); // output: 10

// reference example
let obj1 = { name: 'alice' };
let obj2 = obj1;
obj2.name = 'bob';
console.log(obj1.name); // output: 'bob'

 

说明
  • 原语:将 a 分配给 b 会创建该值的副本。更改 b 不会影响 a,因为它们是独立的。
  • 引用类型:obj1和obj2都指向相同的内存位置。通过 obj2 更改内容也会更新 obj1。

3.可视化概念

  • 基元:将每个变量想象成它自己的包含值的框。复制会创建一个具有独立值的新框。
  • 引用类型:将变量视为指向共享容器的标签。引用同一容器的所有标签都会受到其内容更改的影响。

4.变异与赋值

理解变异赋值之间的区别是使用引用类型时的关键。

突变:修改现有对象的内容。
let arr = [1, 2, 3];
let arr2 = arr;
arr2.push(4);
console.log(arr); // output: [1, 2, 3, 4]
赋值:更改对新对象的引用。
let arr = [1, 2, 3];
let arr2 = arr;
arr2 = [4, 5, 6];
console.log(arr); // output: [1, 2, 3]

5.复制对象和数组

浅复制

要创建对象或数组的单独副本,请使用扩展运算符 (...) 或 object.assign()。

let original = { name: 'alice' };
let copy = { ...original };
copy.name = 'bob';
console.log(original.name); // output: 'alice'
深复制

对于嵌套对象,需要深拷贝。一种常见的方法是使用 json.parse(json.stringify()).

let nested = { person: { name: 'alice' } };
let deepcopy = json.parse(json.stringify(nested));
deepcopy.person.name = 'bob';
console.log(nested.person.name); // output: 'alice'

6.按值传递与按引用传递

原语(按值传递)

将基元传递给函数时,会传递值的副本。

function modifyvalue(x) {
  x = 20;
}
let num = 10;
modifyvalue(num);
console.log(num); // output: 10
引用类型(通过引用传递)

传递引用类型时,会传递对内存位置的引用。

function modifyobject(obj) {
  obj.name = 'bob';
}
let person = { name: 'alice' };
modifyobject(person);
console.log(person.name); // output: 'bob'

7.原始包装类型

即使原语是不可变的,javascript 也会暂时将它们包装在对象中以允许访问方法和属性。

let str = 'hello';
console.log(str.length); // output: 5
说明

字符串原语“hello”临时包装在 string 对象中以访问 length 属性。包装在操作后被丢弃。


8.最佳实践

  1. 使用 const 作为引用类型: 使用 const 声明对象和数组可以防止重新分配,但允许内容发生变化。
const obj = { name: 'Alice' };
   obj.name = 'Bob'; // Allowed
   obj = { age: 25 }; // Error: Assignment to constant variable.

 

  1. 避免意外突变
    如果您需要独立副本,请确保使用扩展运算符或深度复制技术创建一个副本。

  2. 知道何时使用深层副本
    对于浅层对象,扩展运算符就足够了,但嵌套结构需要深层复制以避免引用问题。

  3. 利用不变性
    使用 immutable.js 等库或采用函数式编程技术来最大限度地减少意外突变引起的错误。


9.常见陷阱

  1. 混淆赋值与变异
    请注意您是在修改对象还是重新分配引用。

  2. 修改共享引用:
    如果程序的其他部分也使用共享对象,则对共享对象的更改可能会产生意想不到的后果。

  3. 假设所有副本都是独立的
    请记住,浅拷贝并不能防止嵌套结构发生变化。


结论

javascript 的核心思想之一是基元引用类型之间的区别。它会影响您向函数发送数据、管理变量以及防止代码中出现意外副作用的方式。通过掌握这些想法并使用最佳实践,您可以构建更可靠和可维护的 javascript 代码。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/917303.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【C++】—— stack和queue的模拟实现

前言 ​ stack 和 queue使用起来都非常简单,现在来模拟实现一下,理解其底层的原理。 ​ 在实现之前,应该知道,stack 和 queue 都是容器适配器,通过看官网文件也可以看出来;其默认的容器都是deque&#xff…

MuMu模拟器安卓12安装Xposed 框架

MuMu模拟器安卓12安装Xposed 框架 当开启代理后,客户端会对代理服务器证书与自身内置证书展开检测,只要检测出两者存在不一致的情况,客户端就会拒绝连接。正是这个原因,才致使我们既没有网络,又抓不到数据包。 解决方式: 通过xposed框架和trustmealready禁掉app里面校验…

Linux网络:守护进程

Linux网络:守护进程 会话进程组会话终端 守护进程setsiddaemon 在创建一个网络服务后,往往这个服务进程是一直运行的。但是对于大部分进程来说,如果退出终端,这个终端上创建的所有进程都会退出,这就导致进程的生命周期…

丹摩征文活动|丹摩平台一日游

目录 一.引言 二.平台简介 三.体验过程 1.注册与登录 (1).注册 (2).登录 2.界面介绍 (1).主界面 (2).任务监控界面 3.功能体验 (1).数据存储与管理 (2).数据预处理 (3).模型训练 (4).模型评估与优化 4.例子 (1).创建一个实例 (2).选择类型 1.实例配置 2.选择…

计算机网络中的数据包传输机制详解

💓 博客主页:瑕疵的CSDN主页 📝 Gitee主页:瑕疵的gitee主页 ⏩ 文章专栏:《热点资讯》 计算机网络中的数据包传输机制详解 计算机网络中的数据包传输机制详解 计算机网络中的数据包传输机制详解 引言 数据包的基本概念…

普通用户切换到 root 用户不需要输入密码配置(Ubuntu20)

在 Ubuntu 系统中,允许一个普通用户切换到 root 用户而不需要输入密码,可以通过以下步骤配置 sudo 设置来实现。 步骤: 打开 sudoers 文件进行编辑: 在终端中,输入以下命令来编辑 sudoers 文件: sudo visu…

入侵检测算法平台部署LiteAIServer视频智能分析平台行人入侵检测算法:科技守护安全的新篇章

在现代化城市快速发展的背景下,安全防范已成为城市管理与社会生活中不可或缺的一环。随着人工智能、大数据、物联网等技术的飞速发展,智能化安防系统正逐步改变着传统的安全防护模式,特别是在行人入侵检测领域,视频智能分析平台Li…

20.UE5UI预构造,开始菜单,事件分发器

2-22 开始菜单、事件分发器、UI预构造_哔哩哔哩_bilibili 目录 1.UI预构造 2.开始菜单和开始关卡 2.1开始菜单 2.2开始关卡 2.3将开始菜单展示到开始关卡 3.事件分发器 1.UI预构造 如果我们直接再画布上设计我们的按钮,我们需要为每一个按钮进行编辑&#x…

GoFly框架使用vue flow流程图组件说明

Vue Flow组件库是个高度可定制化的流程图组件,可用于工作流设计、流程图及图表编辑器、系统架构展示。可以根据自己的需求,设计独特的节点和边,实现个性化的流程图展示。这不仅增强了应用的视觉效果,也使得用户交互更为直观和流畅…

小白投资理财 - 看懂随机指标 KDJ

小白投资理财 - 看懂随机指标 KDJ 什么是 KDJKDJ 的组成计算 RSV计算 K 值计算 D 值J 值KDJ 的解读 KDJ 使用方式首先是 KD 线适合超买和超卖KD 线的黄金交叉线和死亡交叉线J 线J 线捉低点 KDJ 线注意点总结 身边总会有一位朋友在做选择上总是摇摆不定,做一个选择也…

Charles抓https包-配置系统证书(雷电)

1、导出证书 2、下载 主页上传资源中有安装包,免费的 openssl 安装教程自己搜 openssl x509 -subject_hash_old -in charles.pem 3、修改证书名、后缀改成点0 雷电打开root和磁盘写入 4、导入雷电证书根目录 证书拖进去,基本就完成了&#xff…

SobarQube实现PDF报告导出

文章目录 前言一、插件配置二、使用步骤1.新生成一个Token2.将拷贝的Token加到上文中执行的命令中3.查看报告 三、友情提示总结 前言 这篇博文是承接此文 .Net项目在Windows中使用sonarqube进行代码质量扫描的详细操作配置 描述如何导出PDF报告 众所周知,导出PDF功…

大数据实验9:Spark安装和编程实践

实验九:Spark基础编程1 一、实验目的 通过实验掌握基本的Spark编程方法;掌握用Spark解决一些基本的数据处理和统计分析,去重、排序等; 二、实验要求 掌握Spark相关shell命令的使用;完成下面的实验内容,…

主界面获取个人信息客户端方

主界面获取个人信息客户端方 前言 上一集我们完成了websocket身份验证的内容,那么这一集开始我们将要配合MockServer来完成主界面获取个人信息的内容。 需求分析 我们这边是完成客户端那方的内容,当客户端登录成功之后,我们就要从服务器获…

Git 分⽀规范 Git Flow 模型

前言 GitFlow 是一种流行的 Git 分支管理策略,由 Vincent Driessen 在 2010 年提出。它提供了一种结构化的方法来管理项目的开发、发布和维护,特别适合大型和复杂的项目。GitFlow 定义了一套明确的分支模型和工作流程,使得团队成员可以更有效…

极氪交付与整车营收双创新高,极氪汽车怎么做的?

在当前的新能源汽车市场上,新能源汽车的竞争已经白热化,各家新能源车企都面临巨大的压力,就在最近极氪的财报公布,交付与整车营收双创新高,极氪汽车是怎么做到的?极氪的未来我们又该怎么分析? 一…

HarmonyOS ArkUI(基于ArkTS) 开发布局 (上)

一 ArkUI(基于ArkTS)概述 基于ArkTS的声明式开发范式的方舟开发框架是一套开发极简、高性能、支持跨设备的UI开发框架,提供了构建应用UI所必需的能力 点击详情 特点 开发效率高,开发体验好 代码简洁:通过接近自然语义的方式描述UI&#x…

UE5 材质里面画圆锯齿严重的问题

直接这么画圆会带来锯齿,我们对锯齿位置进行模糊 可以用smoothstep,做值的平滑过渡(虽然不是模糊,但是类似)

[C++] 智能指针

文章目录 智能指针的使用原因及场景分析为什么需要智能指针?异常抛出导致的资源泄漏问题分析 智能指针与RAIIC常用智能指针 使用智能指针优化代码优化后的代码优化点分析 析构函数中的异常问题解决方法 RAII 和智能指针的设计思路详解什么是 RAII?RAII 的…

Python学习笔记(1)装饰器、异常检测、标准库概览、面向对象

1 装饰器 装饰器(decorators)是 Python 中的一种高级功能,它允许你动态地修改函数或类的行为。 装饰器是一种函数,它接受一个函数作为参数,并返回一个新的函数或修改原来的函数。 语法使用 decorator_name 来应用在…