var let const 定义方式比较

Node.js var let const 定义方式比较

定义方式

定义方式 说明
const 不会被重新指定值的变数 e.g. const PI = 3.14159
let 在指定区块才有效用的变数
var 在整个函式或区块中皆可以取用

var

在 function 外的 var 可以被 function 取用

var my_name = "KJ";
function sayMyName() {
    // KJ
    console.log(my_name);
}

sayMyName();

在 function 内的 var 无法被外面取用

function defineMyName() {
    var my_name = "KJ";
}
//  my_name is not defined
console.log(my_name);

同样变数 可以 重新定义

不建议使用,会导致变数定义混乱

var my_name = "Kay";
var my_name = "Jay";

// Jay
console.log(my_name);

let

在 function 内的 let 无法被外面取用

function defineMyName() {
    let my_name = "KJ";
}
//  my_name is not defined
console.log(my_name);

内部变数与外部变数名称一样不会互相汙染

let my_name = "Kay";
if (true) {
    let my_name = "Jay";
    // Jay
    console.log(my_name);
}
// Kay
console.log(my_name);

同样变数无法重新定义

let my_name = "Kay";
// SyntaxError: Identifier 'my_name' has already been declared
let my_name = "Jay";

const

常数无法重新被赋予值

const my_name = "Kay";
my_name = "Jay";
// TypeError: Assignment to constant variable.
console.log(my_name);
const employee = {
    name: "Kay",
    age: 18
};

// TypeError: Assignment to constant variable.
employee = {
    name: "Jay",
    age: 17
}

常数物件数值可以被异动

const employee = {
    name: "Kay",
    age: 18
};
// { name: 'Kay', age: 18 }
console.log(employee);

// 变更常数物件数值
employee.name = "Jay";
employee.age = 17;

// { name: 'Jay', age: 17 }
console.log(employee);

同样变数无法重新定义

const my_name = "Kay";
// SyntaxError: Identifier 'my_name' has already been declared
const my_name = "Jay";

必须赋予初始值

// SyntaxError: Missing initializer in const declaration
const my_name;

var vs let vs const

类型 var let const
scope 范围 global 全域 block 区块 block 区块
re-declared 重新定义 X X
update 更新 X
赋予初始值 不限制 不限制 必要
function run() {
    var my_name = "Kay";
    let my_age = 19;

    // Kay 19
    console.log(my_name, my_age);

    {
        var their_name = "Jay"
        let their_age = 17;
        // Jay 17
        console.log(their_name, their_age);
    }

    // Jay
    console.log(their_name);
    // ReferenceError: their_age is not defined
    console.log(their_age);
}

run();

赋予值异动

var funcs = [];
// let's create 3 functions
for (var i = 0; i < 3; i++) {
    // and store them in funcs
    funcs[i] = function() {
        // each should log its value.
        console.log("My var value: " + i);
    };
}
for (var j = 0; j < 3; j++) {
    // and now let's run each one to see
    funcs[j]();
}
// My var value: 3
// My var value: 3
// My var value: 3

var i 最后已经变成 3 了,所以最后会印出三行 My var value: 3

var funcs = [];
// let's create 3 functions
for (let i = 0; i < 3; i++) {
    // and store them in funcs
    funcs[i] = function() {
        // each should log its value.
        console.log("My let value: " + i);
    };
}
for (var j = 0; j < 3; j++) {
    // and now let's run each one to see
    funcs[j]();
}
// My let value: 0
// My let value: 1
// My let value: 2

let i 只作用在 for 的 scope 中,所以最后会分别印他们当初传进去的值

经典问题

Scope 数值

var a = 1;
var b = 1;
var e = 1;

function test(a) {
    // undefined
    console.log(a);
    var b = 2;
    // 2
    console.log(b);

    if (true) {
        let c = 5;
        var d = 6;
        const e = 7;
    }

    // undefined
    console.log(c);
    // 6
    console.log(d);
    // 1
    console.log(e);
}

test();

i 执行到后面已经变成 6 了,然后接下来会执行 setTimeout 的程式,印出来的变数都是 6

for(var i = 1; i <= 5; i++) {
    setTimeout(function() {
        console.log(i)
    }, 0)
}
// 6
// 6
// 6
// 6
// 6

解决方式

使用 let 将变数定在 block 中,区块中会保留原本的数值

// 方法 1
for(let i = 1; i <= 5; i++) {
    setTimeout(function() { console.log(i) }, 0)
}
// 1
// 2
// 3
// 4
// 5

使用 IIFE 方式,事先将要处理的变数传入会立即执行的函式,将变数包在 block 中,这样执行的时候也可以拿到正确的值

// 方法 2 IIFE
for(var i = 1; i <= 5; i++) {
    (function (x) {
        setTimeout(function() { console.log(x) }, 0)
    })(i)
}

// 1
// 2
// 3
// 4
// 5

参考资料