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
Theme Stack designed by Jimmy