Featured image of post 【JavaScript 变数】var let const 变数定义方式比较差异

【JavaScript 变数】var let const 变数定义方式比较差异

【JavaScript 变数】var let const 变数定义方式比较差异

Photo by Mohammad Rahmani on Unsplash

定义方式

定义方式 说明
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

Reference

Donate KJ 贊助作者喝咖啡

如果這篇文章對你有幫助的話,可以透過下面支付方式贊助作者喝咖啡,如果有什麼建議或想說的話可以贊助並留言給我
If this article has been helpful to you, you can support the author by treating them to a coffee through the payment options below. If you have any suggestions or comments, feel free to sponsor and leave a message for me!
方式 Method 贊助 Donate
PayPal https://paypal.me/kejyun
綠界 ECPay https://p.ecpay.com.tw/AC218F1
歐付寶 OPay https://payment.opay.tw/Broadcaster/Donate/BD2BD896029F2155041C8C8FAED3A6F8
All rights reserved,未經允許不得隨意轉載
Built with Hugo
主题 StackJimmy 设计