JS基础-3|var、let和const的区别,作用域以及变量提升

511 阅读4分钟

开发中无时无刻不在定义变量,有局部变量,全局变量,私有变量等等,本章沉淀一下原始定义方式和现阶段的定义方式

原生JS定义变量及常量的方式

原生js定义变量使用var关键字定义,不使用var时就会创建全局变量。很容易混淆,所以形成了一些约定:

  • 全局变量:变量名使用大写字母,如:USERS
  • 局部变量:变量名使用小写字母,如:user
  • 函数变量:函数内部定义变量必须使用var

约定毕竟需要人进行约束,所以不可避免会出现一些意外状况。其次对于循环,两个同级别的循环定义同一个变量名(如i)会冲突,所以需要定义其他的变量名(如:m、n、j等),对于书写代码来说非常不友好。‘

原生JS变量

在ES6出来之前,var相关问题经常会被问到,在ES6出来之后,var仅成了对比,本篇沉淀一下var定义变量的一些历史知识点,对于此不熟悉的可以了解一下

变量作用域

变量作用域是前几年比较常见的问题之一,全局作用域、函数作用域,变量名相同时是什么样的等等。

全局作用域

在最外层定义的变量都具备全局作用域

var a = 1;
function test () {
  console.log(a)
}
test() // 1

由于a在function外面,所以具备全局作用域,函数内可以访问到全局作用域的变量a。

在函数内定义变量a会如何?

var a = 1;
function test () {
  var a = 2;
  console.log(a)
}
test() // 2
console.log(a) // 1

函数内部若定义了和外部一样的变量名,则优先读取函数内部的变量值。

那函数内部变量不带var?

var a = 1;
function test () {
  a = 2;
  console.log(a)
}
test() // 2
console.log(a) // 2

函数内部会读取全局作用域的a变量,同时进行修改

不在外部定义变量会怎么样

function test () {
  a = 2;
  console.log(a)
}
test() // 2
console.log(a) // 2

当不带var关键字时会创建全局作用域的变量,其实函数的执行如下:

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

原理就是变量提升,下面对变量提升进行了专门的解析

变量提升

早期JS中经常被提及的问题,如下代码:

function test () {
  console.log(a)
  var a = 1;
}
test(); // undefined

你认为undefined是因为a定义在了console后面么,非也,其实代码真正执行顺序:

function test () {
  var a;
  console.log(a)
  a = 1;
}
test();

上述是在函数内的变量提升,现在看一下函数外的变量提升

a = 1;
var a;
console.log(a)

输出是1,实际生命变量会提升到作用域顶端,具体如下

var a;
a = 1;
console.log(a)

来一道多年前的面试题,现在很少见的哦~

console.log(a);
var a = 1;
function test() {
  console.log(a);
  var a = 2;
  console.log(a);
}
test();
console.log(a); 

结果:undefined undefined 2 1

现在是不是很容易理解了,实际代码运行

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

ES6新增let和const命令

ES6为了解决原生JS遗留的问题,新增了let和const命令:

  • let 声明的变量,只在let命令所在的代码块内有效
  • const 一旦声明,常量的值就不能改变

上述两个命令解决了块级作用域及常量不可修改的问题。

let

let 用于定义变量,作用域范围为代码块内。

let a = 1; 
function test () {
  console.log(a) 
}; 
test();  // 1
console.log(a) // 1

在函数外面使用let定义和var没有太大区别,作用域基本一致。

但是:

var a = 1;
window.a // 1;
let b = 2;
window.b // undefined
const c = 3;
window.c // undefined

因此,基于var定义的变量会挂载在window上。

for循环是属于独立代码块,看一下let的表现

// 原生var
for(var j = 0; j < 3; j++) {}
console.log(j) // 3

// ES6的let
for(let i = 0; i < 3; i++) {}
console.log(i) // 报错

根据上述代码运行结果可以发现:let仅作用于代码块内

关于块级作用域

function test() {
  var n = 5;
  if (true) {
    var n = 10;
  }
  console.log(n);
}
test(); // 10

function test() {
  let n = 5;
  if (true) {
    let n = 10;
  }
  console.log(n);
}
test(); // 5

每个{}包裹的代码都属于块级作用域

const

const声明一个只读的常量。一旦声明,常量的值就不能改变。

const a = 1;
a = 2; // Uncaught SyntaxError: Identifier 'a' has already been declared

对于基础数据类型,const定义的变量是不可更改的。

const a = {
    key1: 1
}
a.key2 = 2; // { key1: 1, key2: 2 }
delete a.key1; // {key2: 2}
a = {}; // Uncaught TypeError: Assignment to constant variable.

对于复杂数据,可以添加或删除值,但不可重新赋值。

总结分析

  1. let定义的变量作用域为块作用域,
  2. const定义的变量不可直接赋值
  3. var定义的全局变量会挂载在window上

相关试题

  1. ES6新增了哪些特性。
  2. let、const和var的区别。
  3. let和const的特点。
  4. 变量提升相关试题(笔试)