zoukankan      html  css  js  c++  java
  • JavaScript var、let、const 关键字

    var 关键字

    函数作用域

    使用 var 操作符定义的变量会成为包含它的函数的局部变量。比如,使用 var 在一个函数内部定义一个变量,就意味着该变量将在函数退出时被销毁:

    function sayHello() {
    	var message = 'Hello'
    	console.log(message)
    }
    
    sayHello()	// Hello
    console.log(message)	// ReferenceError: message is not defined
    

    全局变量

    去掉之前的 var 操作符之后,message 就变成了全局变量。只需要调用一次函数 sayHello(),就会定义这个全局变量,并且可以在函数外部访问到:

    function sayHello() {
    	message = 'Hello'
    	console.log(message)
    }
    
    sayHello()	// Hello
    console.log(message)	// Hello
    

    注意:

    • 声明全局变量时,必须给全局变量赋值,否则会报错;
    • 虽然可以通过省略 var 操作符定义全局变量,但不推荐这么做。在局部作用域中定义的全局变量很难维护,也会造成困惑。
    • 严格模式下,如果像这样给未声明的变量赋值,则会导致抛出 ReferenceError

    变量提升

    使用 var 时,下面的代码不会报错。这是因为使用这个关键字声明的变量会自动提升到函数作用域顶部:

    function sayHello() {
    	console.log(message)
    	var message = 'Hello'
    }
    
    sayHello()	// undefined
    

    之所以不会报错,是因为 ECMAScript 运行时把它看成等价于如下代码:

    function sayHello() {
    	var message
    	console.log(message)
    	message = 'Hello'
    }
    
    sayHello()	// undefined
    

    这就是所谓的“提升”(hoist),也就是把所有变量声明都拉到函数作用域的顶部。此外,反复多次使用 var 声明同一个变量也没有问题:

    function sayHello() {
    	var message = 'Hello'
    	var message = 'World'
    	var message = 'Hello, World!'
    	console.log(message)
    }
    
    sayHello()	// Hello, World!
    

    let 关键字

    块级作用域

    块级作用域的表现形式和 Java、Python 等语言变量一致。块作用域是函数作用域的子集,因此适用于 var 的作用域限制同样也适用于 let

    for (var i = 0; i < 5; i++) {
    	// nothing to do here.
    }
    console.log(i)	// 5
    
    for (let j = 0; j < 5; j++) {
    	// nothing to do here.
    }
    console.log(j)	// ReferenceError: j is not defined
    

    在上述代码中,因为用 var 声明的变量具有函数作用域的特性。对于 for 循环,因为不是函数,所以在语句内声明的变量在外部也能使用;而用 let 声明的变量具有块级作用域的特性,所以在语句块({})内声明的变量,只能在语句块内使用,退出语句块时变量会被销毁。

    暂时性死区

    letvar 的另一个重要区别就是:let 声明的变量不会在作用域中被提升。

    console.log(name)	// undefined
    var name = '张三'
    
    console.log(age)	// ReferenceError: Cannot access 'age' before initialization
    let age = 22
    

    在解析代码时,JavaScript 引擎也会注意出现在块后面的 let 声明,只不过在此之前不能以任何方
    式来引用未声明的变量。在 let 声明之前的执行瞬间被称为“暂时性死区”(temporal dead zone),在此
    阶段引用任何后面才声明的变量都会抛出 ReferenceError

    let name = '张三'
    let name = '李四'	// SyntaxError: Identifier 'name' has already been declared
    let name = '王五'
    console.log(name)
    

    因为使用 let 声明的变量不存在变量提升现象,所以不能使用 let 同时声明多个相同标识符的变量。但是因为使用 let 声明的变量具有块级作用域的特性,在不同块级作用域中声明相同的变量是合法的:

    let name = '张三'
    
    if (true) {
    	// console.log(name)	// ReferenceError: Cannot access 'name' before initialization
    	let name = '李四'
    	console.log(name)	// 李四
    }
    
    console.log(name)	// 张三
    

    全局声明

    var 关键字不同,使用 let 在全局作用域中声明的变量不会成为 window 对象的属性(var
    明的变量则会)。

    var name = '张三'
    console.log(window.name)	// 张三
    
    let age = 22
    console.log(window.age)		// undefined
    

    for 循环比较

    for (var i = 0; i < 5; i++) {
    	setTimeout(() => console.log(i), 500)
    }
    
    // 5 5 5 5 5
    
    for (let i = 0; i < 5; i++) {
    	setTimeout(() => console.log(i), 500)
    }
    
    // 0 1 2 3 4
    

    第一个输出结果可能有点超乎我们的意料,仔细想想,这是因为 var 声明变量函数作用域特性导致的,最后打印的都是同一个变量 i,其值为 5;而在使用let 声明迭代变量时,JavaScript 引擎在后台会为每个迭代循环声明一个新的迭代变量。每个setTimeout 引用的都是不同的变量实例,所以console.log 输出的是我们期望的值,也就是循环执行过程中每个迭代变量的值。

    这种每次迭代声明一个独立变量实例的行为适用于所有风格的 for 循环,包括 for-infor-of 循环。

    const 关键字

    const 的行为与let 基本相同,唯一一个重要的区别是用它声明变量时必须同时初始化变量,且尝试修改 const 声明的变量会导致运行时错误。

    JavaScript 引擎会为for 循环中的let 声明分别创建独立的变量实例,虽然const 变量跟let 变量很相似,但是不能用const 来声明迭代变量(因为迭代变量会自增)。

    for (const i = 0; i < 5; i++) {	// TypeError: Assignment to constant variable.
    	// nothing to do here.
    }
    

    不过,如果你只想用const 声明一个不会被修改的for 循环变量,那也是可以的。也就是说,每次迭代只是创建一个新变量。这对for-offor-in 循环特别有意义:

    const stu = {
    	name: '张三',
    	age: 22,
    	gender: '男'
    }
    
    for (const keyVal of Object.entries(stu)) {
    	console.log(keyVal)
    }
    
    // [ 'name', '张三' ]
    // [ 'age', 22 ]
    // [ 'gender', '男' ]
    

    总结

    不使用 var

    有了letconst,大多数开发者会发现自己不再需要var 了。限制自己只使用letconst有助于提升代码质量,因为变量有了明确的作用域、声明位置,以及不变的值。

    const 优先,let 次之

    使用const 声明可以让浏览器运行时强制保持变量不变,也可以让静态代码分析工具提前发现不合法的赋值操作。因此,很多开发者认为应该优先使用const 来声明变量,只在提前知道未来会有修改时,再使用let。这样可以让开发者更有信心地推断某些变量的值永远不会变,同时也能迅速发现因意外赋值导致的非预期行为。

  • 相关阅读:
    oracle之check约束小结
    非归档模式下使用Rman进行备份和恢复
    R中,定义一个长度为0的向量
    R中,去掉dataframe中的NA行
    Oracle数据库的后备和恢复————关于检查点的一些知识
    关于oracle修复控制文件与数据文件不一致的问题----
    《SLAM机器人基础教程》第三章 单片机与STM32:GPIO实验及Keil软件使用WatchWindows进行Debug调试
    《SLAM导航机器人基础》第三章:单片机与STM32:单片机概述和Keil开发环境配置
    《SLAM导航机器人基础》第二章:C/C++编程(后)
    《SLAM导航机器人基础》第二章:C/C++编程(中)
  • 原文地址:https://www.cnblogs.com/haveadate/p/var_let_const.html
Copyright © 2011-2022 走看看