理解JavaScript中的变量、范围和提升

2023-05-16

变量是许多编程语言的基本组成部分,也是新手需要学习的第一个也是最重要的概念。JavaScript中有许多不同的变量属性,以及命名变量时必须遵循的一些规则。在JavaScript中,有三个关键字用于声明变量——var、let和const——每个关键字都会影响代码对变量的不同解释。

本教程将介绍什么是变量,如何声明和命名变量,并进一步研究var、let和const之间的区别。我们还将回顾提升的影响以及全局和局部作用域对变量行为的重要性。

理解变量

变量是用于存储值的命名容器。我们可能多次引用的一条信息可以存储在一个变量中,供以后使用或修改。在JavaScript中,变量中包含的值可以是任何JavaScript数据类型,包括数字、字符串或对象。

在今天的JavaScript所基于的ECMAScript 2015 (ES6)语言规范之前,只有一种方法来声明变量——使用var关键字。因此,大多数较老的代码和学习资源将只对变量使用var。我们将在下面单独一节讨论var、let和const关键字之间的区别。

我们可以使用var来演示变量本身的概念。在下面的示例中,我们将声明一个变量,并为其赋值。

// Assign the string value Sammy to the username identifier
var username = "sammy_shark";

本声明由以下几部分组成:

  • 使用var关键字声明变量

  • 变量名(或标识符),用户名

  • 赋值操作,由=语法表示

  • 分配的值“sammy_shark”

现在我们可以在代码中使用username。JavaScript将记住username表示字符串值sammy_shark。

// Check if variable is equal to value
if (username === "sammy_shark") {
  console.log(true);
  }

输出:

true

如前所述,变量可以用来表示任何JavaScript数据类型。在本例中,我们将使用字符串、数字、对象、布尔值和null值声明变量。

// Assignment of various variables
var name = "Sammy";
var spartans = 300;
var kingdoms = [ "mammals", "birds", "fish" ];
var poem = { roses: "red", violets: "blue" }; 
var success = true;
var nothing = null;

使用console.log,我们可以看到特定变量中包含的值。

// Send spartans variable to the console
console.log(spartans);

输出:300

变量将数据存储在内存中,稍后可以访问和修改这些数据。变量也可以重新分配,并给定一个新值。下面的简化示例演示了如何将密码存储到变量中,然后进行更新。

//为password变量赋值
var password = "hunter2";
//用一个新值重新分配变量值
password = "hunter3";
console.log(password);

输出:

'hunter3'

在实际的程序中,密码很可能安全地存储在数据库中。然而,这个例子说明了一种情况,在这种情况下,我们可能需要更新变量的值。password的值是hunter2,但是我们将其重新分配给了hunter3,这是JavaScript从那时起可以识别的值。

命名变量

变量名在JavaScript中称为标识符。我们讨论了在理解JavaScript语法和代码结构时命名标识符的一些规则,总结如下:

  • 变量名只能由字母(a-z)、数字(0-9)、美元符号($)和下划线(_)组成

  • 变量名不能包含任何空白字符(制表符或空格)

  • 数字不能是任何变量的名称开头

  • 保留的关键字不能用作变量的名称

  • 变量名区分大小写

JavaScript还习惯在使用var或let声明的函数和变量的名称中使用驼峰大小写(有时作为驼峰大小写进行样式化)。这是一种将第一个单词小写,然后将后面每个单词的第一个字母大写,中间没有空格的做法。除了一些例外,大多数非常量的变量都遵循这种约定。使用const关键字声明的常量变量的名称通常都是大写的。

这可能看起来像要学习很多规则,但很快就会成为编写有效和常规变量名称的第二天性。

var、let和const之间的区别

JavaScript有三个不同的关键字来声明变量,这给语言增加了额外的复杂性。三者之间的区别是基于范围、提升和重新分配。

关键字范围变量提升可以重新分配可以重新定义
var功能范围YesYesYes
let阻止范围NoYesNo
const阻止范围NoNoNo

