乐趣区

关于javascript:javascript高级程序设计学习笔记-33变量

关注前端小讴,浏览更多原创技术文章

变量

  • 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 申明有哪些异同?
  • 申明变量时,有哪些助于晋升生代码品质的最佳实际?
退出移动版