这是用户在 2024-5-28 13:59 为 https://justjavascript.com/learn/03-values-and-variables 保存的双语快照页面,由 沉浸式翻译 提供双语支持。了解如何保存?
Skip to content

Values and Variables

episode 03

We’ll kick off this module with a little code snippet.
我们将以一个小代码片段开始这个模块。

let reaction = 'yikes';
reaction[0] = 'l';
console.log(reaction);

What do you expect this code to do? It’s okay if you’re not sure. Try to find the answer using your current knowledge of JavaScript.
你期望这段代码做什么?如果你不确定也没关系。试着用你现有的 JavaScript 知识找到答案。

I want you to take a few moments and write down your exact thought process for each line of this code, step by step. Pay attention to any gaps or uncertainties in your existing mental model and write them down, too. If you have any doubts, try to articulate them as clearly as you can.
我希望你花几分钟时间,逐行写下你对这段代码的确切思考过程。注意你现有的思维模型中的任何空白或不确定性,并将它们也写下来。如果你有任何疑问,尽量清楚地表达出来。

Answer 答案
Don’t reveal until you have finished writing.
写完之前不要透露。
Answer 答案

This code will either print "yikes" or throw an error depending on whether you are in strict mode. It will never print "likes".
这段代码要么打印 "yikes" ,要么在严格模式下抛出错误。它永远不会打印 "likes"

Yikes. 哎呀。

Primitive Values Are Immutable
原始值是不可变的

Did you get the answer right? This might seem like the kind of trivia question that only comes up in JavaScript interviews. Even so, it illustrates an important point about primitive values.
你答对了吗?这可能看起来像是只有在 JavaScript 面试中才会出现的琐事问题。即便如此,它说明了一个关于原始值的重要点。

We can’t change primitive values.
我们不能改变原始值。

I will explain this with a small example. Strings (which are primitive) and arrays (which are not) have some superficial similarities. An array is a sequence of items, and a string is a sequence of characters:
我将用一个小例子来解释这一点。字符串(原始类型)和数组(非原始类型)有一些表面上的相似之处。数组是一个项目的序列,而字符串是一个字符的序列:

let arr = [212, 8, 506];
let str = 'hello';

We can access the array’s first item and the string’s first character similarly. It almost feels like strings are arrays:
我们可以类似地访问数组的第一个项目和字符串的第一个字符。几乎感觉字符串就是数组:

console.log(arr[0]); // 212
console.log(str[0]); // "h"

But they’re not. Let’s take a closer look. We can change an array’s first item:
但事实并非如此。让我们仔细看看。我们可以更改数组的第一个项目:

arr[0] = 420;
console.log(arr); // [420, 8, 506]

Intuitively, it’s easy to assume that we can do the same to a string:
直观地看,很容易假设我们可以对字符串做同样的事情:

str[0] = 'j'; // ???

But we can’t. 但我们不能。

It’s an important detail we need to add to our mental model. A string is a primitive value, and all primitive values are immutable. “Immutable” is a fancy Latin way to say “unchangeable.” Read-only. We can’t mess with primitive values. At all.
这是我们需要添加到心理模型中的一个重要细节。字符串是一种原始值,所有原始值都是不可变的。“不可变”是一个花哨的拉丁词,意思是“不可更改”。只读。我们不能随意更改原始值。完全不能。

JavaScript won’t let us set a property on any primitive value, be it a number, string or something else. Whether it will silently refuse our request or throw an error depends on which mode our code is in. But rest assured that this will never work:
JavaScript 不允许我们在任何原始值上设置属性,无论是数字、字符串还是其他东西。它是否会默默地拒绝我们的请求或抛出错误取决于我们的代码处于哪种模式。但请放心,这永远不会奏效:

let fifty = 50;
fifty.shades = 'gray'; // No!

Like any number, 50 is a primitive value. We can’t set properties on it.
像任何数字一样, 50 是一个原始值。我们不能在其上设置属性。

Remember that in our JavaScript universe, all primitive values are distant stars, floating farthest from our code. We can point to them, but they will always stay where they are, unchanged.
请记住,在我们的 JavaScript 宇宙中,所有的原始值都是遥远的星星,漂浮在离我们的代码最远的地方。我们可以指向它们,但它们将始终保持原位,不会改变。

I find it strangely comforting.
我觉得这莫名地令人安慰。

Variables and Values—A Contradiction?
变量和值——一种矛盾?

