关注前端小讴,浏览更多原创技术文章
变量
- ECMAScript 变量是 涣散类型 的:变量能够保留任何类型的数据
- 3 个申明变量的关键字:var、const、let
相干代码 →
var 关键字
- 不初始化时,变量保留 undefined
var message
console.log(message) // undefined
- 初始化变量只是设置变量的值,能够 扭转保留的值 ,也能够 扭转值的类型
var message = 'hi'
message = 100 // 非法,但不举荐
console.log(message) // 100
var 申明作用域
- 应用 var 操作符定义的变量,会成为 蕴含它的函数 的局部变量
- 函数退出(调用)时,该变量被销毁
function test() {var messageTest = 'hi' // 在函数外部创立变量并赋值}
test() // 调用函数,外部变量被销毁
console.log(messageTest) // ReferenceError: messageTest is not defined
- 在 函数内 定义变量时 省略 var 操作符 ,能够创立一个 全局变量
function test() {messageTest = 'hi' // 省略 var 操作符,全局变量}
test() // 调用函数,定义外部的全局变量
console.log(messageTest) // 'hi
-
不举荐在 函数外部 通过 省略 var 关键字 定义全局变量:
- 部分作用域中定义的全局变量很难保护
- 会造成困惑,无奈判定省略 var 是无意为之还是语法错误
- 严格模式下,抛出 ReferenceError
var 申明晋升
- 应用 var 申明的变量,(无论理论申明的地位在何处)会主动晋升到函数作用域顶部;如果申明不在函数内,则被晋升到全局作用域顶部
function foo() {console.log(age)
var age = 30
}
foo() // undefined,不报错,变量申明晋升到函数作用域顶部
console.log(age)
var age = 30 // undefined,不报错,变量申明晋升到全局作用域顶部
- 以上代码等价于:
var age
function foo() {
var age
console.log(age)
age = 30
}
foo() // undefined
console.log(age) // undefined
age = 30
- 可重复屡次应用 var 申明同一个变量
function fooAge() {
var age = 16
var age = 26
var age = 36
console.log(age)
}
fooAge() // 36,可重复屡次应用 var 申明同一个变量
let 申明
- 与 var 作用差不多,但申明范畴是 块作用域(var 是函数作用域)
if (true) {
var nameVar = 'Matt'
console.log(nameVar) // 'Matt'
}
console.log(nameVar) // 'Matt'
if (true) {
let nameLet = 'Matt' // 作用域仅限块外部
console.log(nameLet) // 'Matt'
}
console.log(nameLet) // ReferenceError: nameLet is not defined
- let 呈现过的同一个块作用域中,不容许呈现 冗余申明
var nameVar
var nameVar // var 容许反复申明同一个变量
let nameLet
let nameLet // Identifier 'nameLet' has already been declared,冗余申明
let nameVar // Identifier 'nameVar' has already been declared
var nameLet // Identifier 'nameLet' has already been declared
- 若同一个块中没有反复申明,可嵌套应用雷同的标识符
let ageNest = 30
console.log(ageNest) // 30
if (true) {
let ageNest = 28
console.log(ageNest) // 28,在不同的块中
}
暂时性死区
- let 申明的变量 不会在作用域中被晋升(var 能够晋升)
- 在 let 申明之前的执行霎时被称为“暂时性死区”,此阶段援用任何候面才申明的变量都会抛出 ReferenceError
console.log(ageVarPromote) // undefined
var ageVarPromote = 26
console.log(ageLetPromote) // ReferenceError: ageLetPromote is not defined
let ageLetPromote = 26
全局申明
- 在全局作用域中,let 申明的变量不会成为 window 对象的属性(var 申明的变量则会)
var nameVarWhole = 'Matt'
console.log(window.nameVarWhole) // 'Matt0',vscode 没有 window 对象,在浏览器印证
let nameLetWhole = 'Matt'
console.log(window.nameLetWhole) // undefined,vscode 没有 window 对象,在浏览器中印证
条件申明
- 对于 let 申明,不能依赖条件申明模式(条件申明是反模式,如果发现正在应用这个模式,则定有更好的代替形式)
// typeof 操作符
if (typeof nameLetCondition === 'undefined') {
let nameLetCondition = 'Matt' // 仅在块级作用域内
console.log(nameLetCondition) // 'Matt'
}
console.log(nameLetCondition) // ReferenceError: nameLetCondition is not defined
// try/catch 语句
try {console.log(nameLetCondition2)
} catch (error) {
let nameLetCondition2 = 'Matt' // 仅在块级作用域内
console.log(nameLetCondition2) // 'Matt'
}
console.log(nameLetCondition2) // ReferenceError: nameLetCondition2 is not defined
for 循环中的 let 申明
- let 申明迭代变量的作用域同样仅限于 for 循环块外部(var 会渗透到循环体内部)
for (var iVar = 0; iVar < 5; iVar++) {}
console.log(iVar) // 5,循环体内部受影响
for (let iLet = 0; iLet < 5; iLet++) {}
// console.log(iLet) // ReferenceError: iLet is not defined
- let 申明迭代变量,JS 引擎会为每个迭代循环申明新的迭代变量(var 保留的是导致循环退出的值)
// 应用 var 申明:退出循环时,迭代变量保留的是导致循环退出的值
for (var iVarDelay = 0; iVarDelay < 5; iVarDelay++) {
// 超时逻辑在退出循环后执行,此时变量的值为 5
setTimeout(() => {console.log(iVarDelay) // 5、5、5、5、5
}, 0)
}
// 应用 let 申明:为每个迭代循环申明新的迭代变量
for (let iLetDelay = 0; iLetDelay < 5; iLetDelay++) {
// 超时逻辑在退出循环后执行,变量值别离为每个新的迭代变量
setTimeout(() => {console.log(iLetDelay) // 0、1、2、3、4
}, 0)
}
const 申明
- 与 let 行为基本相同,但 申明时必须赋初始值
const ageConst // SyntaxError: Missing initializer in const declaration
- 尝试批改 const 定义的变量,会报错(或者说定义的是常量)
const ageConst = 26
ageConst = 28 // TypeError: Assignment to constant variable.
- const 也 不容许反复申明
const ageConst = 26
const ageConst = 28 // SyntaxError: Identifier 'ageConst' has already been declared
- const 申明的 作用域也是块
if (true) {const nameConst = 'Nicholas'}
console.log(nameConst) // ReferenceError: nameConst is not defined
-
const 申明的限度只实用于 指向的内存地址不得改变(指针):
- 对于根本类型来说,不得批改值
- 对于援用类型的对象来说,不得重写地址,但能够批改其外部属性
const person = {}
console.log(person.name) // undefined
person.name = 'Matt'
console.log(person.name) // 'Matt',未重写地址,仅批改对象的外部属性
person = {name: 'Matt'} // TypeError: Assignment to constant variable,重写地址
- 不能用 const 申明迭代变量,因为迭代变量会自增
for (const index = 0; index < 5; index++) {} // TypeError: Assignment to constant variable.
- 能够用 const 申明不会被批改的 for 循环变量,这对于 for-in 和 for-of 循环特地有意义
let i = 0
for (const j = 7; i < 5; i++) {console.log(j) // 7、7、7、7、7
}
for (const key in { a: 1, b: 2}) {console.log(key) // a、b
}
for (const value of 'Matt') {console.log(value) // 'M'、'a'、't'、't'
}
申明格调及最佳实际
-
尽量 不应用 var,只应用 let 和 const
- 变量有了 明确的作用域 、 申明地位 和不变的值
-
优先应用 const,let 次之
- 让浏览器运行时强制放弃变量不变,让动态代码剖析工具提前发现不非法的赋值操作
- 提前晓得会有批改再应用 let
总结 & 问点
操作符 | 重写值 | 作用域 | 申明晋升 | 在全局作用域中申明 | 申明冗余 | 条件申明模式 | for 循环中 | 最佳实际 |
---|---|---|---|---|---|---|---|---|
var | 能够 | 函数作用域 | 有 | 成为 window 对象的属性 | 容许 | 影响全局属性 | 迭代变量保留的是导致循环退出的值 | 尽量不必 |
let | 能够 | 块作用域 | 无 | 不成为 window 对象的属性 | 不容许 | 只影响块中属性 | 每个迭代循环申明一个新的迭代变量 | 次之 |
const | 不可,可批改对象外部属性 | 块作用域 | 无 | 不成为 window 对象的属性 | 不容许 | 只影响块中属性 | 只能申明不会被批改的 for 循环变量 | 首选 |
- 如何了解“JS 的变量是涣散类型”的?JS 变量初始化后,能够扭转值的类型么?
- 在函数中,用 var 操作符定义的变量,在调用函数后会怎么?若省略 var 操作符呢?
- 变量晋升的含意是什么?为什么不举荐在函数中用省略 var 操作符的方法定义全局变量?
- let 申明的范畴是什么?其在全局申明、条件申明和迭代循环时,有哪些特点?
- 具体阐明 let 申明和 var 申明有哪些异同?
- 能够批改用 const 申明的数组或对象的值或属性吗?为什么?
- 具体阐明 let 申明和 const 申明有哪些异同?
- 申明变量时,有哪些助于晋升生代码品质的最佳实际?