万丈高楼平地起,欲练此功,必先打好基本功: )。浏览器
ES6已经融入到了咱们的平常开发当中,甚至一些ES7的特性也已经在广泛使用,但因为浏览器的支持问题,ES6的代码在大多数状况下,仍是须要编译成ES5才能正常地在各浏览器上正常运行。
ES6支持6中形式的变量命名方式:var
、let
、const
、function
、class
、function
,本文主要讨论的是var
、let
、const
。class
和function
会在以后专门讨论。app
在ES5里面,咱们要声明一个变量,会经过三种命令方式来实现,var
、隐式声明
、function
;ide
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
两种形式,先看如下例子:ui
console.log(a); //无报错,输出undefined var a = 'test'; var a = 'var again';
经过var
声明的变量存在变量提高一说,同一变量名在相同做用域下能重复定义,上述代码执行时会以如下情形执行:先定义一个变量var a,console.log(a),a = 'test';code
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
定义的name
、obj
是一个常量,在声明时必须对其进行赋值,且赋值后不能进行二次赋值,而let
声明的变量在声明时可不赋值,后面再赋值,此时默认值为undefined
。递归
const obj = {}; obj; //{} obj.a = '1'; obj; //{a:1}
const
定义的obj
在常量中存储的是obj对象在栈
里指向堆
的地址,该指向地址不可改变,而在堆
地址里面存放的数据不被约束,是可变的。若但愿禁止变动obj及其内部属性,Object提供了freeze方法,以下函数能更好的递归冻结Object对象ip
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:
const:
=
直接替换整个值不然报错;let
和 const
的出现,很好地把ES5中var
定义变量的Bug给埋了,解决了定义同名变量致使变量间相互污染的问题,保证了同一块级做用域下,变量名的惟一性。同时const
定义常量能更直观地明白常量的意义及其不可修改性。
ES6新增的变量声明命令存在块级做用域
{ var a = 'test'; let b = 'test1'; } console.log(a); //test console.log(b); //Uncaught ReferenceError: b is not defined
这即是块级做用域最基本的示例,经过let
、const
声明的变量仅能在其代码块内被使用,该代码块内部便是一个块级做用域
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); // 一、二、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
,让变量存在了块级做用域,很好地划分变量间的做用范围,避免了以往同名变量相互污染问题;外层变量没法直接读取内层变量,对内层变量具备更好的保密性,内外层代码独立执行,相互间不影响;精简了函数自执行代码
以上。
文章观点内容若有错误欢迎指出交流,相互进步