1.介绍 node
总的来讲,ES6是在ES2015的基础上改变了一些书写方式,开放了更多API,这样作的目的最终仍是为了贴合实际开发的须要。若是说一门编程语言的诞生是天才的构思和实现,那它的发展无疑就是不断填坑的历史。ES6正是为了填一些坑。git
我对ES6语法的学习,主要在浏览器端,参考阮一峰大神的ES6入门教程,添加了一些我的理解的注释和遇到的小问题,欢迎批评指正,共同进步。es6
浏览器端引用的依赖文件和本文案例 可在 https://github.com/chanceLe/ES6-Basic-Syntax 找到。github
2.基础部分编程
2.1let和const关键字浏览器
let命令声明变量,相似var,但所声明的变量只在let代码块有效。 编程语言
{ let a = 1; var b = 2; } console.log(b); console.log(a); //报错,找不到。 //for循环的计数器,就很适合用let for(let i=0;i<5;i++){ console.log(i); } //上面的代码的计数器i,只在for循环体内有效。
{}在ES6中用来造成块级做用域,后边会说到。 函数
var a = []; for(var i=0;i<10;i++){ a[i] = function(){ console.log(i); } }
a[6](); //10 到九循环完,又加了1,换成let会获得指望结果。
var声明的变量全局范围内都有效。因此每次循环,新的i值都会覆盖旧值
let声明的仅在块级做用域内有效,最后输出6
let不会发生变量提高的现象,因此必定要在定义后使用,不然报错。
暂时性死区:只要块级做用域内存在let命令,它所声明的变量就绑定这个区域,再也不受外部影响。学习
var tmp = 123; if(true){ tmp = "abc"; console.log(tmp,"11"); //"abc" let tmp; } console.log(tmp,"22"); //"123"
书上说,若是区块中存在let和const命令,这个区块对这些命令声明的变量,从一开始就造成了封闭
做用域,凡是声明以前使用的,都会报错。spa
实际状况,let不会报错,const会报错(这可能跟浏览器端转码有关,版本为5)。
有些死区比较隐蔽,不太容易发现:
function bar(x=y,y=2){ return [x,y]; } console.log(bar()); //书上说这里因为y没有定义,应该报错,实际是 [undefined,2] function bar2(x=2,y=x){ return [x,y]; } console.log(bar2()); //[2,2]正常
不容许重复声明,let不容许在相同做用域内,重复声明同一个变量:
function fun(){ let a = 10; // var a = 5; //报错。 // let a = 1; //报错 }
不能在函数内部从新声明参数:
function fun1(arg){ // let arg; //报错 { let arg; //不报错 } }
const命令
声明一个只读的常量。一旦声明,常量的值就不能改变。
同时也说明,一旦声明,就要当即初始化,不然也报错。
const PI = 3.1415; console.log(PI); // PI = 3; //报错 只读的 // const circle; //报错,一旦声明,必须当即初始化。 /* * const的做用域与let命令相同:只在声明所在的块级做用域有效。 */ if(true){ const m = 5; } // console.log(m); //未定义
与let类似:
const命令声明的常量也不提高,一样存在暂时性死区,只能在声明的位置后使用。
也不能够重复声明。
对于复合类型的变量,变量名不指向数据,而是指向数据所在的地址。const命令只
是保证变量名指向的地址不变,并不保证该地址的数据不变,因此将一个对象声明为常量,
必须很是当心。
const foo = {}; foo.prop = 123; console.log(foo.prop); //上面的常量foo存储的是对象的地址,这个地址不可变,但依然能够添加属性。 const a = []; a.push("hello"); a.length = 0; // a = ["Dave"] //报错,赋值就是更换地址,不行的。 //若是真的想把对象冻结,应该使用Object.freeze方法。 const foo2 = Object.freeze({}); //常规模式下,下面一行不起做用 //严格模式下,会报错 foo.prop = 123;
ES5只有两种声明变量的方法:var和function。
ES6有6种:var function let const class import
全局对象属性:
全局对象是最顶层的对象,在浏览器环境下指的是window对象,在node指的是
global对象。ES5中,全局对象的属性和全局变量是等价的。
未声明的全局变量,自动成为全局对象window的属性,这被认为是js的最大败笔。
ES6为了改变这一点,一方面规定,为了保持兼容性,var命令和function命令声明的全局变量,
依旧是全局对象的属性,另外一方面规定,let,const,class命令声明的全局变量不属于全局对象的
属性。也就是说,从ES6开始,全局变量将逐渐与全局对象的属性脱钩。
2.2块级做用域:
ES5只有全局做用域和函数做用域,没有块级做用域,有不少不合理场景:
1.内层变量可能会覆盖外层变量。
var tmp = new Date(); function f(){ console.log(tmp); if(false){ var tmp = "hello world!"; } } f(); //undefined 声明提高,后边的定义把前边的覆盖掉了。
2.用来计数的循环变量泄漏为全局变量。典型的var定义的循环,上边有代码体现。
let实际上为js新增了块级做用域。下面的代码两个代码块都声明了n,运行输出5,表示外层代码不受内层代码块的影响。若是是var定义,就会收到影响,输出10;
function f1(){ let n = 5; if(true){ let n = 10; } console.log(n); } f1();
//es6容许块级做用域的任意嵌套: {{{{{ let insane = "hello world" }}}}} //上面代码使用了五层块级做用域,外部不能访问内部的变量。 //块级做用域实际上使得普遍应用的当即执行匿名函数(IIFE)再也不须要了。 //IIFE写法 (function(){ })() //块级做用域写法 { } /*
* 块级做用域与函数声明: * ES5规定,函数只能在顶层做用域和函数做用域之中声明,不能在块做用域中声明, * 状况一: * if(true){ * function(){} * } * 状况二: * try{ * function(){} * }
这两种状况,根据ES5的规定都是非法的。可是浏览器没有遵照这个规定,能够运行,在严格
模式下,仍是会报错。
ES6引入了块级做用域,明确容许在块级做用域中声明函数。
块级做用域中,函数声明语句的行为相似于let,在块级做用域以外,不能够引用。
由于块级做用域对做用域以外没有影响,这个差别会对老代码产生很大影响,为了减轻这个不兼容
问题,ES6在附录B中规定,浏览器能够不遵照上面的规定,有本身的行为方式。
1.容许在块级做用域内声明函数。 2.函数声明相似于var,即会提高到全局做用域或函数做用域的头部。 3.同时,函数声明还会提高到所在块级做用域的头部。 上面的3个规则只对ES6 的浏览器实现有效,其余环境的实现不用遵照,仍是将块级做用域当作let处理。 考虑到环境致使的行为差别太大,应该避免在块级做用域内声明函数。若是确实须要,也应该写成函数表达式。 ES6的块级做用域容许声明函数的规则,只在使用大括号的状况下成立,没有使用大括号,会报错。