由于在学习vue的时候有许多自己不懂的语法,于是简单的学习一下ES6。
1.ES简介
ES6, 全称 ECMAScript 6.0 ,是 JavaScript 的下一个版本标准,2015.06 发版。
ES6 主要是为了解决 ES5 的先天不足,比如 JavaScript 里并没有类的概念,但是目前浏览器的 JavaScript 是 ES5 版本,大多数高版本的浏览器也支持 ES6,不过只实现了 ES6 的部分特性和功能
JavaScript 是大家所了解的语言名称,但是这个语言名称是商标( Oracle 公司注册的商标)。因此,JavaScript 的正式名称是 ECMAScript 。1996年11月,JavaScript 的创造者网景公司将 JS 提交给国际化标准组织 ECMA(European computer manufactures association,欧洲计算机制造联合会),希望这种语言能够成为国际标准,随后 ECMA 发布了规定浏览器脚本语言的标准,即 ECMAScript。这也有利于这门语言的开放和中立。
2.ES6新特性
在这里简要的学习一下ES6的比较重要的新特性,在自己的平时工作中也没有过多的用到的ES6简要记录。
1.let与const关键字(重要)
这两个关键字都是声明变量的关键字,其与var声明的变量有一定的区别,区别如下:
1.let解释
(1)let 声明的变量只在 let 命令所在的代码块内有效
{ let a = 0; var b = 1; } a // ReferenceError: a is not defined b // 1
(2)let 只能声明一次 var 可以声明多次:
let a = 1; let a = 2; var b = 3; var b = 4; a // Identifier 'a' has already been declared b // 4
(3)let 不存在变量提升,var 会变量提升:
console.log(a); //ReferenceError: a is not defined let a = "apple"; console.log(b); //undefined var b = "banana";
2.const关键字
const声明一个只读变量,声明之后不允许改变。意味着,一旦声明必须初始化,否则会报错。有点类似于java的final修饰的变量,是引用不可变。
ES6 明确规定,代码块内如果存在 let 或者 const,代码块会对这些命令声明的变量从块的开始就形成一个封闭作用域。代码块内,在声明变量 PI 之前使用它会报错。
2.解构赋值
解构赋值是对赋值运算符的扩展。
他是一种针对数组或者对象进行模式匹配,然后对其中的变量进行赋值。
在代码书写上简洁且易读,语义更加清晰明了;也方便了复杂对象中数据字段获取。
1.数组模型的解构
基本: let [a, b, c] = [1, 2, 3]; // a = 1 // b = 2 // c = 3 嵌套: let [a, [[b], c]] = [1, [[2], 3]]; // a = 1 // b = 2 // c = 3 忽略: let [a, , b] = [1, 2, 3]; // a = 1 // b = 3 不完全解构: let [a = 1, b] = []; // a = 1, b = undefined 剩余运算符: let [a, ...b] = [1, 2, 3]; //a = 1 //b = [2, 3] 字符串等: let [a, b, c, d, e] = 'hello'; // a = 'h' // b = 'e' // c = 'l' // d = 'l' // e = 'o'
2.对象模型的结构
基本: let { foo, bar } = { foo: 'aaa', bar: 'bbb' }; // foo = 'aaa' // bar = 'bbb' let { baz : foo } = { baz : 'ddd' }; // foo = 'ddd' 剩余运算符: let {a, b, ...rest} = {a: 10, b: 20, c: 30, d: 40}; // a = 10 // b = 20 // rest = {c: 30, d: 40} 解构默认值: let {a = 10, b = 5} = {a: 3}; // a = 3; b = 5; let {a: aa = 10, b: bb = 5} = {a: 3}; // aa = 3; bb = 5;
3.Symbol类型
ES6 引入了一种新的原始数据类型 Symbol ,表示独一无二的值,最大的用法是用来定义对象的唯一属性名。
ES6 数据类型除了 Number 、 String 、 Boolean 、 Objec t、 null 和 undefined ,还新增了 Symbol 。
Symbol 函数栈不能用 new 命令,因为 Symbol 是原始数据类型,不是对象。可以接受一个字符串作为参数,为新创建的 Symbol 提供描述,用来显示在控制台或者作为字符串的时候使用,便于区分。
let sy = Symbol("KK"); console.log(sy); // Symbol(KK) console.log(typeof(sy)); // "symbol" // 相同参数 Symbol() 返回的值不相等 let sy1 = Symbol("kk"); console.log(sy === sy1); // false
4.Map与Set
Map 对象保存键值对。任何值(对象或者原始值) 都可以作为一个键或一个值。Set 对象允许你存储任何类型的唯一值,无论是原始值或者是对象引用。Set 对象存储的值总是唯一的。
有点类似于Java的Map与Set。
5.Reflect 与 Proxy
Proxy 与 Reflect 是 ES6 为了操作对象引入的 API 。
Proxy 可以对目标对象的读取、函数调用等操作进行拦截,然后进行操作处理。它不直接操作对象,而是像代理模式,通过对象的代理对象进行操作,在进行这些操作时,可以添加一些需要的额外操作。
Reflect 可以用于获取目标对象的行为,它与 Object 类似,但是更易读,为操作对象提供了一种更优雅的方式。它的方法与 Proxy 是对应的。
有点类似于Java的反射和代理。
6.字符串
拓展了一些方法。包括判断包含,是否以指定字符串结束、开始等操作。
更加趋向于apache的StringUtils。
7.ES6 数值
对数字进行了扩展,包括Number类。
8.对象(重要)
(1)属性的简洁表示法
const age = 12; const name = "Amy"; const person = {age, name}; person //{age: 12, name: "Amy"} //等同于 const person = {age: age, name: name}
(2)方法名也可以简写
const person = { sayHi(){ console.log("Hi"); } } person.sayHi(); //"Hi" //等同于 const person = { sayHi:function(){ console.log("Hi"); } } person.sayHi();//"Hi"
9.数组
增加了一些创建数组的发那个发以及数组转换的方法,也增加了数组遍历的方法。
10.函数(重要)
这里有两个重要的改变。一个是函数的参数支持默认值以及不定参数,一个是箭头函数。
(1)参数默认值和不定参数
默认参数: function fn(name,age=17){ console.log(name+","+age); } fn("Amy",18); // Amy,18 fn("Amy",""); // Amy, fn("Amy"); // Amy,17 不定参数: function f(...values){ console.log(values.length); } f(1,2); //2 f(1,2,3,4); //4
(2)箭头函数
基本语法:
参数 => 函数体
注意:
当箭头函数没有参数或者有多个参数,要用 () 括起来。
var f = (a,b) => a+b; f(6,2); //8
当箭头函数函数体有多行语句,用 {} 包裹起来,表示代码块,当只有一行语句,并且需要返回结果时,可以省略 {} , 结果会自动返回。
var f = (a,b) => { let result = a+b; return result; } f(6,2); // 8
当箭头函数要返回对象的时候,为了区分于代码块,要用 () 将对象包裹起来
// 报错 var f = (id,name) => {id: id, name: name}; f(6,2); // SyntaxError: Unexpected token : // 不报错 var f = (id,name) => ({id: id, name: name}); f(6,2); // {id: 6, name: 2}
注意:
(1)箭头函数没有 this、super、arguments 和 new.target 绑定。
var func = () => { // 箭头函数里面没有 this 对象, // 此时的 this 是外层的 this 对象,即 Window console.log(this) } func(55) // Window var func = () => { console.log(arguments) } func(55); // ReferenceError: arguments is not defined
(2)回调函数中的箭头函数的this指向外层的实例对象
function fn(){ setTimeout(()=>{ // 定义时,this 绑定的是 fn 中的 this 对象 console.log(this.a); },0) } var a = 20; // fn 的 this 对象为 {a: 19} fn.call({a: 18}); // 18
call函数第一个参数相当于传递的上下文。
11.迭代器-Iterator
迭代器是一个统一的接口,它的作用是使各种数据结构可被便捷的访问,它是通过一个键为Symbol.iterator 的方法来实现。
迭代器是用于遍历数据结构元素的指针(如数据库中的游标)。
基本用法:
通过 Symbol.iterator 创建一个迭代器,指向当前数据结构的起始位置。随后通过 next 方法进行向下迭代指向下一个位置, next 方法会返回当前位置的对象,对象包含了 value 和 done 两个属性, value 是当前属性的值, done 用于判断是否遍历结束,当 done 为 true 时则遍历结束
const items = ["zero", "one", "two"]; const it = items[Symbol.iterator](); it.next(); >{value: "zero", done: false} it.next(); >{value: "one", done: false} it.next(); >{value: "two", done: false} it.next(); >{value: undefined, done: true}
for...of 循环(参见下文的 for...of 循环)对数据结构进行迭代:
for (let item of ["zero", "one", "two"]) { console.log(item); } // output: // zero // one // two
12.Class 类
在ES6中,class (类)作为对象的模板被引入,可以通过 class 关键字定义类。class 的本质是 function。它可以看作一个语法糖,让对象原型的写法更加清晰、更像面向对象编程的语法。
13.模块(重要)
ES6 引入了模块化,其设计思想是在编译时就能确定模块的依赖关系,以及输入和输出的变量。
ES6 的模块化分为导出(export) @与导入(import)两个模块。
特点:
ES6 的模块自动开启严格模式,不管你有没有在模块头部加上 use strict;。
模块中可以导入和导出各种类型的变量,如函数,对象,字符串,数字,布尔值,类等。
每个模块都有自己的上下文,每一个模块内声明的变量都是局部变量,不会污染全局作用域。
每一个模块只加载一次(是单例的), 若再去加载同目录下同文件,直接从内存中读取。
建议使用大括号指定所要输出的一组变量写在文档尾部,明确导出的接口。
函数与类都需要有对应的名称,导出文档尾部也避免了无对应名称。
1. 基本用法:
index.html (注意script的type设为module)
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title></title> <script src="js/test2.js" type="module" charset="utf-8"></script> </head> <body> <div id="app"> </div> <script type="text/javascript"> </script> </body> </html>
test2.js
import { myName, myAge, myfn } from "./test.js"; console.log(myfn());// My name is Tom! I'm 20 years old. console.log(myAge);// 20 console.log(myName);// Tom
test.js
let myName = "Tom"; let myAge = 20; let myfn = function(){ return "My name is" + myName + "! I'm '" + myAge + "years old." } export { myName, myAge, myfn }
2.as 的用法-起别名
export 命令导出的接口名称,须和模块内部的变量有一一对应关系。
导入的变量名,须和导出的接口名称相同,即顺序可以不一致。
/*-----export [test.js]-----*/ let myName = "Tom"; export { myName as exportName } /*-----import [xxx.js]-----*/ import { exportName } from "./test.js"; console.log(exportName);// Tom 使用 as 重新定义导出的接口名称,隐藏模块内部的变量 /*-----export [test1.js]-----*/ let myName = "Tom"; export { myName } /*-----export [test2.js]-----*/ let myName = "Jerry"; export { myName } /*-----import [xxx.js]-----*/ import { myName as name1 } from "./test1.js"; import { myName as name2 } from "./test2.js"; console.log(name1);// Tom console.log(name2);// Jerry
3.import 命令的特点
只读属性:不允许在加载模块的脚本里面,改写接口的引用指向,即可以改写 import 变量类型为对象的属性值,不能改写 import 变量类型为基本类型的值。
单例模式:多次重复执行同一句 import 语句,那么只会执行一次,而不会执行多次。import 同一模块,声明不同接口引用,会声明对应变量,但只执行一次 import 。
静态执行特性:import 是静态执行,所以不能使用表达式和变量。
4.export default 命令
在一个文件或模块中,export、import 可以有多个,export default 仅有一个。
export default 中的 default 是对应的导出接口变量。
通过 export 方式导出,在导入时要加{ },export default 则不需要。
export default 向外暴露的成员,可以使用任意变量来接收。
var a = "My name is Tom!"; export default a; // 仅有一个 export default var c = "error"; // error,default 已经是对应的导出变量,不能跟着变量声明语句 import b from "./xxx.js"; // 不需要加{}, 使用任意变量接收
5.复合使用
export 与 import 可以在同一模块使用,使用特点:
可以将导出接口改名,包括 default。
复合使用 export 与 import ,也可以导出全部,当前模块导出的接口会覆盖继承导出的
export { foo, bar } from "methods"; // 约等于下面两段语句,不过上面导入导出方式该模块没有导入 foo 与 bar import { foo, bar } from "methods"; export { foo, bar }; /* ------- 特点 1 --------*/ // 普通改名 export { foo as bar } from "methods"; // 将 foo 转导成 default export { foo as default } from "methods"; // 将 default 转导成 foo export { default as foo } from "methods"; /* ------- 特点 2 --------*/ export * from "methods";
14.Promise 对象
是异步编程的一种解决方案。
从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。
15.Generator 函数
ES6 新引入了 Generator 函数,可以通过 yield 关键字,把函数的执行流挂起,为改变执行流程提供了可能,从而为异步编程提供解决方案。
14. async 函数
async 是 ES7 才有的与异步操作有关的关键字,和 Promise , Generator 有很大关联的。