# 声明关键字

# 前言

  • es6 开始之后,又出现了letconst两个关键字用于声明变量,三个关键字存在一些细微的区别,这里从区别性方面出发,总结一下。

    注:某些示例代码因为letconst的表现一致,所以统一用let作为示例,有不同的时候会特意说一下const

  • 变量提升 and 函数提升与普通变量提升的区别

# let var const 区别

# 作用域区别

  • var 声明变量会挂载在全局对象(浏览器环境就是 window 对象),函数作用域。
  • let,const 不会,块级作用域,就是一个大括号包裹的代码块。
  • 注意如果变量不加声明的关键字,默认就是挂载在全局对象上。
// 代码块1 声明挂载全局变量上
var bar = 'bar';
let foo = 'foo';

console.log(window.bar); // bar
console.log(window.foo); // undefined

// 代码块2 作用域
{
  let b = 2;
  var a = 1;
}
function fn() {
  var c = 3;
  d = 10;
}
fn();

console.log(a); // 1
console.log(d); // 10
console.log(window.d); // 10
console.log(c); // Uncaught ReferenceError: c is not defined // 函数作用域
console.log(b); // Uncaught ReferenceError: b is not defined // 块级作用域

# 重复声明

  • var 可,会进行值的覆盖。
  • let,const 不可。
var a = 1;
var a = 2;

console.log(a); // 2

let b = 1;
let b = 2; // Uncaught SyntaxError: Identifier 'b' has already been declared

# 声明前可否使用(变量提升,暂时性死区)

  • var 可,存在变量提升。
  • let,const 不可,存在暂时性死区,声明前的区域不能使用该变量大概就是暂时性死区的意思。
console.log(a); // undefined
var a = 1;
// 等价于
// var a;
// console.log(a);
// a = 1;

console.log(b); // Uncaught ReferenceError: b is not defined
let b = 1;

# 声明前是否必须赋值

  • var,let 不需要。
  • const 在声明时就需要显性指定赋值,否则报错Uncaught SyntaxError: Missing initializer in const declaration
var a;
let b;
const c; // Uncaught SyntaxError: Missing initializer in const declaration

# 常量

const 声明的变量为常量,变量为基础类型则值不可变,引用类型时则引用的指针值不可变。

const a = 1;
const obj = { a: 1 };

obj.a = 2; // 不报错,因为引用不变
a = 2; // Uncaught TypeError: Assignment to constant variable

# 变量提升

其实应该叫变量声明提升。

  • 只有声明被提升,初始化不会被提升。
  • 声明会被提升到当前作用域的顶端。
  • 普通变量和函数声明都存在提升,另外函数function关键字声明的是整个声明和赋值都会提升。
  • 注意:变量的函数赋值与普通的变量赋值表现一致,即函数的赋值不会提升。

说了这么多,看几个经常会遇到的题目对比一下就清楚了:

console.log(a); // undefined
var a = 1;
console.log(a); // f a() {}
console.log(a()); // 2
function a() {
  return 2;
}
console.log(a); // undefined
console.log(a()); // Uncaught TypeError: a is not a function
var a = function() {
  // 这种方式声明的函数赋值操作不会提升
  return 2;
};

# 函数提升与变量提升优先级

如果一个同名变量,又被声明为函数,又用 var 声明,两者间都存在变量提升,优先级怎么样呢?

  • 函数提升变量提升之前。

  • 变量的问题,莫过于声明赋值两个步骤,而这两个步骤是分开的。

  • 函数声明被提升时,声明和赋值两个步骤都会被提升,而普通变量却只能提升声明步骤,而不能提升赋值步骤

  • 变量被提升过后,先对提升上来的所有对象统一执行一遍声明步骤,然后再对变量执行一次赋值步骤。而执行赋值步骤时,会优先执行函数变量的赋值步骤再执行普通变量的赋值步骤

  • 先解析,再按顺序执行。

来看两个例子:

  • # 例子1:

console.log(a); // f a() {} 不管var a = 1;function a() {};哪行代码在前此处都是函数
var a = 1;
function a() {}
console.log(a); // 1

// 等价于

预编译后等价于:

var a;
function a
a = () {} // 此处都是优先函数的赋值
console.log(a);
a = 1;
console.log(a);
  • # 例子2:

var foo = 'hello';
(function(foo) {
  console.log(foo);
  var foo = foo || 'world';
  console.log(foo);
})(foo);
console.log(foo);
// 依次输出 hello hello hello

预编译后等价于:

var foo = 'hello';
(function(foo) {
  var foo; // undefined;
  foo = 'hello'; //传入的foo的值
  console.log(foo); // hello
  foo = foo || 'world'; // 因为foo有值所以没有赋值world
  console.log(foo); //hello
})(foo);
console.log(foo); // hello,打印的是var foo = 'hello' 的值(变量作用域)
Last Updated: 6/25/2021, 6:35:25 AM