三、JavaScript 变量

在本章中,你将学习一些基本的 JavaScript 数据类型。当你想让计算机保存一些信息时,这些信息就是某种“类型”例如,电子邮件地址是一种称为字符串的类型。电脑识别出你的电子邮件地址是一系列字母、数字和符号。

如果您要执行计算,计算机会将您用来执行计算的数据视为数字。它可以计算数字,但不能计算字符串。

在阅读本章的过程中,您将探索其中的一些数据类型。此外,您还将看到变量是如何工作的。

在这一章中,我使用术语“环境”它只是表示 JavaScript 在哪里执行,可能是在浏览器中,也可能是使用 Node.js。

在 JavaScript 中声明变量

JavaScript 是一种松散类型或动态语言。这只能说明 JavaScript 非常适合你。取决于你对此的感受,这可能是好的也可能是坏的。当您希望环境保存一个值时,您必须声明一个变量。

如果你创建了一个变量并赋予它一个值,那么你可以把这个值改变成完全不同的值。让我们看看实际情况(图 3-1 )。

img/313453_3_En_3_Fig1_HTML.jpg

图 3-1

使用 Chrome 中的控制台测试 JavaScript 变量

打开 web 浏览器,找到开发人员工具,然后转到控制台。当你在控制台时,输入图 3-1 中的代码。将userName的值设置为"Violator";你可以看到它在引号中,这使它成为一个字符串。然后它被重新分配给数字42,它的字符周围没有引号,所以它被认为是一个数字。

JavaScript 允许不同的变量声明方式。你需要遵守一些规则。

在创建变量的时候,首先需要让环境知道这是你的意图。这里我将介绍关键字的概念。

本例中使用的关键字是var(变量的缩写)。这个关键字将告诉环境你想要保留一些信息。

JavaScript 中还内置了其他关键字,可以让环境知道如何处理日期、数字,甚至是浏览器中当前的 HTML 文档。您将在未来的示例中探索它们。

在这里,您创建了一个名为userName的变量。这种大写叫做骆驼大小写,其中每隔一个单词的第一个字母都有一个大写字母。这不是创建变量的唯一方法,但你会经常看到。

在 JavaScript 中命名变量时,不能以数字或符号开头(考虑像@ a 符号这样的字符)。所有变量都可以以字母开头;无论是大写还是小写都没有关系。其后的任何字符都可以使用数字或符号。变量名称中也不能有空格。看看清单 3-1 中的例子。

var  user name = "Violator"; // not a valid variable
var !username = "Violator"; // not a valid variable
var 1user_name = "Violator"; // not a valid variable
var user_name = "Violator"; // valid variable
var userName = "Violator"; // valid variable
var username = "Violator"; // valid variable

Listing 3-1Valid and Invalid Ways to Create a Variable

这并不是一个关于变量命名的详尽列表,但是它应该给你一个在 JavaScript 中如何命名变量的概念。

注意

要获得更详尽的列表,看一看同样由 Apress 出版的 JavaScript 食谱

一旦您告诉环境您需要保存一些信息,接下来的事情就是将数据赋给该变量。该数据属于某种类型。在本例中,您将字符串"Violator"赋给了新创建的变量。

字符串是可以以文本形式使用的数据表示。电子邮件的内容、用户名和密码都是字符串。在 JavaScript 中创建字符串变量时,您可以在想要使用的字符周围使用单引号或双引号。重要的是要始终如一。你不能以单引号开始,以双引号结束,或者反过来。

在字符周围使用引号是很重要的,因为将"1"(引号中的数字)或1(只是数字)赋给一个变量是有区别的。第一个是字符串;第二个是数字。数字在 JavaScript 中是一种不同的数据类型。符号也是如此;"@"被认为是一串。

每条语句的末尾都有一个分号。这就像是句尾的句号。如果你不添加一个,环境会很好地试图理解你的意思,并会在它认为必要的地方插入一个。

您可能会遇到的一个问题是,环境将分号插入了错误的位置。这将在运行时产生错误。

然而,如果你添加它,它确实使你的代码更容易阅读。因此,作为最佳实践,在每个语句的末尾添加分号。

总之,在 JavaScript 中声明变量时,使用关键字(在本例中是var),命名变量,然后赋值。

在 JavaScript 中重新分配变量

JavaScript 中的一些变量可以被重新分配。这意味着,一旦你给了一个变量一个值,很容易,在某些情况下,有必要回到那个变量,给它一个全新的值。