您可能想知道应该在自己的程序中使用这三种方法中的哪一种。一个普遍接受的做法是尽可能多地使用const,并在循环和重新分配的情况下使用let。通常,在处理遗留代码之外可以避免var。

变量作用域

JavaScript中的作用域是指代码的当前上下文,它决定了变量对JavaScript的可访问性。范围的两种类型是局部的和全局的:

  • 全局变量是在块之外声明的变量

  • 局部变量是在块内声明的变量

在下面的示例中,我们将创建一个全局变量。

//初始化一个全局变量
var creature = "wolf";

我们知道变量可以重新分配。使用局部作用域,我们实际上可以创建与外部作用域中的变量同名的新变量,而无需更改或重新分配原始值。

在下面的示例中,我们将创建一个全局species变量。函数内部是一个具有相同名称的局部变量。通过将它们发送到控制台,我们可以看到变量的值如何根据范围而不同,并且原始值不会更改。

//初始化一个全局变量
var species = "human";
function transform() {
//初始化一个局部的、函数作用域的变量
  var species = "werewolf";
  console.log(species);
}
//记录全局和局部变量
console.log(species);
transform();
console.log(species);

输出:

human
werewolf
human

在本例中,局部变量是函数作用域的。使用var关键字声明的变量总是函数作用域,这意味着它们将函数识别为具有独立作用域。因此,这个局部作用域的变量不能从全局作用域访问。

然而,新的关键字let和const是块范围的。这意味着从任何类型的块(包括函数块、if语句、for和while循环)创建一个新的本地范围。

为了说明函数作用域变量和块作用域变量之间的区别,我们将使用let在if块中分配一个新变量。

var fullMoon = true;
//初始化一个全局变量
let species = "human";
if (fullMoon) { 
//初始化一个块范围的变量
  let species = "werewolf";
  console.log(`It is a full moon. Lupin is currently a ${species}.`);
}
console.log(`It is not a full moon. Lupin is currently a ${species}.`);

输出:

It is a full moon. Lupin is currently a werewolf.
It is not a full moon. Lupin is currently a human.

在此示例中,species变量具有一个值global(human),另一个值local(werewolf)。var但是,如果我们使用,则会有不同的结果。

//使用var初始化一个变量
var species = "human";
if (fullMoon) {  
//尝试在一个块中创建一个新变量
  var species = "werewolf";
  console.log(`It is a full moon. Lupin is currently a ${species}.`);
}

console.log(`It is not a full moon. Lupin is currently a ${species}.`);

输出:

It is a full moon. Lupin is currently a werewolf.
It is not a full moon. Lupin is currently a werewolf.

在这个例子的结果中,全局变量和块范围的变量都以相同的值结束。这是因为您不是使用var创建一个新的本地变量,而是在相同的范围内重新分配相同的变量。var不能识别是否属于不同的新范围。通常建议声明块范围的变量,因为它们生成的代码不太可能无意中覆盖变量值。

变量提升

到目前为止,在大多数示例中,我们已经使用var声明了一个变量,并使用一个值初始化了它。在声明和初始化之后,我们可以访问或重新分配变量。

如果我们试图在变量被声明和初始化之前使用它,它将返回undefined。

//在声明变量之前尝试使用它
console.log(x);
/ /变量赋值
var x = 100;

输出:

undefined

但是,如果省略var关键字,就不再声明变量,而是初始化它。它将返回一个ReferenceError并停止脚本的执行。

//在声明变量之前尝试使用它
console.log(x);
//没有var的变量赋值
x = 100;

输出:

ReferenceError: x is not defined

原因在于提升,这是JavaScript的一种行为,其中变量和函数声明被移到它们作用域的顶部。由于只挂起实际声明,而没有初始化,因此第一个示例中的值返回未定义的值。

为了更清楚地演示这个概念,下面是我们编写的代码以及JavaScript如何解释它。

// The code we wrote
console.log(x);
var x = 100;
// How JavaScript interpreted it
var x;
console.log(x);
x = 100;

