通俗易懂明白ES6 - 变量声明敕令及其块级作用域

弁言

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

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:

  1. 存在变量提拔,可反复屡次声明同名变量。

let:

  1. 不存在变量提拔,必需先定义再运用,不然报错;
  2. 统一作用域下不可反复定义同名变量,不然报错;
  3. 在代码块内,经由过程let声明的变量,只管代码块外层有同名变量,代码块内部在该变量声明前都不能运用该变量,不然报错。

const:

  1. 不存在变量提拔,必需先定义再运用,不然报错;
  2. 统一作用域下不可反复定义同名变量,不然报错;
  3. 建立变量的同时必需对其赋值,且赋值后不能直接经由过程=直接替代全部值不然报错;
  4. 在代码块内,经由过程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://segmentfault.com/a/1190000019095101
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