在 JavaScript 中更新现有变量的一个例子是,如果您正在跟踪一个用户是否有权访问某些东西。您可以使用变量作为标志来检查某人的状态。这里有一个例子:

if ( hasAccess === true ){
     hasAccess = false;
}

这个例子说明了一个变量可以有多个值。变量hasAccess的值可以是真或假,这里您使用一个if语句来检查当前的值。

使用 true 或 false 作为值使您的变量成为布尔数据类型,这意味着它只能有一个值。布尔值只能为真或假。

有时候你可能需要一个变量有一个常量值。这种情况下的关键词是const。任何时候你都不希望这个变量的值改变。让我们看一个例子。

无法重新分配的变量

如果您有不应该更改的数据怎么办?在这种情况下,您希望变量包含一个无论发生什么都保持不变的值。JavaScript 提供了这样一种变量类型,它被称为常量

常量是一种变量,在第一次赋值后就不能更改。图 3-2 显示了一个试图改变常量值的例子。

img/313453_3_En_3_Fig2_HTML.jpg

图 3-2

标记为常量的变量在第一次给定值后不能改变

使用关键字const将允许您做与使用var相同的事情,不同之处在于您不能在以后重新赋值。在图 3-2 的例子中,你会看到浏览器抛出一个错误。

虽然不能将单个值重新分配给常量,但如果要分配一个对象,则该对象的属性可以更新。清单 3-2 包含了一个例子。

const myObj = {}
myObj.firstName = "Vince"
console.log(myObj)
{firstName: "Vince"}
  myObj.lastName = "Clarke"

console.log(myObj)
{firstName: "Vince", lastName: "Clarke"}
myObj = {}
Uncaught TypeError: Assignment to constant variable.

Listing 3-2Assigning an Object to a Constant

因为常数是一个对象,所以您可以访问该对象的属性并更新它们。我将在下一章全面阐述对象的概念。现在,把一个物体想象成名词。

这个“东西”有属性,(高度,宽度,颜色等。).对象的属性(这个“东西”)可以更新。但是变量myObj不能被重新分配。在最后一行中,您可以看到当试图给对象重新分配一个新值时,浏览器将抛出一个错误。

*到目前为止,我已经讨论了创建变量、为变量赋值以及更新变量的能力。我展示了不能给变量赋值的例子。

下一节将介绍环境如何控制变量的范围、上下文或“作用域”。

只能在单个代码块中使用的变量

我们先定义一个代码块。当您使用 JavaScript 函数时,经常会看到一组花括号({})。这是你的代码块。这些括号中的任何内容都是将要执行的代码。当使用关键字let来声明你的变量时,浏览器知道你赋给变量的值只能在那个块中看到。清单 3-3 包含了一个例子。

for (let i = 0; i < 10; i++) {
  console.log(i); //output = numbers between 0 and 9
}

console.log(i) //error i is undefined

Listing 3-3A let Statement Only Has a Value While Inside the Code Block

这里有一个循环。它创建一个名为i的变量,从值0开始,只要i没有值10,它就给i加 1。

当这个循环发生时,您在控制台中打印出i的当前值。这将显示值09(只要该值小于10)。

所有这些都发生在花括号内。一旦这个循环完成,变量i消失。环境不再考虑它了。所以,当你试图在下一行引用这个变量时,它会抛出一个错误。

所以,概括一下,当代码在花括号中执行时,使用的变量有一个值。当块执行完所有代码后,代码的其他部分就不能再访问该变量了。它已经不存在了。

这是letvar的主要区别之一。清单 3-4 显示了一个使用var的类似例子。

for (var i = 0; i < 10; i++) {
  console.log(i); //output = numbers between 0 and 9
}

console.log(i) //returns 10

Listing 3-4A var Statement Will Retain Its Value After the Code Block Has Been Executed

如果var的行为类似于let,您将得到相同的结果,其中i的值将返回undefined。相反,循环的行为完全相同,但是在这种情况下,您的变量是可以在循环外部访问的,并打印出10的值。

var关键字创建的变量是基于它当前的执行上下文来声明的。在第一种情况下,循环不在函数内部;因此,该变量在范围上成为全局变量。

在它的正下方,有一个相同的循环,但是这次是在一个函数块中。然后,该变量位于不同的执行上下文中。如果你试图在函数之外打印变量的值,浏览器将抛出一个错误。参见列表 3-53-6

