JS - 变量 var/let/const, 声明最佳实践

301 阅读4分钟

标识符

标识符就是变量、函数、属性或者函数参数的名称,一般使用 小驼峰; 关键字不能作为标识符

var variableName = "xxx";
function funName(argName) {
    xxx
};

var 声明变量

// 不初始化的情况下,变量的值时 undefined
var variableName; 
// 定义变量并赋值
var str = "abc";
// 定义多个变量, 每个变量使用逗号隔开
var v1 = 1, v2 = 2, v3 = 3;

var 声明作用域

var 操作服定义的变狼会成为包含它的函数的局部变量

function fn() {
    // 局部变量, 在函数退出时被销毁
    var msg = "hi"; 
}
fn();
console.log(message); // 出错

如果省略 var 关键字,可能会造成创建一个全局变量;

注意: 在严格模式下 使用 "use strict"; 如果给未声明的变量赋值,会导致 ReferenceError 异常

function fn() {
    // 当 fn 被调用的时候会被创建一个全局变量 msg
    msg = "hi"; 
}
fn();
// “hi”
console.log(msg); 

var 声明提升

变量提升,就是把所有变量声明都放到函数作用域顶部,此外反复使用 var 声明同一个变量也没有问题(最终会覆盖的)

function foo() {
    console.log(age); // undefined
    var age = 26;
}
foo();

// 如上的代码相当于这样
function foo() {
    // 这就是变量提升,就是把所有变量都
    var age;
     console.log(age); // undefined
    age = 26;
}
foo();

let 声明

let 也可以声明变量,let 声明的范围是块作用域,而 var 声明的范围是函数作用域。

var name;
// var 可以允许重复声明
var name; 

let age;
// let 重复声明将会报错、let 不允许同一个块作用域中出现冗余声明
let age; 

对于声明冗余报错不会因为 混用 let 和 var 而受影响

var name;
let name; // SyntaxError

暂存性死区

const、let 声明的变量不会在作用域中被提升; js 引擎不允许以在let 声明之前的任何方式来引用 其变量。

// 因为 const、let 声明的变量不会被提升, 所以会出现 ReferenceError
console.log(num);
let age = 26;

全局变量

let 声明的变量不会挂载到 window 对象的属性上,var 声明的变量则会,不过 let 声明仍然会在全局作用域中发生,相应变量会在 页面的生命周期内存续。

var name = "varStr";
console.log(window.name); // varStr

let age = 26;
console.log(window.age); // undefined;

let 不能依赖条件声明模式,如尝试检查 一个变量是否为 undefined,如果 为 undefined 则使用 let 声明

if(typeof name === "undefined") {
    let name = "kj"; // 这牙膏 name 就被限制在了 if {} 块中
}

for 循环中的 let 声明

在 let 出现之前,for 循环 var 定义的迭代变量会被渗透到循环体外部

for(var i = 0; i < 5; i++) {
 // 循环逻辑
}

console.log(i); // 5, 糟糕 i 被渗透到了 for 循环体外部

以为 let 声明的是 块级作用域,因此声明的变量只会绑定到 let 出现在 {} 内部

for (let i = 0; i < 5; i++) {
    // xxxx
}
console.log(i); // ReferenceError, 太棒了, i 没有渗透出来

const 声明

const 的行为和 let 基本相同,区别在于 const 声明变量时必须同时使用初始化变量,初始化后不能修改其变量的引用。

const str = "hi";
str = "hello"; // TypeError

const 声明的限制只适用于它指向的变量的引用,换句话说,如果 const 变量引用的是一个对象,那么修改这个对象内部的属性并不违反 const 的限制

const person = {
    age: 23,
};

person.age = "33"; // 没有问题

person = "hello"; // 错误,因为 这个改变了变量的引用

const 的循环

如果在 for 循环中 迭代变量是变化的,则不能使用 const 来声明,如果迭代变量是不变化的则可以使用 const 来定义

// error
for (const i = 0; i < 10; i++) {} // TypeError 给常量 i 赋值了

// ok
for (const key in { a:1,b:2 }) {
    console.log(key);
}

声明风格以及最佳实践

  1. 不使用 var, var 的维护成本高,不小心就定义了全局变量、变量声明提升等问题

  2. const 优先、let 次之

    const 声明可以让那个浏览器运行时强制保持变量不变,也可以静态代码分析工具提前发现不合法的赋值操作,只在提前知道未来会有修改时,再使用 let。