You’ve seen that primitive values are read-only—or, in the parlance of our times, immutable. Now, use the following code snippet to test your mental model.
你已经看到原始值是只读的——或者用我们这个时代的术语来说,是不可变的。现在,使用以下代码片段来测试你的心理模型。

let pet = 'Narwhal';
pet = 'The Kraken';
console.log(pet); // ?

Like before, write down your thought process in a few sentences. Don’t rush ahead. Pay close attention to how you’re thinking about each line, step by step. Does the immutability of strings play a role here? If it does, what role does it play?
像之前一样,用几句话写下你的思考过程。不要急于求成。仔细注意你对每一行的思考过程,一步一步来。字符串的不可变性在这里起作用了吗?如果起作用,它起了什么作用?

Answer 答案
Don’t reveal until you have finished writing.
写完之前不要透露。
Answer 答案

If you thought I was trying to mess with your head, you were right! The answer is "The Kraken". Immutability doesn’t play a role here.
如果你认为我在试图扰乱你的思维,你是对的!答案是 "The Kraken" 。不可变性在这里不起作用。

Don’t despair if you got it wrong! This example may seem like it’s contradicting string immutability, but it’s not.
如果你弄错了,不要绝望!这个例子看起来似乎与字符串不可变性相矛盾,但实际上并没有。

When you’re new to a language, sometimes it’s necessary to put aside contradictions so that you can avoid rabbit holes and continue learning. But now that you are committed to building a mental model, you need to question contradictions.
当你刚开始学习一门语言时,有时有必要放下矛盾,以避免陷入困境并继续学习。但现在你已经致力于建立一个心理模型,你需要质疑这些矛盾。

Contradictions reveal gaps in mental models.
矛盾揭示了心理模型中的差距。

Variables Are Wires 变量是线

Let’s look at this example again.
让我们再看这个例子。

let pet = 'Narwhal';
pet = 'The Kraken';
console.log(pet); // "The Kraken"

We know that string values can’t change because they are primitive. But the pet variable does change to "The Kraken". What’s up with that?
我们知道字符串值不能改变,因为它们是原始值。但是 pet 变量确实变成了 "The Kraken" 。这是怎么回事?

This might seem like it’s a contradiction, but it’s not. We said primitive values can’t change, but we didn’t say anything about variables! As we refine our mental model, we need to untangle a couple of related concepts:
这看起来可能是一个矛盾,但事实并非如此。我们说过原始值不能改变,但我们没有说变量!随着我们完善我们的心理模型,我们需要解开几个相关的概念:

Variables are not values.
变量不是值。

Variables point to values.
变量指向值。

Assigning a Value to a Variable
给变量赋值

In our JavaScript universe, a variable is a wire that points to a value.
在我们的 JavaScript 宇宙中,变量是指向值的线。

For example, I can point the pet variable to the "Narwhal" value. (I can also say that I’m assigning the value "Narwhal" to the variable called pet):
例如,我可以将 pet 变量指向 "Narwhal" 值。(我也可以说我正在将值 "Narwhal" 分配给名为 pet 的变量):

let pet = 'Narwhal';

But what if I want a different pet? No problem—I can point pet to another value:
但是如果我想要不同的宠物怎么办?没问题——我可以将 pet 指向另一个值:

pet = 'The Kraken';

All I am doing here is instructing JavaScript to point the variable, or a “wire”, on the left side (pet) to the value on the right side ('The Kraken'). It will keep pointing at that value unless I reassign it again later.
我在这里所做的只是指示 JavaScript 将左侧的变量或“线”( pet )指向右侧的值( 'The Kraken' )。除非我稍后再次重新分配它,否则它将继续指向该值。

Rules of Assignment 赋值规则

There are two rules when we want to use the = assignment operator:
使用 = 赋值运算符时有两个规则:

  1. The left side of an assignment must be a “wire”—such as the pet variable. Note that the left side can’t be a value. (Try these examples in the console):
    赋值的左侧必须是一个“线”,例如 pet 变量。请注意,左侧不能是一个值。(在控制台中尝试这些示例):

    20000 = 'leagues under the sea'; // Nope.
    'war' = 'peace'; // Nope.
  2. The right side of an assignment must be an expression, so it always results in a value. Our expression can be something simple, like 2 or 'hello'. It can also be a more complicated expression—for example:
    赋值的右侧必须是一个表达式,所以它总是会产生一个值。我们的表达式可以是简单的,比如 2'hello' 。它也可以是一个更复杂的表达式——例如:

    pet = count + ' Dalmatians';

    Here, count + ' Dalmatians' is an expression—a question to JavaScript. JavaScript will answer it with a value (for example, "101 Dalmatians"). From now on, the pet variable “wire” will point to that particular value.
    这里, count + ' Dalmatians' 是一个表达式——一个对 JavaScript 的提问。JavaScript 会用一个值来回答它(例如, "101 Dalmatians" )。从现在开始, pet 变量“线”将指向那个特定的值。