for (var i = 0; i < 10; i++) {
        console.log(i); //output = numbers between 0 and 9
}

console.log(i) //returns 10

Listing 3-5When Creating a Variable with the var Keyword, It Will Exist Inside the Current Execution Context. The Code Here Is Outside a Function, Making the Context Global.
function goLoop(){
   for (var i = 0; i < 10; i++) {
        console.log(i); //output = numbers between 0 and 9
   }
}
goLoop();
console.log(i) //returns error

Listing 3-6When Creating a Variable Using the var Keyword Inside a Function, the Execution Context is Local to the Function

当处理变量时,在var上使用let将确保变量只存在于你创建的代码块中。变量表现不同的原因是因为变量提升。下一节将更详细地解释吊装。

面试问题

varconstlet有什么区别?说出一些 JavaScript 数据类型。

可变提升

在面试中,你可能会被问及variable hoisting。听起来比实际困难得多。这一节将澄清关于它如何工作的任何困惑。

当浏览器经历其编译阶段时,它会将函数和变量声明放入内存。

下面是一个如何声明变量的示例:

userName = "Stephanie";

这与使用关键字let初始化变量是不同的。这里,你给一个变量赋值,没有使用任何关键字。因为没有给这个变量分配关键字,所以它被认为是一个全局变量。这和使用var关键字是一样的。

下一个示例显示了工作代码,尽管它看起来不应该工作:

userName = "Stephanie";
console.log(userName); //returns Stephanie
var userName;

虽然看起来结果应该是undefined,但它返回了正确的值。与其他示例类似,在范围或执行上下文没有设置为代码块的情况下,使用关键字var

被提升的变量移动到当前作用域的顶部。因此,如果没有函数,变量将被移到全局范围。如果一个变量(使用var关键字)在一个函数中被声明,它将移动到该作用域的顶部。

变量提升在变量被声明时生效,而不是被赋值时生效。如果您声明了一个没有值的变量,即使它没有值,它仍然会被提升。清单 3-7 包含了一个例子。

function checkVars(){
   console.log(username); //returns undefined
   var username = "Hunter";
  console.log(username); //returns Hunter;
}
checkVars() //executes function;

function checkVars(){
   var username;
   console.log(username); //returns undefined
   username = "Hunter";
  console.log(username); //returns Hunter;
}

checkVars() //executes function;

Listing 3-7Variables Are Hoisted When They Are Declared, Not When They Are Assigned a Value. These Two Examples Produce the Same Result.

面试问题

什么是吊装,它是如何工作的?

严格模式

严格模式告诉浏览器运行更受限制的 JavaScript 版本。这是你可以选择的。在严格模式下运行您的代码将防止浏览器犯错误,从而难以优化代码。

当某些语法可能会被添加到 JavaScript 的未来版本中时,它还会阻止该语法的执行。它还消除了无声错误(没有浏览器反馈的错误)。

您可以对整个 JavaScript 文件或单个函数调用严格模式。要将其添加到整个脚本的顶部,请将use strict;添加到您的代码中。

在清单 3-8 中,如果你声明了一个变量而没有初始化它,浏览器会抛出一个错误。

x = "think tank" //Reference Error: x is not defined

Listing 3-8Variables Declared While in Strict Mode Must Be Initalized

如果您试图将一个对象赋给一个尚未初始化的变量,就会出现这种情况:

X = {user:"Player One", score:1000} //Reference Error: x is not defined.

单个函数可以在严格模式下运行,只需在函数体中添加相同的代码行。参见清单 3-9

function myFunction(){
   "use strict";
 // add commands here
}

Listing 3-9Using “use strict” Inside a Function Declaration Will Tell the Browser to Run Just That Function in Strict Mode

使用严格模式可以确保浏览器以最有效的方式执行您的代码,并在出现错误时提供最多的反馈。

摘要

本章讲述了如何创建变量以及何时应该使用某种类型的变量。一些变量存在于代码块中,而另一些则无法更新。

您探索了可变提升的概念。当使用关键字var时,变量可以被提升或移动到执行上下文的顶部。这可能会导致这样的情况,即使一个变量已经被声明,它可能还没有一个值,所以将返回undefined作为一个值。

最后一节介绍了在严格模式下运行代码的一些好处。它将执行更高效的 JavaScript 版本,并在浏览器忽略错误时通过返回错误给出更好的反馈。

下一章将更详细地介绍对象是如何工作的,并介绍一种叫做数组的对象。*