这是用户在 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';

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:


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;
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:


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.