Fun Fact 有趣的事实

If the right side must be an expression, does this mean that simple things—numbers like 2 or strings like 'The Kraken'—written in code are also expressions? Yes! Such expressions are called literals—because we literally write down the values that they result in.
如果右侧必须是一个表达式,这是否意味着简单的东西——像 2 这样的数字或像 'The Kraken' 这样的字符串——写在代码中也是表达式?是的!这样的表达式被称为字面量——因为我们实际上写下了它们所产生的值。

Reading a Value of a Variable
读取变量的值

I can also read the value of a variable—for example, to log it:
我也可以读取变量的值——例如,记录它:

console.log(pet);

That’s hardly surprising.
这并不奇怪。

But note that it is not the pet variable that we pass to console.log. We might say that colloquially, but we can’t really pass variables to functions. We pass the current value of the pet variable. How does this work?
但请注意,我们传递给 console.log 的不是 pet 变量。我们可能会这样说,但我们不能真正将变量传递给函数。我们传递的是 pet 变量的当前值。这是如何工作的?

It turns out that a variable name like pet can serve as an expression too! When we write pet, we’re asking JavaScript a question: “What is the current value of pet?” To answer our question, JavaScript follows pet “wire,” and gives us back the value at the end of this “wire.”
事实证明,像 pet 这样的变量名也可以作为表达式使用!当我们写 pet 时,我们是在问 JavaScript 一个问题:“ pet 的当前值是什么?”为了回答我们的问题,JavaScript 会沿着 pet “线”查找,并将这条“线”末端的值返回给我们。

So the same expression can give us different values at different times!
因此,同一个表达式在不同时间可以给我们不同的值!

Nitpicking 吹毛求疵

Who cares if you say “pass a variable” or “pass a value”? Isn’t the difference hopelessly pedantic? I certainly don’t encourage interrupting your colleagues to correct them. That would be a waste of everyone’s time.
谁在乎你说“传递变量”还是“传递值”?这种区别不是无可救药的迂腐吗?我当然不鼓励打断同事去纠正他们。这会浪费大家的时间。

But you need to have clarity on what you can do with each JavaScript concept in your head. You can’t skate a bike. You can’t fly an avocado. You can’t sing a mosquito. And you can’t pass a variable—at least not in JavaScript.
但你需要清楚地知道你脑海中的每个 JavaScript 概念能做什么。你不能滑冰骑自行车。你不能飞一个鳄梨。你不能唱蚊子。而且你不能传递变量——至少在 JavaScript 中不能。

Here’s a small example of why these details matter.
这是一个小例子,说明为什么这些细节很重要。

function double(x) {
x = x * 2;
}
let money = 10;
double(money);
console.log(money); // ?

If we thought double(money) was passing a variable, we could expect that x = x * 2 would double the money variable.
如果我们认为 double(money) 是在传递一个变量,我们可能会期望 x = x * 2 会将 money 变量加倍。

But that’s not right: double(money) means “figure out the value of money, and then pass that value to double.” So money still points to 10. What a scam!
但那是不对的: double(money) 的意思是“找出 money 的值,然后将该值传递给 double 。”所以 money 仍然指向 10 。真是个骗局!

What are the different JavaScript concepts in your head? How do they relate to each other and how can we interact with them from code?
你脑海中有哪些不同的 JavaScript 概念?它们之间如何关联,我们如何从代码中与它们交互?

Write down a short list of the ones you use most often.
写下你最常用的那些概念的简短列表。

Putting it Together 综合起来

Now let’s revisit the first example from Mental Models:
现在让我们重新审视一下《思维模型》中的第一个例子:

let x = 10;
let y = x;
x = 0;

I suggest that you take a piece of paper or a drawing app and sketch out a diagram of what happens to the “wires” of the x and y variables step by step.
我建议你拿一张纸或一个绘图应用程序,逐步画出 xy 变量的“线”发生了什么变化的图。

You can do the sketch right here:
你可以在这里画草图:

Shapes

Drawing canvas 画布

The first line doesn’t do much:
第一行没什么作用:

  • Declare a variable called x.
    声明一个名为 x 的变量。
    • Draw the x variable wire.
      画出 x 变量线。
  • Assign to x the value of 10.
    x 的值赋给 10
    • Point the x wire to the value 10.
      x 线指向值 10

