es6入门
一、es6 简介
1.什么是es6?
Es6是简称,全称是ECMAScript 6.0。由于es6是2015年6月份发布的标准。又可以称之为ECMAScript 2015,或es2015。它的目标,是使得 JavaScript 语言可以用来编写复杂的大型应用程序,成为企业级开发语言。
2.ECMAScript和JavaScript的关系
请问二者相等吗?
ECMAScript != JavaScript
稍微回顾js的历史。
ECMAScript是一个语言标准。
JavaScript则是这个语言标准的一个具体实现。在浏览器环境中的具体实现。
再如,微软的Jscript。Flash中的ActionScript,服务器端的node。
ECMAScript只是提供了js语法。
JavaScript通常是指浏览器的ECMAScript的实现,除了有ECMAScript语法之外,还有浏览器相应的接口,比如documnet.getElmentById。
由于js和ECMAScript并不是同一个概念,所以在es6之后,就不再叫javascript了,而是回归到本来的名称。
3.ECMAScript的历史
ES6从开始制定到最后发布,整整用了15年。
1997年发布ECMAScript 1.0
1998年6月发布ECMAScript 2.0
1999年12月发布 ECMAScript 3.0(巨大成功,奠定js的基本语法)
2000年,其实有一个4.0版本,由于激进,没有获得通过。
2009年12月,ECMAScript5.0 版正式发布
2015年6月,ECMAScript 6.0 正式通过,成为国际标准。
ECMA决定:从2015年开始,每一年发布一个新的版本。
2016年6月,小幅修订的《ECMAScript 2016标准》即 ES6.1 版
根据计划,2017年6月发布 ES2017 标准。
还有es6、es7和es8的说法。
ES6 既是一个历史名词,也是一个泛指,含义是5.1版以后的 JavaScript 的下一代标准,涵盖了ES2015、ES2016、ES2017等等,有时也泛指“下一代 JavaScript 语言
4.为什么要学习ES6?
es6的出现,给前端开发人员带来了新的惊喜,它包含了一些很棒的新特性,可以更加方便的实现很多复杂的操作,提高开发人员的效率。
二、let
let的作用,和var是类似的。是用来声明变量的
let声明的变量有一些特性:
-
块作用域
-
不能声明提前
-
在同一个块作用域中,不允许重复声明变量
-
暂时性死区
(1)基本使用
let a=200;
console.log(a);
a=400;
console.log(a);
// 从这个层面来讲,和var是一样的效果
(2)块级作用域
首先需要搞清楚,在es5中,有没有块作用域?
没有,在es5中,变量的作用域只有两种:
-
全局变量
-
局部变量
它们是以函数作为分界线的。
以单层函数为例:函数外部的,就是全局变量,如果是在函数内部声明的变量,就是局部变量。
Let则提供了块作用域的用法。
也就说,在es6中,使用let来声明变量,就有三种作用域:
-
全局作用域
-
局部作用域
-
块级作用域
定义一个块级的变量如下:
<script>
{
let b = 20;
const c = 30;
console.log(b);
console.log(c);
}
console.log(b);
</script>
使用let声明的变量,只在当前块有效果
//在进行for循环时,使用let来声明计数器变量,如下:
for (let i = 0; i < 10; i++) {
.......
}
console.log(i)
此处说明,这个i并不是一个全局变量,而是块级变量。
小结:****let声明的变量,局部块级作用域特性,具体体现在两个地方:****
-
{}
-
for循环中声明的计数器
(3)不能声明提前
和var对比,var可以声明提前,但是let不可以。
{
console.log(s);
let s = "let es6"
console.log(s)
}
所以,在使用let声明变量时,必须要先声明,然后才能使用发,否则报错
(4)不能重复声明
在同一个块级作用域中,不能重复声明
{
let a=100;
let a=200;
console.log(a);
}
在不同的作用域中,我们是可以声明的。
let a=400; //全局的
console.log(a)
{
let a=100; //块级的
console.log(a);
}
(5)暂时性死区–(面试)
只要块级作用域内存在let命令,它所声明的变量就“绑定”(binding)这个区域,不再受外部的影响。
在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”,temporal dead zone,简称 ****TDZ****。
<script>
var world = 'globalWorld';
function fn(){
console.log(s1);
let world = 'location';
console.log(world)
}
fn()
</script>
var world = 'globalWorld';
function fn(){
//暂时性死区开始了
//console.log(s1);
//暂时性死区结束了
let world = 'location';
console.log(world)
}
fn()
let还有哪些应用呢?
//给li循环绑定点击事件,当点击的时候,分别弹出0,1,2,3
//一般可能会这么写?
var lis = document.getElementsByTagName("li");
for(var i=0;i<lis.length;i++){
lis[i].onclick=function(){
alert(i)
}
}
//执行之后,发现每一个li点击之后弹出的都是4,并不是我们期望的0,1,2和3。
原因何在?
其实,我们一定要搞清楚,代码的编写和执行是分开的。换言之,事件的执行一定是分两个过程:
-
注册过程,绑定过程
-
触发了,执行注册好代码
在注册的过程中,for语句一定会执行。但是函数中的alert是不会执行的
循环完毕,相当于是如下代码:
lis[0].onclick=function(){
alert(i)
}
lis[1].onclick=function(){
alert(i)
}
lis[2].onclick=function(){
alert(i)
}
lis[3].onclick=function(){
alert(i)
}
其中的i,由于没有执行,仍然是i.
循环完毕,i的值已经是4了.
然后,当我们点击具体的某一个li时,才会真正的执行function代码.
此时,i的值就是外部的i,都会弹出4.
解决方法有二:
-
人为的给每一个li元素对象增加一个索引值
-
利用自执行函数或闭包
a.增加索引
var lis = document.getElementsByTagName("li");
for(var i=0;i<lis.length;i++){
lis[i].index = i;
lis[i].onclick=function(){
alert(this.index)
}
}
//测试,ok
b.自执行函数和闭包
for(var i=0;i<lis.length;i++){
lis[i].onclick=function(n){
return function(){
alert(n);
}
}(i)
}
//测试,ok
这里之所以,可以就是因为针对每一个li绑定的处理函数中,都有一个自己是局部变量,值依次是i循环的值,分别是0,1,2和3。
c.let 的方式
for(let i=0;i<lis.length;i++){
lis[i].onclick=function(){
alert(i)
}
}
//测试,ok
尽管现在看到只有一个i,但是这个i不是全局的i,而是每一个事件处理函数自己的i。
实际上,let 的出现,其实就是为了解决这一类的问题。
三、const
作用:是用于定义常量的。
在es5中,js中是没有常量的概念。所有的都是通过var来定义
const PI=3.1415926;
console.log(PI);
PI=3.14;
console.log(PI)
和let对比,let定义的变化,其值是可以修改的。而const定义的量是不能修改的。
-
const在声明的时候必须要赋值。
const num; num = 20.5; console.log(num);
除了上述两个区别,其他let局部的几大特性,const也都具备
-
不存在声明提前
-
只在当前的块级作用域内有效
-
不能重复声明
-
存在暂时性死区
注意:****常量的本质****
const定义的常量是不能修改的
对于应用数据类型:
- 直接修改了指向
const person = {
name:'lucky',
age:20,
address:'中山西路666号'
}
person = {}
console.log(person)
- 只是修改了属性,
const person = {
name:'lucky',
age:20,
address:'中山西路666号'
}
person.age=21;
console.log(person)
实际上,我们说const真正不变的是常量保存的内容。
如果是基本数据类型,就是值
如果是引用数据类型,就是指对象的地址,地址不变就ok。
到了es6中,大家在编写代码的时候,就不要再写var了。
需要使用let或者const。
如果这个值需要变化,就使用let。
如果这个值不会变化,就使用const。
四、try catch
我们编译运行程序出错的时候,编译器就会抛出异常。同时程序下面的代码不能执行,这对开发不是很好,但是有一种更为合理的语法结构 try..catch
,它会在捕捉到异常的同时不会使得代码停止执行而是可以做一些更为合理的操作。
function rand(){
var i = Math.random()*10;
if(i<5){
throw Error ("发生了错误")
}else{
return i
}
}
try {
console.log(rand())
} catch (error) {
console.log(error)
}
console.log(22)
它按照以下步骤执行:
- 首先,执行
try {...}
里面的代码。 - 如果执行过程中没有异常,那么忽略
catch(err)
里面的代码,try
里面的代码执行完之后跳出该代码块。 - 如果执行过程中发生异常,控制流就到了
catch(err)
的开头。变量err
(可以取其他任何的名称)是一个包含了异常信息的对象。
五、变量解构赋值
1.*什么是解构赋值*
ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring)。
包括:****数组、对象、函数参数****、字符串、数值和布尔值。null和undefined不行。
在实际开发时,真正使用比较多的是数组、对象和函数参数的解构。
解构,通俗的讲法,****就是批量定义变量****。本质是定义变量的。
可以理解为变量的取出
- 数组的解构赋值
<script>
var arr = [1,2,3];
//var a = arr[0],b = arr[1], c = arr[2];
[a,b,c] = arr;
console.log(a,b,c)
</script>
上面代码表示,可以从数组中提取值,按照对应位置
,对变量赋值。
本质上,这种写法属于“模式匹配”,只要等号两边的模式相同,左边的变量就会被赋予对应的值。
如果解构失败,变量的值等于undefined。
<script>
let [foo, bar, baz] = [1, 2, 3];
foo // 1
bar // 2
baz // 3
let [ , , third] = ["foo", "bar", "baz"];
third // "baz"
let [x, , y] = [1, 2, 3];
x // 1
y // 3
let [x, y, z] = ['a'];
x // a
y // undefined
z // undefined
</script>
- 对象的解构赋值
解构不仅可以用于数组,还可以用于对象。对象的解构与数组有一个重要的不同。数组的元素是按次序排列的,变量的取值由它的位置决定;而对象的属性没有次序,变量必须与属性同名,才能取到正确的值。如果解构失败,变量的值等于undefined。
<script>
let {
bar, foo } = {
foo: 'aaa', bar: 'bbb' };
foo // "aaa"
bar // "bbb"
let {
baz } = {
foo: 'aaa', bar: 'bbb' };
baz // undefined
</script>
六、箭头函数
箭头函数 ES6 允许使用“箭头”(=>)定义函数。箭头函数实际还是函数
箭头函数的写法
<script>
var f = v => v;
// 等同于
var