详解var、let、const关键词声明变量的区别,以及变量提升、块级作用域的认识等。

首先回顾一下JavaScript中var声明变量的基础知识:

• 在使用var关键词声明变量时,变量在函数外则是全局变量,有全局作用域,全局变量在页面关闭后销毁;变量在函数内则是局部变量,作用局部作用域(变量只能在该函数内有效,函数执行完将自动销毁)

• 我们使用var来创建变量,声明后未赋值的变量输出会提示 “undefined”。在方法函数外声明的变量未使用var ,会报错“x is not defined”;

• 在函数内未使用var声明的变量自动变为全局变量


开发背景(WHY)为什么要使用let、const关键词来创建变量或常量

•解决ES5使用var初始化变量时会出现的变量提升问题

•解决使用闭包时出错的问题

•解决使用计数的for循环变量时候会导致泄露为全局变量的问题,

•ES5只有全局作用域和函数作用域(对应var声明的全局变量和局部变量时),没有块级作用域(ES6中{}中的代码块)。同理只能在顶层作用域window中和函数中声明函数,不能在块级作用域中声明函数;


那么先来理解一下什么是变量提升特性,会导致的问题(比如内层变量覆盖外层变量)


•变量初始化时可以分为两步:使用关键词var声明变量,以及赋值。变量提升就是将声明变量这一步提升到该作用域的头部。注意函数声明也会类似var声明出现提升特效,函数声明提升在变量声明提升上面;

参考网址:https://blog.csdn.net/recoluan/article/details/79253223

实例01

console. log( foo);
console. log( foo2);
var foo= 2;
let foo2= 3;

//以上代码var声明变量后,相当于如下
// var foo;
// console.log(foo); //会提示‘undefined’
// foo=2;
// let不存在变量提升,会报错

实例02

var a= "我在外面";
function func(){
console. log( a); //undefined
console. log( window. a); //我在外面
var a= '我在里面';
console. log( a); //我在里面
}
//以上代码var声明变量后,相当于如下
// var a="我在外面";
// function func(){
// var a;
// console.log(a);
// console.log(window.a);
// a='我在里面';
// console.log(a);
// }

注意:在使用let、const命令声明的变量不具备变量提升效果;

    :函数声明提升会在变量声明提升上面

fuc2();
function fuc2(){
console. log( b); //undefined
}
var b= 35;
//相当于
// function fuc2(){
// console.log(b);
// }
// var b;
// func2();
// b=35;


为什么需要块级作用域?

• 用来计数的循环变量泄露为全局变量,如下:

for ( var i = 0; i < s. length; i++) {
console. log( s[ i]); //会将字符串拆分为一个个的字符输出
}
console. log( i); // 5


• let和const是ES6新增特性,都可生成块级作用域(是指声明在花括号内的变量只在该区域内有效)。let用来声明变量,const用来声明常量(不可修改变量值,数组和对象除外);如果区块内存在let或const命令,这个区块对这些命令声明的变量会形成封闭的区域,该区域外不能被使用,且变量声明前使用变量会报错(又叫暂时性死区),更加严谨

var tmp = 123;
if ( true) {
tmp = 'abc';
// ReferenceError,不能未声明前使用这就是暂时性死区
console. log( temp);
let tmp;
temp= 666;
console. log( temp);
}


function bar( x = y, y = 2) {
return [ x, y];
}
bar(); // 报错


块级作用域外不能访问该区块内的变量或者常量,子块级作用域可以访问父块级作用域的变量

{
const ss= 99;
{
console. log( ss); //可以在子块内访问父块定义的常量
}
}
console. log( ss); //b不可以在块作用外访问let、const定义的变量或者常量

以上代码中通过将let替换var就可以修复各种bug,所以,let是更完美的var”。


其他的let、const和var的用法及注意点

• let和var的区别:let声明的变量只在其声明的块或子块中可用,而var声明的变量的作用域是整个封闭函数可用;

• let和const的特点:

① let和const关键词声明的变量不具备变量提升的特效(第二步提到了的),存在暂时性的死区,只能在声明的位置后使用,同一块级作用域中不能反复声明同一变量名(子块级可以重复声明父块级变量),var可以;

② let和const声明只在最靠近的一个块(花括号内)中有效;

③ 使用const声明常量时候大写,const在声明时必须赋值;

注意1: const声明的变量值并不是不能变的,而是变量指向的内存地址是不能变的,对于数值、字符串等简单类型的数据,值就保存在变量指向的内存地址上,因此等同于常量;但对于符合类型的数据(如数组和对象),变量指向的内存地址是一个指引,数据结构是否可变就不能控制了,所以将对象声明为常量必须非常小心;

const newArr=[ 23, 43, 22, 66];
newArr[ 0]= 888;
console. log( newArr); //[888, 43, 22, 66]

注意2:外层块作用域不可以访问块内层作用域,内层块作用域可以获取外层块作用域变量,子块可以重复定义外层块作用域变量。函数在块级作用域中声明是行为类似let,不能被作用域外访问,块中的函数声明存在变量提升,确实需要时候使用函数表达式的形式,而不是函数声明语句形式;

function f() { console. log( 'I am outside!'); }
( function () {
if ( false) {
//函数提升后,这里重复声明了该匿名函数外的函数f,所以会覆盖外部函数
function f() { console. log( 'I am inside!'); }
}
f();
}());

注意3:  Let不允许在相同作用域中使用与其他let或const,重复声明同一个变量,所以不能在有参函数声明中重复声明函数参数,如function func(arg){let arg}会报错

var message = "Hello!";
let age = 25;
// 以下两行都会报错
const message = "Goodbye!";
const age = 30;


注意4: 在ES5中顶层对象(在浏览器指的是window对象),顶层对象属性和全局变量是等价的。属性也可以动态创建变量,顶层对象的属性可以被随处读写不利于模块化编程;而在ES6中,var命令和function命令声明的全局变量,依旧是顶层对象的属性;另一方面规定,let命令、const命令、class命令声明的全局变量,不属于顶层对象的属性。也就是说,从 ES6 开始,全局变量将逐步与顶层对象的属性脱钩。

var aaa= 1;
console. log( window. aaa); //输出1
let bbb= 2;
console. log( window. bbb ); //输出undefined



猜你喜欢

转载自blog.csdn.net/zhouzuoluo/article/details/80724033
今日推荐