The second line is short, but it does quite a few things:
第二行很短,但它做了很多事情:

  • Declare a variable called y.
    声明一个名为 y 的变量。
    • Draw the y variable wire.
      绘制 y 变量线。
  • Assign to y the value of x.
    y 的值赋给 x
    • Evaluate the expression: x.
      计算表达式: x
      • The “question” we want to answer is x.
        我们想回答的“问题”是 x
      • Follow the x wire—the answer is the value 10.
        跟随 x 线——答案是值 10
    • The x expression resulted in the value 10.
      x 表达式的结果是值 10
    • Therefore, assign to y the value of 10.
      因此,将 y 的值赋为 10
    • Point the y wire to the value 10.
      y 线指向值 10

Finally, we get to the third line:
最后,我们进入第三行:

  • Assign to x the value of 0.
    x 的值赋给 0
    • Point the x wire to the value 0.
      x 线指向值 0

After these three lines of code have run, the x variable points to the value 0, and the y variable points to the value 10.
运行这三行代码后, x 变量指向值 0 ,而 y 变量指向值 10

Note that y = x did not mean point y to x. We can’t point variables to each other! Variables always point to values. When we see an assignment, we “ask” the right side’s value, and point the “wire” on the left side to that value.
请注意, y = x 并不意味着将 y 指向 x 。我们不能将变量相互指向!变量总是指向值。当我们看到赋值时,我们“询问”右侧的值,并将左侧的“线”指向该值。

I mentioned in Mental Models that it is common to think of variables as boxes. The universe we’re building is not going to have any boxes at all. It only has wires!
我在《心理模型》中提到,人们通常将变量视为盒子。我们正在构建的宇宙根本不会有任何盒子。它只有电线!

This might seem a bit annoying, but using wires makes it much easier to explain numerous other concepts, like strict equality, object identity, and mutation. We’re going to stick with wires, so you might as well start getting used to them now!
这可能看起来有点烦人,但使用电线可以更容易地解释许多其他概念,比如严格相等、对象身份和变异。我们将坚持使用电线,所以你现在最好开始习惯它们!

Our universe is full of wires.
我们的宇宙充满了电线。

Recap 回顾

  • Primitive values are immutable. They’re a permanent part of our JavaScript universe—we can’t create, destroy, or change them. For example, we can’t set a property on a string value because it is a primitive value. Arrays are not primitive, so we can set their properties.
    原始值是不可变的。它们是我们 JavaScript 世界的永久部分——我们不能创建、销毁或更改它们。例如,我们不能在字符串值上设置属性,因为它是一个原始值。数组不是原始值,所以我们可以设置它们的属性。

  • Variables are not values. Each variable points to a particular value. We can change which value it points to by using the = assignment operator.
    变量不是值。每个变量指向一个特定的值。我们可以使用 = 赋值运算符更改它指向的值。

  • Variables are like wires. A “wire” is not a JavaScript concept—but it helps us imagine how variables point to values. When we do an assignment, there’s always a wire on the left, and an expression (resulting in a value) on the right.
    变量就像电线。“电线”不是 JavaScript 概念——但它帮助我们想象变量如何指向值。当我们进行赋值时,左边总是有一根电线,右边是一个表达式(产生一个值)。

  • Look out for contradictions. If two things that you learned seem to contradict each other, don’t get discouraged. Usually it’s a sign that there’s a deeper truth lurking underneath.
    注意矛盾。如果你学到的两件事似乎相互矛盾,不要气馁。通常这表明有更深层的真理潜伏在下面。

  • Language matters. We’re building a mental model so that we can be confident in what can or cannot happen in our universe. We might speak about these ideas in a casual way (and nitpicking is often counterproductive) but our understanding of the meaning behind the terms needs to be precise.
    语言很重要。我们正在构建一个心理模型,以便对宇宙中可能或不可能发生的事情有信心。我们可能会以一种随意的方式谈论这些想法(吹毛求疵通常是适得其反的),但我们对术语背后含义的理解需要精确。

Exercises 练习

This module also has exercises for you to practice!
本模块还有练习供您练习!

Don’t skip them! 不要跳过它们!

Even though you’re likely familiar with the concept of variables, these exercises will help you cement the mental model we’re building. We need this foundation before we can get to more complex topics.
尽管您可能已经熟悉变量的概念,这些练习将帮助您巩固我们正在构建的心理模型。在我们进入更复杂的主题之前,我们需要这个基础。