JavaScript在执行脚本之前将x保存为内存作为变量。 由于它在定义之前仍然被调用,因此结果是未定义的而不是100.但是,它不会导致ReferenceError并停止脚本。

尽管var关键字实际上并未更改var的位置,但这有助于表示提升的工作原理。 但是,这种行为可能会导致问题,因为编写此代码的程序员可能希望x的输出为true,而不是undefined。

在下一个例子中,我们还可以看到提升是如何导致不可预测的结果的:

//在全局范围内初始化x
var x = 100;
function hoist() {
//不应影响编码结果的条件
  if (false) {
      var x = 200;
  }
  console.log(x);
}

hoist();

输出:

undefined

在本例中,我们声明x全局为100。根据if语句,x可以更改为200,但是由于条件为false,所以它不应该影响x的值。

这种不可预测的行为可能会在程序中引起bug。由于let和const是块范围的,所以它们不会以这种方式提升,如下所示。

//在全局范围内初始化x
let x = true;function hoist() {
//在函数作用域中初始化x
 if (3 === 4) {
      let x = false;
  }
  console.log(x);
}

hoist();

输出:

true

变量的重复声明(这在var中是可能的)将在let和const中抛出一个错误。

//试图覆盖用var声明的变量
var x = 1;
var x = 2;

console.log(x);

输出:2

//试图覆盖用let声明的变量
let y = 1;
let y = 2;

console.log(y);

输出:

Uncaught SyntaxError: Identifier 'y' has already been declared

总之,使用var引入的变量有可能受到提升的影响,提升是JavaScript中的一种机制,其中变量声明被保存到内存中。这可能导致代码中出现未定义的变量。let和const的引入解决了这个问题,它在试图在声明变量之前使用该变量或多次声明该变量时抛出一个错误。

常量

许多编程语言都有常量,这些常量是不能修改或更改的值。在JavaScript中,const标识符是根据常量建模的,不能重新分配分配给const的值。

将所有const标识符都写成大写是常见的约定。这将它们与其他变量值区分开来。

在下面的示例中,我们使用const关键字将变量SPECIES初始化为常量。试图重新分配变量将导致错误。

//给const赋值
const SPECIES = "human"; 

//尝试重新分配值
SPECIES = "werewolf";

console.log(SPECIES);

输出:

Uncaught TypeError: Assignment to constant variable.

因为不能重新分配const值,所以需要同时声明和初始化它们,否则也会抛出错误。

//声明,但不初始化const
const TODO;

console.log(TODO);

输出:

Uncaught SyntaxError: Missing initializer in const declaration

不能在编程中更改的值称为不可变值,而可以更改的值是可变的。虽然const值不能重新分配,但是它们是可变的,因为可以修改用const声明的对象的属性。

//创建一个具有两个属性的CAR对象
const CAR = {
    color: "blue",
    price: 15000}
//修改CAR的属性
CAR.price = 20000;

console.log(CAR);

输出:

{ color: 'blue', price: 20000 }

常量非常有用,可以让将来的自己和其他程序员清楚地认识到,不应该重新分配预期的变量。如果您希望将来修改某个变量,那么您可能希望使用let来声明该变量。

想要了解更多前端知识,可访问 前端开发学习!!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

