Skip to content
This page has been auto-translated and may contain errors.View in English

变量和值

docs.scrimba.com

假设你正在构建一个结账页面,商品价格在三个地方出现:产品行、运行总计和确认页面。手动将 19.99 输入到全部三个地方,一笔销售就会变成一个下午的查找和替换工作。将其存储一次,以某个名称保存,然后在一个地方更改它,使用它的每个地方都会跟着更新。那个名称就是一个变量,本章讲的就是如何创建变量、何时锁定变量,以及如何命名变量。

存储值

一个 变量 是你给一个值起的名称,这样你可以稍后再次使用它。你用 let 创建一个变量,然后是一个名称,然后是 =,然后是你想要存储的值:

js
let userName = "张三";
console.log(userName); // 张三

这一行说:记住文本 "张三" 并将其保存到名称 userName 下。从那时起,无论你在哪里写 userName,JavaScript 都会返回你存储的内容。

= 理解为"将这个值存储到这个名称下"。这不是数学课中的等号,其中两边已经相同。这是一条指令:获取右边的值,并将其存储到左边的名称下。

因为这是一条存储指令,你稍后可以改变主意。再写一遍这个名称和 =,加上一个新值,JavaScript 会保留最新的那个:

js
let score = 0;
score = 10;
console.log(score); // 10

第一行创建 score 并在其中放入 0。第二行给它赋一个新值。没有第二个 let,因为 score 已经存在;你是在更新它,而不是重新创建它。

一个变量是一个名称 绑定 到一个值。你用 let 声明它,并用赋值运算符 = 设置其值:

js
let total = 0;
total = 42;
console.log(total); // 42

= 是赋值,不是比较。它计算右边的表达式,然后将结果存储到左边的名称下。这就是为什么 = 表示"赋值",永远不表示"等于";你将在 运算符 中遇到的比较是一个单独的符号,===

let 声明创建名称;再次赋值给它时更新它保存的值。每个变量你只使用一次 let。在那之后,左边的单独名称就足够了:

js
let itemPrice = 19.99;
itemPrice = 24.99;
console.log(itemPrice); // 24.99

右边的值可以是 JavaScript 拥有的任何 数据类型:文本、数字、布尔值。变量不在乎是哪一个;它保存你最后赋值给它的任何东西。

一个变量是一个 标识符(你的代码中的一个名称)绑定到一个值。= 是赋值运算符:它计算右侧表达式并将结果绑定到左侧的名称。它永远不测试相等性,也永远不将值复制到一个固定的盒子里;它指向一个值的名称。

js
let total = 0;
total = 42;
console.log(total); // 42

重新赋值不会创建新变量,而是重新指向现有绑定。对于数字和字符串这样的原始类型,这种区别保持隐藏,因为每个值是独立的、自包含的。但当一个变量持有一些共享的东西,比如一个对象时,这开始变得重要,因为那时两个名称可以指向同一个值,通过一个名称的改变会通过另一个名称显示出来。当 对象 到达时你会完整地看到这一点;现在,保持"名称指向值而不是包含值"的想法。

= 做的另一件事是:它不会将值锁定到位。let score = 0 说"现在让 score 指向 0",下一行可以自由地让它指向别的地方。绑定是否根本可以被重新指向是 letconst 之间的区别,接下来就是这个。

Juno存储值 一个变量是你想要重复使用的值的名称,你用 let name = value 创建一个。将 = 理解为"将这个值存储到这个名称下",而不是数学课的等号。要稍后更改它,用相同的名称和 = 再写一遍,不要第二个 let,JavaScript 会保留最新的值。
Juno存储值let 声明创建一个名称;用 = 赋值将值存储在其下。= 是赋值,不是比较,所以它永远不表示"等于"。你每个变量只写一次 let;在那之后,单独的名称更新它保存的值。
Juno存储值= 将一个名称绑定到一个值,它永远不会复制到一个盒子里或测试相等性。重新赋值是重新指向现有绑定而不是创建新变量。对于数字和字符串这种情况保持隐藏,并在名称指向某个共享的东西时开始产生影响,所以在对象出现前记住"名称指向值"。

let vs const

