变量

变量是为值分配代表性名称的数据结构。 它们可以包含任何类型的数据。

变量的名称称为“标识符”。有效标识符必须遵循 这些规则:

  • 标识符可以包含 Unicode 字母、美元符号 ($)、下划线 字符 (_)、数字 (0-9),甚至一些 Unicode 字符。
  • 标识符不能包含空格,因为解析器会使用空格来 单独的输入元素。例如,如果您尝试调用一个变量, my Variable,而不是 myVariable,解析器会看到两个标识符: myVariable,并抛出语法错误(“意外令牌: 标识符)。
  • 标识符必须以字母、下划线 (_) 或美元符号 ($) 开头。 不能以数字开头,以免将数字和 标识符:

    let 1a = true;
    
    > Uncaught SyntaxError: Invalid or unexpected token
    

    如果 JavaScript 允许在标识符的开头使用数字,那么 只由数字组成的标识符,会导致用作 及用作身份识别号码的号码:

    let 10 = 20
    
    10 + 5
    > ?
    
  • 保留字词” 语法上有意义的字词不能用作标识符。

  • 标识符不能包含特殊字符 (! . , / \ + - * =)。

以下规则不是严格的标识符创建规则, 业界最佳实践,让代码维护变得更轻松。如果您的特定 项目具有不同的标准,请遵循这些标准以确保一致性。

按照 JavaScript 的内置方法和属性设置的示例, 驼峰式大小写(设计样式也为“camelCase”)是 由多个字词组成的标识符。驼峰式大小写是一种 除了第一个单词的首字母,将除第一个单词之外的每个单词的首字母都大写,以提升 可读性(不含空格)。

let camelCasedIdentifier = true;

有些项目会根据上下文和性质使用其他命名惯例 数据。例如,class 的第一个字母 通常采用大写形式,因此多字词类名称通常会使用驼峰 这种大小写形式通常称为“大驼峰式大小写”或 Pascal 大小写形式。

class MyClass {

}

标识符应简明扼要地描述它们所包含数据的性质(例如 例如,与 theNumberOfDaysInTheCurrentMonth 相比,currentMonthDays 这个名称更好) 并且一目了然(originalValueval 更佳)。通过 本单元中使用的 myVariable 标识符 孤立的示例,但在生产代码中将毫无用处,因为它们 不会提供有关其所含数据的信息。

标识符所包含的数据不应过于具体 它们的值可能会根据脚本对这些数据的操作方式而变化, 决策和决策。例如,最初给定 标识符 miles 可能需要在稍后需要更改为以公里为单位的值, 项目,因此维护人员需要将对该变量的所有引用更改为 避免日后出现混淆为防止出现这种情况,请使用 distance 作为标识符 。

JavaScript 不会赋予标识符 以下划线字符 (_) 开头,但通常用于显示 变量、方法或属性是“私有”的也就是说 在包含它的对象的上下文中使用,而不应是 可在该环境之外访问或修改。这是沿用而来的惯例 与其他编程语言不同,并且在 JavaScript 的 私有属性

变量声明

有多种方法可以让 JavaScript 识别标识符,即一个进程, 名为“声明”变量。使用 letconst、 或 var 个关键字。

let myVariable;

使用 letvar 声明可以随时更改的变量。这些 关键字会告知 JavaScript 解释器,字符串是 可能含有值的标识符

使用现代代码库时,请使用 let 而不是 varvar仍可使用 但它也有一些非直观的行为, 最早的 JavaScript 版本,之后无法更改为 保留向后兼容性在 ES6 中添加了 let,以解决一些问题 var的设计

声明的变量通过为变量赋值来“初始化”。使用 单个等号 (=) 来为变量赋值或为其重新赋值。您可以 作为声明它的同一语句的一部分:

let myVariable = 5;

myVariable + myVariable
> 10

您还可以使用 let(或 var)声明变量,而无需初始化变量 。如果这样做,该变量的初始值为 undefined,直到 代码会为其分配一个值。

let myVariable;

myVariable;
> undefined

myVariable = 5;

myVariable + myVariable
> 10

值为 undefined 的变量与未定义变量不同 尚未声明其标识符的 ID。引用未引用的变量 会导致错误。