理解JavaScript中的变量、范围和提升 的相关文章

  • 暂停除了已激活的玩家之外的所有其他玩家。

    我有这个插件 它可以将不同的样式应用于 html5
  • 将鼠标悬停时的鼠标光标更改为锚状样式

    如果我将鼠标悬停在div鼠标光标将更改为 HTML 锚点中的光标 我怎样才能做到这一点 假设你的div has an id myDiv 将以下内容添加到您的 CSS 中 这cursor pointer指定光标应与用于锚点 超链接 的手形图标
  • Chart.js 在初始化时设置活动段

    我正在使用 Chart js v2 并且尝试在加载图表时模拟圆环图上某个段的 悬停状态 因此看起来有一个部分已突出显示 我已经搜索和梳理了代码一天 但找不到一个好的方法来做到这一点 提前致谢 设置片段的悬停样式有点令人困惑 因为它没有真正记
  • 在新的 Google 协作平台 <嵌入 HTML> 中使用 localStorage 和 IndexedDB 不起作用

    我正在尝试将新的 Google 协作平台用于我开发的网页 但是 我在存储本地数据时遇到了问题 本地文件在 Windows 和 Apple safari chrome 中运行良好 从 Google 协作平台尝试一下 没有什么乐趣 此外 在 s
  • Draggable JS Bootstrap 模式 - 性能问题

    对于工作中的项目 我们在 JavaScript 中使用 Bootstrap Modal 窗口 我们想让一些窗口可移动 但我们遇到了 JQuery 的性能问题 myModal draggable handle modal header Exa
  • 防止 iOS 键盘在 cordova 3.5 中滚动页面

    我正在使用 Cordova 3 5 和 jQuery mobile 构建 iOS 应用程序 我在大部分应用程序中禁用了滚动功能 但是 当我选择输入字段时 iOS 键盘会打开并向上滚动页面 我不想要这个功能 由于输入足够高 键盘不会覆盖它 我
  • 尝试将数据存储在点击器网站中

    我正在尝试存储一个名为的变量score无论何时刷新 您都会一次又一次地使用它 我不明白的是它的代码是什么 我尝试了一些方法 但似乎都不起作用 这是我的答题器网站 但是当我尝试使用 JavaScript 来存储它时 它不起作用window o
  • 刷新页面时保存用户的选择

    我目前有一个页面显示不同团队的数据 我有一些数据 用户可以单击使其处于 打开 或 关闭 状态 并为每个数据显示不同的图标 它基本上就像一个清单 只是没有物理复选框 我想记住哪些 复选框 已被选中 即使在用户刷新页面或关闭浏览器并稍后返回之后
  • DataTables row.add 到特定索引

    我正在替换这样的行项目 var targetRow entity row dataTable targetRow closest table dataTable DataTable dataTable row targetRow remov
  • Vuejs 2:去抖动不适用于手表选项

    当我在 VueJs 中反跳此函数时 如果我提供毫秒数作为原语 它就可以正常工作 但是 如果我将其提供为对 prop 的引用 它会忽略它 这是道具的缩写版本 props debounce type Number default 500 这是不
  • Firebase 函数 onWrite 未被调用

    我正在尝试使用 Firebase 函数实现一个触发器 该触发器会复制数据库中的一些数据 我想观看所有添加的内容votes user vote 结构为 我尝试的代码是 const functions require firebase func
  • 从数据库检查数据的异步解决方案各种循环子句

    我想要做的是异步检查数据库并从中获取结果 在我的应用程序中我试图实现Asynchronously将此步骤解决为 从数据库中检查手机号码JsonArray循环子句的种类 Create JsonArray从结果 打印创建的数组 我学到了足够多的
  • Three.js 各种大小的粒子

    我是 Three js 的新手 正在尝试找出添加 1000 个粒子的最佳方法 每个粒子都有不同的大小和颜色 每个粒子的纹理是通过绘制画布创建的 通过使用粒子系统 所有粒子都具有相同的颜色和大小 为每个粒子创建一个粒子系统是非常低效的 有没有
  • 在 JavaScript 循环之外声明变量可以提高速度和内存?

    C 也有类似的问题 但我们没有看到 JavaScript 的任何问题 在循环内声明变量是否可以接受 假设循环有 200 次迭代 使用样本 2 相对于样本 1 是否有性能要求 内存和速度 我们使用 jQuery 来循环 它提高了我们将 var
  • 在 Shopify 商店中嵌入 Vue 组件

    在产品页面中 我尝试显示自定义 Vue 组件 为简洁起见 该组件根据给定的产品 ID 显示 Firebase 数据库中的一些信息 我最初尝试将其制作为 Shopify 应用程序 以便我可以访问他们的 API 我实现了 OAuth 并且可以检
  • 带参数的事件监听器

    我想将参数传递给 JavaScript 中的事件侦听器 我已经找到了解决方案 但我无法理解它们为什么或如何工作以及为什么其他解决方案不起作用 我有 C C 背景 但是 Javascript 函数的执行有很大不同 您能否帮助我理解以下示例如何
  • 用于交互式图形绘制的轻量级 JavaScript 库? [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我有兴趣了解用于绘制交互式图表的最轻量级 javascript 库 我掌握的数据主要是与海洋研究相关的科学数据 我知道一些 jquery
  • 从 FileReader 设置背景图像样式

    我正在寻找一种解决方案 允许我从文件上传输入中获取文件并通过设置 document body style backgroundImage 来预览它 以下代码用于在 Image 元素中显示预览 function setImage id tar
  • Jquery - 选择选项后如何获取选项的特定数据类型?

    我将直接跳到标记 然后解释我想要做什么 HTML 选择选项
  • 如何在react-highcharts中使用图表工具提示格式化程序?

    如何使用图表工具提示格式化程序 我正在使用高图表的反应包装器 我有这样的配置 const CHART CONFIG tooltip formatter tooltip gt var s b this x b each this points

随机推荐

  • 如何巧用 canvas(画布)为图片加水印?

    在前端中 xff0c 如何巧用 canvas xff08 画布 xff09 为图片加水印 xff1f 下面本篇文章就来给大家介绍一下使用 canvas 给图片添加水印的方法 有一定的参考价值 xff0c 有需要的朋友可以参考一下 xff0c
  • EKF(扩展卡尔曼滤波)参数理解

    EKF VELNE NOISE xff1a 速度在坐标轴 NE 方向上的噪声 通常是在 0 上下波动 设置方法 xff1a 将飞机上电静置若干分钟 xff08 时间尽量长一点 xff09 记录飞 行日志 xff0c 由 EKF3 的 IVN
  • 详解HTML文档声明(DOCTYPE)

    HTML文档通常以类型声明开始 xff0c 该声明将帮助浏览器确定其尝试解析和显示的HTML文档类型 本文将详细介绍文档声明DOCTYPE 特点 文档声明必须是HTML文档的第一行 且顶格显示 xff0c 对大小写不敏感 因为任何放在DOC
  • CSS 不定宽高的垂直水平居中(9种方法)

    垂直居中 xff0c 在 CSS 中是一个老生常谈的问题 xff0c 面试的时候也会时常被提及 所以 xff0c 今天我们就来聊聊 9 种不同的居中方法 有常见的 flex transform absolute 等等 也有 CSS3 的网格
  • html5不常用标签应用场景

    作为一个前端开发 xff0c 在浏览别人家的页面时总是会习惯性的查看他们页面的源码 xff0c 发现大多数网站的页面 xff0c 包括我自己写的页面中用到的最多的布局元素无外乎就是div p span ul dl ol li dt dd s
  • HTML的16个全局属性介绍

    在HTML中 xff0c 属性能表达相当丰富的语义 xff0c 而且属性也会额外提供很多实用的功能 xff0c HTML共支持16个常见的全局属性 HTML原有属性 accesskey 作用 xff1a 浏览器用来创建激活或聚焦元素的快捷键
  • 聊聊JavaScript作用域

    几乎所有的语言都有作用域的概念 xff0c 简单的说 xff0c 作用域就是变量和函数的可访问范围 xff0c 即作用域控制在变量和函数的可见性和生命周期 变量作用域 是程序源代码中定义这个变量的区域 1 全局变量拥有全局作用域 xff0c
  • CSS布局方案大全【整理】

    我们在日常开发中经常遇到布局问题 xff0c 下面罗列几种常用的css布局方案话不多说 xff0c 上代码 xff01 居中布局 以下居中布局均以不定宽为前提 xff0c 定宽情况包含其中 1 水平居中 a inline block 43
  • 你必须知道的一些HTML优化技巧

    如何提升Web页面的性能 xff0c 很多开发人员从多个方面来下手如JavaScript 图像优化 服务器配置 xff0c 文件压缩或是调整CSS 很显然HTML 已经达到了一个瓶颈 xff0c 尽管它是开发Web 界面必备的核心语言 HT
  • 常见的CSS图形绘制合集

    展示40多个常见的纯CSS绘制图形 xff0c 效果实时 xff0c 含源代码 xff0c 想要什么效果直接复制粘贴就好了 就算项目用不到 xff0c 看看别人代码怎么写的也有助于提高CSS的基本功 以下这些造型简单的图形都是纯CSS外加一
  • 扩展Vue.js组件

    您的Vue应用程序中是否有共享类似选项的组件 xff0c 甚至模板标记 使用公共选项和标记创建基本组件 xff0c 然后扩展基本组件以创建子组件 xff0c 这是一个好主意 这样的体系结构将帮助您在代码中应用DRY原则 不要重复您自己 xf
  • Node.js日志记录指南

    当你开始用 JavaScript 进行开发时 xff0c 可能学到的第一件事就是如何用 console log 将内容记录到控制台 如果你去搜索如何调试 JavaScript xff0c 会发现数百篇博文和 StackOverflow 文章
  • 软件测试的测试方法及测试流程

    一 测试方法 xff1a 白盒测试 xff1a 把软件比作一个打开的盒子 xff0c 可以看到软件代码的实现 xff0c 针对代码的实现验证代码是否存在问题 单元测试阶段采用的测试方法 灰盒测试 xff1a 介于白盒和黑盒测试之间 灰盒测试
  • 18个用于创建漂亮图表的JavaScript库推荐

    几乎不可能想象没有图形和图表的任何仪表盘 它们快速有效地呈现复杂的统计数据 此外 xff0c 一个好的图表还可以增强网站的整体设计 在本文中 xff0c 我将向您展示一些用于图形和图表的最佳JavaScript库 这些库将帮助您为将来的项目
  • JavaScript基础--引用数据类型 (对象)

    本文主要讲述了JavaScript对象的属性和对象的引用 xff0c 以及对象的读取 赋值 删除和获取对象键名的操作 1 对象 对象就是一组 键值对 xff08 key value xff09 的集合 xff0c 是一种无序的复合数据集合
  • javascript面向对象设计

    javascript和java语言不一样 xff0c 它没有类这个说法 xff0c 更没有子类父类一说 xff0c 所以它所谓的继承机制 xff0c 也是和其他语言完全不同的 创建对象三种方式 1 最简单的方式 xff0c 创建一个obje
  • 关键CSS和Webpack:自动最小化渲染阻止CSS

    消除渲染阻止的JavaScript和CSS 这是我始终坚持使用的Google Page Speed Insights建议 Google建议您在页面加载准备就绪时将最初需要的CSS 内插 CSS内嵌并加载CSS的其余部分 当访问web页面时
  • 如何用SASS编写可重用的CSS

    Sass是一个CSS预处理程序 xff0c 它在前端工程师的工具箱中变得至关重要 Sass之所以流行 xff0c 是因为它修复了几个CSS缺陷 相关推荐 xff1a css在线手册 这也是Bootstrap 4运行的基础 这意味着为了理解如
  • JS 变量的作用域及闭包

    与闭包有关的概念 xff1a 变量的作用域和变量的生存周期 下面本篇文章就来给大家介绍一下JS中变量的作用域及闭包 xff0c 有一定的参考价值 xff0c 有需要的朋友可以参考一下 xff0c 希望对大家有所帮助 一 变量的作用域 1 变
  • 理解JavaScript中的变量、范围和提升

    变量是许多编程语言的基本组成部分 xff0c 也是新手需要学习的第一个也是最重要的概念 JavaScript中有许多不同的变量属性 xff0c 以及命名变量时必须遵循的一些规则 在JavaScript中 xff0c 有三个关键字用于声明变量