资讯专栏INFORMATION COLUMN

通俗易懂理解ES6 - 变量声明命令及其块级作用域

Olivia / 3056人阅读

摘要:变量声明结论存在变量提升,可重复多次声明同名变量。和的出现,很好地把中定义变量的给埋了,解决了定义同名变量导致变量间相互污染的问题,保证了同一块级作用域下,变量名的唯一性。中规定,函数本身的作用域在其所在的块级作用域当中。

引言

万丈高楼平地起,欲练此功,必先打好基本功: )。

ES6已经融入到了我们的日常开发当中,甚至一些ES7的特性也已经在普遍使用,但由于浏览器的支持问题,ES6的代码在大多数情况下,还是需要编译成ES5才能正常地在各浏览器上正常运行。
ES6支持6中形式的变量命名方式:varletconstfunctionclassfunction,本文主要讨论的是varletconstclassfunction会在之后专门讨论。

变量声明

在ES5里面,我们要声明一个变量,会通过三种命令方式来实现,var隐式声明function

var a = "test";     //var定义一个变量a,并赋值字符串"test";
b = "test2";        //隐式声明,在堆变量b赋值字符串"test2"前,未以任何方式声明变量b,此时b为全局变量
function f() {
    cosole.log("haha");
}


隐式声明声明变量是一个很不好的行为,隐式声明的变量类似于通过var定义一个变量,且变量的作用域直接指向window对象,这会导致变量容易被错误引用或修改

function f() {
    var fn = function() {
        (function() {
            b = "隐式声明的变量b";
        })();
    }
    fn();
}
f();
b;          //"隐式声明的变量b"
window.b;   //"隐式声明的变量b"


ES6-变量声明的let和const

而在ES6中,变量声明增加了letconst两种形式,先看以下例子:

console.log(a);     //无报错,输出undefined
var a = "test";
var a = "var again";

通过var声明的变量存在变量提升一说,同一变量名在相同作用域下能重复定义,上述代码执行时会以以下情形执行:先定义一个变量var a,console.log(a),a = "test";

console.log(son);     //报错 Uncaught ReferenceError: son is not defined
let son = "James Bond";

let声明变量不存在变量提升,因此在son被定义前使用son的话,会报错

const name;            //报错 Uncaught SyntaxError: Missing initializer in const declaration
let education;              //正常执行
console.log(education);     //undefined

const name1 = "human";
name1 = "cat";         //报错 Uncaught TypeError: Assignment to constant variable.

通过const定义的nameobj是一个常量,在声明时必须对其进行赋值,且赋值后不能进行二次赋值,而let声明的变量在声明时可不赋值,后面再赋值,此时默认值为undefined

const obj = {};
obj;                //{}
obj.a = "1";
obj;                //{a:1}

const 定义的obj在常量中存储的是obj对象在里指向的地址,该指向地址不可改变,而在地址里面存放的数据不被约束,是可变的。若希望禁止变更obj及其内部属性,Object提供了freeze方法,如下函数能更好的递归冻结Object对象

const freezeObj = (obj) => {
    Object.freeze(obj);
    Object.keys(obj).forEach((item) => {
        if(type of(item) === "object") freezeObj(item);
    });
}


let fruit = "orange";
var fruit = "apple";    //报错 Uncaught SyntaxError: Identifier "fruit" has already been declared

通过let定义的变量在同一作用域下不允许被重复定义,否则会报错,const也是如此

var test = "test",
    test1 = "test1";
{
    test = "new test";      //Uncaught ReferenceError: test is not defined
    test1 = "new test1";    //Uncaught ReferenceError: test1 is not defined
    let test;
    const test1 = "new test1";
}

通过let、const声明的变量会存在 __暂时性死区__,即:在声明该变量的作用域内,变量已经被绑定在该作用域之中,忽略外界存在的同名变量,在该作用域下,该变量在变量声明之前都不能被使用。


变量声明结论

var:

存在变量提升,可重复多次声明同名变量。

let:

不存在变量提升,必须先定义再使用,否则报错;

同一作用域下不可重复定义同名变量,否则报错;

在代码块内,通过let声明的变量,尽管代码块外层有同名变量,代码块内部在该变量声明前都不能使用该变量,否则报错。

const:

不存在变量提升,必须先定义再使用,否则报错;

同一作用域下不可重复定义同名变量,否则报错;

创建变量的同时必须对其赋值,且赋值后不能直接通过=直接替换整个值否则报错;

在代码块内,通过const声明的变量,尽管代码块外层有同名变量,代码块内部在该变量声明前都不能使用该变量,否则报错。

letconst的出现,很好地把ES5中var定义变量的Bug给埋了,解决了定义同名变量导致变量间相互污染的问题,保证了同一块级作用域下,变量名的唯一性。同时const定义常量能更直观地明白常量的意义及其不可修改性。


块级作用域

ES6新增的变量声明命令存在块级作用域

什么是块级作用域?
{
    var a = "test";
    let b = "test1";
}
console.log(a);     //test
console.log(b);     //Uncaught ReferenceError: b is not defined

这便是块级作用域最基本的示例,通过letconst声明的变量仅能在其代码块内被使用,该代码块内部即是一个块级作用域