有两个字用于创建变量:letconst。你已经看过 let。当值在你设置它之后永远不应该改变时,使用 const

js
const taxRate = 0.2;
console.log(taxRate); // 0.2

税率是固定的,所以 const 很合适:它说"这是已设置的,我不想它不小心改变"。如果你尝试重新赋值一个 const,JavaScript 会用错误阻止你,这是一个有用的护栏。

首先考虑 const。只有当你知道值会改变时才使用 let,比如增加的分数或你添加的总计。如果一个值在其整个生命周期中保持不变,const 会说明这一点并保护它。

js
const currency = "USD";
let itemsInCart = 0;
itemsInCart = 3;
console.log(itemsInCart); // 3

货币不会改变,所以它是 const。购物车数量会改变,所以它是 let

JavaScript 给你两种方式声明一个变量,选择是关于值是否会被重新赋值。const 声明一个 常量 绑定:一旦你赋值给它,你不能将那个名称指向一个新值。

js
const taxRate = 0.2;
taxRate = 0.25; // TypeError: Assignment to constant variable.

let 允许重新赋值;const 禁止它。保持代码整洁的规则是 首先考虑 const,只有在你必须重新赋值时才使用 let。大多数变量是设置一次然后读取多次的,所以大多数应该是 const

js
const currency = "USD";
let runningTotal = 0;
runningTotal = 19.99;
console.log(runningTotal); // 19.99

const 不是关于值是否特殊的;它是给任何阅读代码的人(包括下周的你)的一个信号,这个名称不会改变。那个信号使程序更容易理解,因为一个 const 你可以信任它保持不动。

letconst 都声明一个 绑定(名称和值之间的链接)。区别在于那个绑定是否可以被重新赋值。const 冻结绑定:在初始赋值之后,将名称指向一个新值是一个 TypeError

js
const taxRate = 0.2;
taxRate = 0.25; // TypeError: Assignment to constant variable.

默认使用 const,只在需要重新赋值时才用 let。这不是风格上的吹毛求疵;一个 const 是一个你在阅读时可以依赖的事实,一个可能不会在你下面改变的名称更少,这缩小了一个错误可能存在的范围。

值得早点说明的微妙之处:const 固定绑定,而不是内容。它阻止你重新指向名称,但如果值是有内部部分的东西,那些部分仍然可以改变。一个数字或字符串没有内部部分可以改变,所以用这些 const 的行为完全像"这个值是固定的"。但对于一个对象,const 只保证名称继续指向同一对象;对象自己的内容仍然可以编辑。那个间隙会让人惊讶,现在比调试中途更容易理解,所以 对象 直接回到它。

js
const currency = "USD";
let runningTotal = 0;
runningTotal = 19.99;
console.log(runningTotal); // 19.99

有第三个、更旧的关键字你会在现有代码中遇到:var。不要使用它。它与 let 在两个方面不同,会导致错误。首先,var函数作用域:它忽略 letconst 尊重的 { } 块,所以在块内声明的 var 会泄漏到整个周围函数,而 letconst块作用域 的,并保持在最近的 { } 内。其次,var变量提升:声明被视为向其作用域顶部移动,所以 var 名称存在(保存 undefined)在声明它的行之前,这隐藏了错误而不是捕捉它们。

letconst 也是变量提升的,但在声明行之前到达它们会抛出错误而不是无声地给出 undefined;那个早期窗口被称为 暂时死区,它产生的错误是一个特性,因为它将无声的错误变成一个响亮的错误。简短版本:默认写 const,必须重新赋值时写 let,并将 var 视为维护旧代码的只读知识。

Junolet vs const 对于不应该改变的值使用 const,对于会改变的值使用 let。首先考虑 const,只有当你知道值需要改变时才切换到 let。重新赋值一个 const 会给你一个错误,这是护栏在发挥作用。
Junolet vs constconst 禁止重新赋值;let 允许它。默认使用 const,只有当一个值必须改变时才考虑 let。一个 const 告诉下一个读者这个名称不会改变,大多数变量是设置一次然后读取多次,所以大多数应该是 const
Junolet vs constconst 冻结绑定,而不是内容,所以重新赋值名称是 TypeError 但它指向的对象仍然可以编辑。默认使用 const,只对实际重新赋值使用 let,并将旧的 var 视为只读知识,因为它是函数作用域的并以隐藏错误的方式变量提升。绑定与内容的间隙会让人们吃惊,所以在对象到达前记住它。