myVariable
> Uncaught ReferenceError: myVariable is not defined

let myVariable;

myVariable
> undefined

标识符与值之间的关联通常称为“绑定”。 遵循 letvarconst 关键字的语法称为 “绑定列表”支持多个以英文逗号分隔的变量声明 (以预期的分号结尾)。这会使以下代码段 功能上完全相同:

let firstVariable,
     secondVariable,
     thirdVariable;
let firstVariable;
let secondVariable;
let thirdVariable;

重新赋值变量的值不使用 let(或 var),因为 JavaScript 已经知道该变量存在:

let myVariable = true;

myVariable
> true

myVariable = false;

myVariable
> false

您可以根据变量的现有值为它们重新分配新值:

let myVariable = 10;

myVariable
> 10

myVariable = myVariable * myVariable;

myVariable
> 100

如果您尝试在生产环境中使用 let 重新声明变量, 您会遇到语法错误:

let myVariable = true;
let myVariable = false;
> Uncaught SyntaxError: redeclaration of let myVariable

浏览器的开发者工具 更宽松的 let(和 class)重复声明,因此您可能 会在开发者控制台中看到同样的错误。

为了保持旧版浏览器的兼容性,var 允许进行不必要的重复声明 在任何情况下都不会出错:

var myVariable = true;
var myVariable = false;

myVariable\
> false

const

使用 const 关键字声明一个常量,该常量必须是 立即初始化,然后无法更改。常量标识符 遵循与使用 let(以及 var)声明的变量相同的规则:

const myConstant = true;

myConstant
> true

要声明常量,必须立即为其分配值,因为 在创建常量后就不能重新赋值,因此任何未初始化的 常量将永远保持 undefined 状态。如果您尝试声明一个常量 则会出现语法错误:

const myConstant;
Uncaught SyntaxError: missing = in const declaration

尝试按照您可能想要的方式更改使用 const 声明的变量的值 使用 let(或 var)更改声明的变量的值会导致类型 错误:

const myConstant = true;

myConstant = false;
> Uncaught TypeError: invalid assignment to const 'myConstant'

不过,当常量与对象关联时,该常量的属性将 对象可以更改的。

const constantObject = { "firstvalue" : true };

constantObject
> Object { firstvalue: true }

constantObject.secondvalue = false;

constantObject
> Object { firstvalue: true, secondvalue: false }

包含对象的常量是不可变的 对可变数据值的引用。 虽然常量本身无法更改,但所引用项的属性 对象:

const constantObject = { "firstvalue" : true };

constantObject = false
> Uncaught TypeError: invalid assignment to const 'constantObject'

如果您预计变量不会重新赋值,最佳做法是将该变量设为 常量。使用 const 可告知开发团队或未来的维护人员 不要更改该值,以免破坏代码的假设 决定如何使用它,例如,某个变量最终 针对预期数据类型进行评估的。

变量范围

变量的作用域是指脚本中该变量可用的部分。 在变量的作用域之外,不会将其定义为标识符 包含 undefined 值,但好像尚未声明一样。

根据您用于声明变量的关键字以及 在定义变量后,您可以将变量作用域限定为屏蔽语句(屏蔽作用域), 单个函数(函数范围),或整个 JavaScript 应用 (全局范围)。

屏蔽范围

您使用 letconst 声明的任何变量的作用域都限定为最接近的变量 包含 block 语句, 也就是说,只能在该块内访问该变量。正在尝试 访问包含块的块级范围的变量时,会导致同样 尝试访问不存在的变量时发生错误:

{
    let scopedVariable = true;
    console.log( scopedVariable );
}
> true

scopedVariable
> ReferenceError: scopedVariable is not defined

就 JavaScript 而言,块级范围的变量不存在 在包含它的块之外。例如,您可以声明一个常量, 然后在该代码块之外声明另一个常量,该常量使用 相同的标识符:

{
  const myConstant = false;
}
const myConstant = true;

scopedConstant;
> true

虽然声明的变量无法扩展到其父块中,但它 可用于所有后代块:

{
    let scopedVariable = true;
    {
    console.log( scopedVariable );
    }
}
> true

