一篇搞懂var,let,const三者的区别以及var的变量提升与函数提升

100 阅读4分钟

1.分析var,let,const三者的区别

1.var的特性

  • var定义的变量,没有块的概念,可以跨块访问,但是不能跨[函数]访问。
  • 可以进行变量提升,但是在赋值之前调用的话会显示undefined。
  • 如果在函数内不使用var,则该变量是全局的。

2.let的特性

  • let定义的变量,不能跨块访问,也不能跨函数访问。
  • 不能提前调用,会报错。
  • 在同一个块级作用域,不能重复声明变量

3.const的特性

  • const有以上let的特性
  • const用来定义常量,定义的时候必须赋值,如果定义的常量是原始数据类型则不能进行修改。

2.代码演示

1.var特性对应的代码

var定义的变量,没有块的概念,可以跨块访问,但是不能跨函数访问。

 {
     var value = "hallo"
 }
 console.log(value);//hallo
 //立即执行函数
 (function e() {
     var value = "hallo"
 })();
 console.log(value);//temp is not defined

如果在函数内不使用var,则该变量是全局的。

function change() {
    a = 30
}
change()
console.log(a) // 30 

2.let特性对应的代码:

let定义的变量,不能跨块访问,也不能跨函数访问。

if (true) {
    let value = "hallo";
    console.log(value);//hallo
}
console.log(value);//报错temp is not defined

在同一个块级作用域,不能重复声明变量。

let value1 = "aaa";
let value1 = "bbb";
console.log(value1);//报错'temp1' has already been declared
//因为两个temp不在同一个作用域下,因此可以重复声明
 if (true) {
    let value = "hallo";
    console.log(value);//hallo
}
let value = "aaa";
console.log(value);//aaa

let的变量创建的时候可以不用赋值

let valuevalue;
console.log(value)//undefined

3.const特性对应的代码

const定义的变量必须赋初始值并且const定义的变量一般不能改变

const value;
console.log(value)//报错Missing initializer in const declaration
--------------------------------------------------------------
const value = 1;
value = "aaa"//报错

const定义的引用类型除外,因为const里面保存的仅仅是地址

const person = {
     name : '你好',
 }
 person.name = '哈哈'
 console.log(person.name)//哈哈

因为对象是引用类型(对象,数组,函数等),person中保存的仅是对象的指针,这就意味着,const仅保证指针不发生改变,修改对象的属性不会改变对象的指针,所以是被允许的。也就是说const定义的引用类型只要指针不发生改变,其他的不论如何改变都是允许的。

3.var的变量提升与函数提升

1.变量提升

变量提升即将变量声明提升到它所在作用域

  • 通过var定义(声明)的变量,在定义语句之前就可以访问到;
  • 值:undefined;
console.log(a); //undefined
var a = 1;

为什么会发生上面的情况呢,正是由于var的变量提升,上面代码实际的执行顺序为:

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

2.函数提升

js中创建函数有两种方式:函数声明式和函数表达式

1、函数声明提升

	function fun() {
	    console.log('函数声明式');
	}

js在执行之前,会把fun函数提升到最前面,所以我们在fun函数定义之前就可以使用fun函数。 举个例子:

	fun();
	function fun(){
		console.log("aa");
	}

打印结果为aa;说明以函数声明来定义函数时,可以在定义函数之前访问到定义的函数。

2、函数表达式提升

	var fun = function() {
	    console.log('函数表达式');
	};

此种声明方式我们可以理解为一个普通变量的提升,在js代码执行之前会把fun提升带最前面,在函数赋值之前,fun是undefined,如果调用fun(),将会报错。 举个例子:

	fun();
	var fun = function (){
	    console.log("aa");
	}

此时打印的结果为报错Uncaught TypeError: fun is not a function,因为在js代码执行之前,会把fun提升到最前面,值为undefined,不是一个函数,以函数的形式来进行调用时将会报错。

3.面试题测试

把上面这些基本知识理清楚后,在看几道面试题,检测是否真的学明白了。

1.第一题

  var a = 4
  function fn () {
    console.log(a)
    var a = 5
  }
  fn()

输出结果:undefined

说明:  在上面这段代码中有两个作用域,window全局作用域和fn函数作用域,在打印变量a时,会先在fn函数作用域里面查找,因为在执行fn函数时,在函数内部也会先进行变量提升,所以最终的打印结果为undefined
代码实际的执行顺序为:

  var a = 4
  function fn () {
    var a;
    console.log(a); //undefined
    a = 5
  }
  fn()

2.第二题

  function a() {}
  var a;
  console.log(typeof a)

输出结果:function

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

输出结果:number

说明:函数提升优先级高于变量提升,且不会被同名变量声明时覆盖,但是会被同名变量赋值后覆盖。

3.第三题

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

输出结果:function

上面代码的执行顺序实际上是:

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

重点就是:函数提升优先级高于变量提升,虽然这里是同名变量并且赋值了,但是console.log在最前面

4.第四题

  console.log(v1);
  var v1 = 100;
  function foo() {
    console.log(v1);
    var v1 = 200;
    console.log(v1);
  }
  foo();
  console.log(v1);

大家可以看下这个例子最后的输出结果,检测下自己理解的如何。至于打印输出的结果我就不透露了,大家可以在控制台打印输出下,看看是否和自己预想的一样。