implements package public
interface protected static
let private
模块代码中保留
await
[](()声明变量并赋值
在 JavaScript 中,有 3 个关键字可以声明变量: var
、const
和 let
。其中,var
在 ECMAScript
的所有版本中都可以使用,而 const
和let
只能在ECMAScript 6
(将在后面学到) 及更晚的版本中使用。
[](()var 关键字
要定义变量,可以使用 var
关键字,后跟变量名:
var xhsRookies
这行代码定义了一个名为 xhsRookies
的变量,可以用它保存任何类型的值。ECMAScript
实现变量初始化,因此可以同时定义变量并设置它的值:
var xhsRookies = ‘hi’
xhsRookies
被定义为一个保存字符串值hi
的变量。像这样初始化变量不会将它标识为字符串类型,只是一个简单的赋值而已。随后,不仅可以改变保存的值,也可以改变值的类型:
var xhsRookies = ‘hi’
xhsRookies = 100 // 合法,但不推荐
在这个例子中,变量 xhsRookies
首先被定义为一个保存字符串值hi
的变量,然后又被重写为保存了数值 100 。虽然不推荐改变变量保存值的类型,但这在ECMAScript
中是完全有效的。
1. var 声明作用域
使用 var
操作符定义的变量会成为包含它的函数的局部变量。比如,使用 var
在一个函数内部定义一个变量,就意味着该变量将在函数退出时被销毁:
function xhsTest() {
var xhsRookies = ‘hi’ // 局部变量
}
xhsTest()
console.log(xhsRookies) // 出错!
这里,xhsRookies
变量是在函数内部使用var
定义的。函数叫 xhsTest()
,调用它会创建这个变量并给它赋值。调用之后变量随即被销毁,因此示例中的最后一行会导致错误。不过,在函数内定义变量时省略 var
操作符,可以创建一个全局变量:
function xhsTest() {
xhsRookies = ‘hi’ // 全局变量
}
xhsTest()
console.log(xhsRookies) // “hi”
去掉之前的 var
之后,xhsRookies
就变成了全局变量。只要调用一次函数 xhsTest()
,就会定义这个变量,并且可以在函数外部访问到。
虽然可以通过省略 var 操作符定义全局变量,但不推荐这么做。在局部作用域中定义的全局变量很难维护,也会造成困惑。
如果需要定义多个变量,可以在一条语句中用逗号分隔每个变量(及可选的初始化):
var xhsRookies = ‘hi’,
xhsFound = false,
xhsNumber = 29
这里定义并初始化了 3 个变量。
2. var 声明提升
使用 var
时,下面的代码不会报错。这是因为使用这个关键字声明的变量会自动提升到块作用域 5 顶部:
{
console.log(xhsNumber) // undefined
var xhsNumber = 26
}
之所以不会报错,是因为 ECMAScript 运行时把它看成等价于如下代码:
{
var xhsNumber
console.log(xhsNumber) // undefined
xhsNumber = 26
}
这就是所谓的“提升”(hoist),也就是把所有变量声明都拉到块作用域的顶部。
[](()let 声明
let
跟 var
的作用差不多,但有着非常重要的区别。最明显的区别是,let
声明的范围是块作用域, 而var
声明的范围是函数作用域。
{
var xhsRookies = ‘xhs-rookies’
console.log(xhsRookies) // xhs-rookies
}
console.log(xhsRookies) // xhs-rookies
{
let xhsNumber = 26
console.log(xhsNumber) // 26
}
console.log(xhsNumber) // ReferenceError: xhsNumber 没有定义
在这里,xhsNumber
变量之所以不能在块作用域外部被引用,是因为它的作用域仅限于该块内部。块作用域是函数作用域的子集,因此适用于 var
的作用域限制同样也适用于let
。
let
也不允许同一个块作用域中出现冗余声明。这样会导致报错:
var xhsRookies
var xhsRookies
let xhsNumber
let xhsNumber // SyntaxError;标识符xhsNumber已经声明过了
当然,JavaScript 引擎会记录用于变量声明的标识符及其所在的块作用域,因此嵌套使用相同的标识符不会报错,而这是因为同一个块中没有重复声明:
var xhsRookies = ‘xhs-rookies’
console.log(xhsRookies) // ‘xhs-rookies’
{
var xhsRookies = ‘xhs-rookies-boy’
console.log(xhsRookies) // ‘xhs-rookies-boy’
}
let xhsNumber = 30
console.log(xhsNumber) // 30
{
let xhsNumber = 26
console.log(xhsNumber) // 26
}
对声明冗余报错不会因混用let
和 var
而受影响。这两个关键字声明的并不是不同类型的变量, 它们只是指出变量在相关作用域如何存在。
var xhsRookies
let xhsRookies // SyntaxError
let xhsNumber
var xhsNumber // SyntaxError
1. 全局声明
与var
关键字不同,使用 let
在全局作用域中声明的变量不会成为window
对象的属性(var
声明的变量则会)。
var xhsRookies = ‘xhsRookies’
console.log(window.xhsRookies) // ‘xhsRookies’
let xhsNumber = 26
console.log(window.xhsNumber) // undefined
不过,let
声明仍然是在全局作用域中发生的,相应变量会在页面的生命周期内存续。因此,为了 避免 SyntaxError
,必须确保页面不会重复声明同一个变量。
2. let 作用域
在 let出现之前,代码块中定义的迭代变量会渗透到外部:
{
var xhs = 5
}
console.log(xhs) // 5
改成使用 let 之后,这个问题就消失了,因为 let 变量的作用域仅限于代码块内部:
{
let xhs = 0
}
console.log(xhs) // ReferenceError: xhs 没有定义
[](()const 声明
const
的行为与let
基本相同,唯一一个重要的区别是用它声明变量时必须同时初始化变量,且尝试修改 const
声明的变量会导致运行时错误。
const xhsNumber = 26
xhsNumber = 36 // TypeError: 给常量赋值
// const 也不允许重复声明
const xhsRookies = ‘xhs-rookies’
const xhsRookies = ‘xhs-rookies-boy’ // SyntaxError
// const 声明的作用域也是块
const xhsRookies = ‘xhs-rookies’
console.log(xhsRookies) // xhs-rookies
[](()变量命名规则
-
严格区分大小写(大写的变量和小写的变量是不同的变量);
-
变量名可以由数字、字母(大小写都可以)、下划线、美元符($)组成,但是不能以数字开头;
-
不能是 javascript 中的关键字和保留字,如:if,else,function 等;
-
变量名需要有意义,即语义化,增强代码可读性,比如:存储年龄用 age,姓名用 name,可以防止过段时间就不理解代码是什么了,也可以防止合作时别人看不懂;
-
使用驼峰命名法:从第二个单词开始,首字母大写,如用户个人数据(userPersonalData);
[](()题目自测
[](()一:下列代码输出结果是什么?
var xhsRookies = ‘hello’
function textFun() {
var xhsRookies = ‘hi’
}
console.log(xhsRookies)
A. hello
B. hi
C 《大厂前端面试题解析+Web核心总结学习笔记+企业项目实战源码+最新高清讲解视频》无偿开源 徽信搜索公众号【编程进阶路】 . hi hello
D. hello hi
Answer:A
这道题考查的是 var 声明作用域,在第一行 xhsRookies
变量在 textFun
函数作用域外使用 var
定义的,第三行xhsRookies
变量是在textFun
作用域内部使用 var 定义的。所以最后一行输出 xhsRookies
其实是第一行定义的,结果是:hello