var、let、const

JavaScript中的变量声明目前有三种:var、let、const。let和const是JavaScript里相对较新的变量声明方式。 let在很多方面与var是相似的,但是可以帮助大家避免在JavaScript里常见一些问题。 const是对let的一个增强,它能阻止对一个变量再次赋值。

var

  1. 奇怪的作用域规则
function f(shouldInitialize) {
    if (shouldInitialize) {
        var x = 10;
    }

    return x;
}

f(true);  // returns '10'
f(false); // returns 'undefined'

变量 x是定义在if语句里面,但是我们却可以在语句的外面访问它。 这是因为 var声明可以在包含它的函数,模块,命名空间或全局作用域内部任何位置被访问,包含它的代码块对此没有什么影响。 有些人称此为var作用域或函数作用域。 函数参数也使用函数作用域。

  1. 捕获变量的怪异之处
for (var i = 0; i < 10; i++) {
    setTimeout(function() { console.log(i); }, 100 * i);
}

输出 >>

10
10
10
10
10
10
10
10
10
10

相信大部分时候我们的期望输出是

0
1
2
3
4
5
6
7
8
9

原因:console输出的 i与for循环中的 i是同一个作用域里头的同一个 i,setTimeout后执行console.log时 i已经结束了循环,值已然是10了。
通常的一个解决办法是采用立即执行函数表达式(IIFE)来捕获每次循环时候的 i

for (var i = 0; i < 10; i++) {
    (function(i){
        setTimeout(function() { console.log(i); }, 100 * i)
    })(i);
}

let

  1. 块作用域
function f(input) {
    let a = 100;

    if (input) {
        // Still okay to reference 'a'
        let b = a + 1;
        return b;
    }

    // Uncaught ReferenceError: b is not defined
    return b;
}

a的作用域是f函数内,b的作用域是if语句块内

a++; // Uncaught ReferenceError: a is not defined
let a;

拥有块级作用域的另一个显著特点就是:不能先调用再定义,因为不会像var一样做变量提升

function foo() {
    // okay to capture 'a'
    return a;
}

// 不能在'a'被声明前调用'foo'
// 运行时应该抛出错误
foo();

let a;

注意:我们仍然可以在一个拥有块作用域变量被声明前获取它。 只是我们不能在变量声明前去调用那个函数。
如果改成下面的代码,就没毛病 >>

function foo() {
    // okay to capture 'a'
    return a;
}

let a;

foo();
  1. 重定义及屏蔽
let x = 10;
let x = 20; //Uncaught SyntaxError: Identifier 'x' has already been declared

在一个嵌套作用域里引入一个新名字的行为称做屏蔽。 它是一把双刃剑,它可能会不小心地引入新问题,同时也可能会解决一些错误。

function sumMatrix(matrix) {
    let sum = 0;
    for (let i = 0; i < matrix.length; i++) {
        var currentRow = matrix[i];
        for (let i = 0; i < currentRow.length; i++) {
            sum += currentRow[i];
        }
    }

    return sum;
}

这中写法的循环能得到正确的结果,因为内层循环的i可以屏蔽掉外层循环的i。

  1. 块级作用域变量的获取

let声明出现在循环体里时拥有完全不同的行为。 不仅是在循环里引入了一个新的变量环境,而是针对 每次迭代都会创建这样一个新作用域。 这就是我们在使用立即执行的函数表达式时做的事,所以在 setTimeout例子里我们仅使用let声明就可以了。

for (let i = 0; i < 10; i++) {
    setTimeout(function() { console.log(i); }, 100 * i);
}

const

与let声明相似,但是就像它的名字所表达的,被赋值后不能再改变。

const obj = {name: 'qingqinxl', age: 18};
obj = {name:'Lily', age:18}; //Uncaught TypeError: Assignment to constant variable.

obj内部状态可以被修改

obj.name = 'Lily';
obj.age = obj.age + 1;
// obj
// {name: "Lily", age: 19}

let vs const

所有变量除了你计划去修改的都应该使用const。

你可能感兴趣的:(var、let、const)