命名变量

变量名有几个规则。它可以使用字母、数字、_$,但不能以数字开头,也不能包含空格:

js
let firstName = "张三";
let item2 = "book";

名称是 区分大小写 的,这意味着 firstNamefirstname 是两个不同的变量。大小写弄错是一个常见的早期错误,所以保持名称一致是有帮助的。

JavaScript 开发者使用的风格被称为 驼峰命名法:以小写开头,每个后面的单词的首字母大写,没有空格。所以 firstNameitemPriceisLoggedIn

js
let itemPrice = 19.99;
let isLoggedIn = true;

超过规则之外,目标是选择说明它们保存的内容的名称。pricep 更好,userNamex 更好。你读你的代码远多于你写它,清晰的名称是使其可读的关键。

有效名称的规则:它可能包含字母、数字、_$,不能以数字开头,不能包含空格或保留字如 let。名称是区分大小写的,所以 totalTotal 是独立的变量。

在这些规则内,约定是 驼峰命名法:小写第一个单词,每个后续单词大写,没有分隔符。

js
let firstName = "张三";
let itemPrice = 19.99;
let isLoggedIn = true;

约定不由语言强制执行,但由你将在其中工作的每个代码库强制执行,所以从一开始就遵循它。一个布尔值通常用 ishas 前缀读得很好(isLoggedInhasDiscount),这一眼就表明了值是真还是假。

名称是文档。daysUntilExpiry 告诉下一个读者值的含义;d 让他们去搜索。描述性名称花费一些击键并节省真实的时间,所以花费它们。

词法规则:一个有效的 标识符(代码中的名称)可能包含字母、数字、_$,不能以数字开头,不能是保留字(letconstreturn 等)。标识符是区分大小写的,所以 totalTotal 是不同的。

分层的约定是变量的驼峰命名法,即使语言不强制执行它,也值得视为不可协商。工具、队友和每个流行的风格指南都假设它,所以偏离会增加摩擦,没有收益。

js
const firstName = "张三";
const itemPrice = 19.99;
const isLoggedIn = true;

更高价值的习惯是按意义命名。一个名称是你拥有的最便宜的文档,也是最可能保持准确的,因为它坐在它描述的值上。remainingCredits 在一次重构中存活下来,而一个说"剩余信用"的注释可能不会。布尔值最好读作一个是/否问题(isActivehasAccess),避免名称在改变后说谎,比如一个 const total 你从概念上不断添加到;如果意义漂移了,重新命名它。清晰的命名是本章中最高杠杆的习惯,并且是免费的。

Juno命名变量 一个名称可以使用字母、数字、_$,但不能以数字开头或包含空格。名称是区分大小写的,所以 firstNamefirstname 是不同的。使用驼峰命名法如 itemPrice,并选择说明它们保存内容的名称,所以 price 优于 p
Juno命名变量 有效名称使用字母、数字、_$,永远不以数字开头,并且是区分大小写的。约定是驼峰命名法,虽然语言不强制执行它,但每个代码库都强制执行,所以从第一天就遵循它。一个描述性的名称是保持准确的文档,所以在 daysUntilExpiry 上花费击键,不要用 d
Juno命名变量 标识符允许字母、数字、_$,不能以数字开头,不能是保留字,并且是区分大小写的。使用驼峰命名法;语言不强制执行它但每个工具和队友都假设它。按意义命名是这里最高杠杆的习惯,并且花费零成本,所以使 remainingCredits 成为默认值,而不是 r

变量从这里去哪儿

变量是一切坐在其上的基础:一个值直到有一个你可以通过其到达的名称才不是有用的。你现在有三个重要的步骤,用 let 存储值,用 const 锁定值,并很好地命名它,你会从这里开始在你写的每个程序中使用这三个。

接下来你将查看 数据类型 中的值本身:你一直在存储的文本、数字和布尔值,以及是什么使每个值的行为方式如此。在那之后,运算符 向你展示如何组合这些值,函数 让你像变量命名值那样命名一段工作。