可以在后代块中更改声明的变量的值:

{
    let scopedVariable = false;
    {
    scopedVariable = true;
    }
    console.log( scopedVariable );
}
> true

可通过在后代内使用 letconst 来初始化新变量 块中没有任何错误,即使它使用的标识符与变量中的变量相同, 父块:

{
    let scopedVariable = false;
    {
    let scopedVariable = true;
    }
    console.log( scopedVariable );
}
> false

函数范围

使用 var 声明的变量的作用域限定为最接近的包含函数 (或中的静态初始化块)。

function myFunction() {
    var scopedVariable = true;

    return scopedVariable;
}

scopedVariable;
> ReferenceError: scopedVariable is not defined

调用函数后,情况仍然如此。虽然 一个变量是在函数执行时进行初始化的,则该变量仍然 在函数范围之外不可用:

function myFunction() {
    var scopedVariable = true;

    return scopedVariable;
}

scopedVariable;
> ReferenceError: scopedVariable is not defined

myFunction();
> true

scopedVariable;
> ReferenceError: scopedVariable is not defined

全局范围

全局变量在整个 JavaScript 应用中都可用, 添加到网页上的任何脚本中。

虽然这看起来似乎很不错,但 可能会增加不必要的开销,甚至可能导致 与应用中其他位置具有相同标识符的变量冲突。 这适用于网页呈现过程中涉及的所有 JavaScript 包括第三方库和用户分析等因此, 遵循最佳实践,尽可能避免污染全局范围

在父函数之外使用 var 或者使用 let 或 在父块外的 const 是全局性的:

var functionGlobal = true; // Global
let blockGlobal = true; // Global

{
    console.log( blockGlobal );
    console.log( functionGlobal );
}
> true
> true

(function() {
    console.log( blockGlobal );
    console.log( functionGlobal );
}());
> true
> true

在未明确声明的情况下为变量赋值(也就是说, 绝不使用 varletconst 来创建)会将变量提升为 全局作用域,即使在函数或块内初始化时也是如此。变量 使用这种模式创建的内容有时称为“隐式全局”。

function myFunction() {
    globalVariable = "global";

    return globalVariable
}

myFunction()\
> "global"

globalVariable\
> "global"

变量提升

变量和函数声明会提升到其作用域的顶部, JavaScript 解释器会处理在任何阶段 并有效地将其移到包含所选脚本的第一行 作用域。也就是说,使用 可以在声明变量之前引用 var,而不会遇到 错误:

hoistedVariable
> undefined

var hoistedVariable;

由于只托管变量声明,而不是初始化, 尚未使用 varletconst 明确声明的变量 未提升:

unhoistedVariable;
> Uncaught ReferenceError: unhoistedVariable is not defined

unhoistedVariable = true;

如前所述,一个已声明但未初始化的变量 分配的值为 undefined。该行为适用于提升的变量 声明,但仅限于使用 var 声明的那些。

hoistedVariable
> undefined

var hoistedVariable = 2 + 2;

hoistedVariable\
> 4

这种不直观的行为在很大程度上阻碍了 最早的 JavaScript 版本,并且无法更改,除非出现 破坏现有网站

letconst 解决了此行为,方法是在发生以下情况时抛出错误: 变量在创建之前对其进行访问:

{
    hoistedVariable;

    let hoistedVariable;
}
> Uncaught ReferenceError: can't access lexical declaration 'hoistedVariable' before initialization

此错误与“hoistedVariable is notundefined”不同出错了 。由于 JavaScript 已经提升该变量,但知道该变量将在 给定的范围。不过,与其让该变量在其 值为 undefined 时,解释器会抛出错误。 使用 letconst(或 class)声明的变量称存在于 “时间死区”(“TDZ”) 在代码中声明变量的位置。

时间死区使得 let 的行为比 var 更直观: 作者。它对于 const 的设计也至关重要。因为常数不能 已更改,一个提升到其作用域顶部且给定隐式值的常量 有 1 个 undefined 无法使用任何有意义的值进行初始化。

检查您的理解情况

标识符可以使用哪些类型的字符开头?

数字
下划线
字母

如果要声明某个变量的值, 可以随时更改?

变量
const