块级作用域有什么用?
var a = "test";
function f(){
    console.log(a);
    if(true) {
        var a = "test1";
    }
    console.log(a);
}
f();        //undefinded   test1

这个例子输出的结果是undefined,原因在于,在f()中,不论if语句判断是否通过,if内部的var a都被变量提升,且变量a均通过var命令声明,内部变量a覆盖了外部变量a;

换个写法再来一遍

let a = "test";
function f(){
    console.log(a);
    if(true) {
        let a = "test1";
    }
    console.log(a);
}
f();        //test   test

比对一下两段代码的执行情况:
看看该代码的实际执行情况:

var a                               let a
a = "test"                          a = "test"
function f                          function f
f() = {}                            f() = {}
f()                                 f()
var a                               console.log(a);
console.log(a)                      if(true)
if(true)                            let a        //此处的a是另一个a,可以理解为_a,且_a的作用范围仅在if语句内
a = "test1"                         a = "test1";    //类似于_a = "test1"
console.log(a)                      console.log(a)  //类似于console.log(_a)

从上面的比对可以看出,通过let声明的变量a,不会被变量提升,且具有块级作用域,不会影响到上层作用域的a变量

再来一个示例:

for(var i=0;i<10;i++){
    console.log("for里面的i:"+i);          // 1、2、3......10
}
console.log(i);            //10

这里定义的循环计数变量i,原本只是想在循环内使用,但由于使用了var声明,因此不存在块级作用域,导致for循环外也能获取到了i的值。

ES6中规定,函数本身的作用域在其所在的块级作用域当中。

function fn() {
    console.log("outside console");
}
(function() {
    if(false) {
        function fn() {
            console.log("inside console");
        }
    }
    fn();
}());

上述代码中,fn()执行结果会报错fn is not a function,因为在fn执行的环境中存在function fn的声明,声明被提前,导致fn被提前定义,但没有被赋值为function。

ES6的函数自执行代码变得精简。

//从
(function() {
    console.log("test");
})();

//变为

{
    console.log("test");
}
块级作用域结论

通过使用let const,让变量存在了块级作用域,很好地划分变量间的作用范围,避免了以往同名变量相互污染问题;外层变量无法直接读取内层变量,对内层变量具有更好的保密性,内外层代码独立执行,相互间不影响;精简了函数自执行代码

以上。

文章观点内容如有错误欢迎指出交流,相互进步

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/104167.html

相关文章

  • Javascript ES6学习

    摘要:以下简称是语言的下一代标准。因为当前版本的是在年发布的,所以又称。命令用于规定模块的对外接口,命令用于输入其他模块提供的功能。需要特别注意的是,命令规定的是对外的接口,必须与模块内部的变量建立一一对应关系。 ECMAScript 6(以下简称ES6)是JavaScript语言的下一代标准。因为当前版本的ES6是在2015年发布的,所以又称ECMAScript 2015。 最常用的ES6...

    gclove 评论0 收藏0
  • JavaScript基础系列---变量及其值类型

    摘要:但对于引用类型的数据主要是对象和数组,变量指向的内存地址,保存的只是一个引用地址指针,只能保证这个引用地址指针是固定的,至于它指向的堆内存中的存储的值是不是可变的,就完全不能控制了。 基础概念 变量是存储信息的容器,这里需要区分一下:变量不是指存储的信息本身,而是指这个用于存储信息的容器,可以把变量想象成一个个用来装东西的纸箱子 变量需要声明,并且建议在声明的同时进行初始化,如下所...

    sugarmo 评论0 收藏0
  • 30分钟掌握ES6/ES2015核心内容

    摘要:以下简称是语言的下一代标准。因为当前版本的是在年发布的,所以又称。用它所声明的变量,只在命令所在的代码块内有效。的继承机制,实质是先创造父类的实例对象所以必须先调用方法,然后再用子类的构造函数修改。 ECMAScript 6(以下简称ES6)是JavaScript语言的下一代标准。因为当前版本的ES6是在2015年发布的,所以又称ECMAScript 2015。 也就是说,ES6就是E...

    LucasTwilight 评论0 收藏0
  • 30分钟掌握ES6/ES2015核心内容(上)

    摘要:以下简称是语言的下一代标准。的继承机制,实质是先创造父类的实例对象所以必须先调用方法,然后再用子类的构造函数修改。总结以上就是最常用的一些语法,可以说这的语法,在的日常使用中占了追加十分钟好的吗分钟掌握核心内容下 ECMAScript 6(以下简称ES6)是JavaScript语言的下一代标准。因为当前版本的ES6是在2015年发布的,所以又称ECMAScript 2015。 也就是说...

    YPHP 评论0 收藏0
  • es6语法快速上手

    摘要:二一个的解析器在我们正式讲解语法之前,我们得先了解下。而则实际上为新增了块级作用域。的继承机制,实质是先创造父类的实例对象所以必须先调用方法,然后再用子类的构造函数修改。 随着google和firfox以及node6.0对es6的支持,es6语法的定稿使它越来越受到关注,尤其是react项目基本上都是用es6来写的。是时候从es5到es6转变了showImg(http://static...

    PiscesYE 评论0 收藏0

发表评论

0条评论

Olivia

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<