目录
什么是 ES6?
let 和 const
字符串模板
解构赋值
复制数组
Map
for-of 循环
箭头函数
对象的简洁语法
class 和 extends
模块化 - export,import
- Promise
- Generator,yield
1. 什么是 ES6?
ECMAScript 6(以下简称 ES6)是 JavaScript 语言的下一代标准. 因为当前版本的 ES6 是在 2015 年发布的, 所以又称 ECMAScript 2015(简称 ES2015). 虽然浏览器在不断更新, 但并不是所有用户的电脑浏览器都支持 ES6, 所以在使用的过程中建议还是转成 es5, 保证代码的可执行性. 至于转换的方式大家可以用 Babel 或者 Traceur 转码器.
2. let 和 const
在 ES6 以前, Javascript 并不同有块级作用域的概念, 有的是函数作用域, 而 let 的出现就是为了打破局面, 有点向后台语言发展的趋势. const 是代表常量, 必须在定义的时候初始化, 不可改变. 下面我举例子说明.
- window.onload = function(){
- var aInput = document.getElementsByTagName("input");
- // 传统解决办法
- for(var i=0;i<aInput.length;i++){
- (function(i){
- // 函数闭包自执行来解决 i 索引的问题
- aInput[i].onclick = function(){
- alert(i);
- };
- })(i);
- }
- // let 变量的出现相当于给你加了一个封闭空间来极度简化了 i 值索引的问题
- // let 大家可以看成是匿名函数立即调用(IIFE)
- for(let i=0;i<aInput.length;i++){
- aInput[i].onclick = function(){
- alert(i);
- };
- }
- };
- // 对于 let 和 const 来说, 变量不能重新声明, 所以一旦赋值的变量以前声明过, 就会报错, 而以前 var 的时候并不会报错, 只是覆盖定义
- let a = 12;
- let a = 13; //Identifier 'a' has already been declared
- //const 必须在初始化的时候同时赋初值, 且不能更改
- const b; //Uncaught SyntaxError: Missing initializer in const declaration
- const b = 14;
- b = 15; //Uncaught TypeError: Assignment to constant variable.
3. 字符串模板
- // 传统字符串拼接
- var s1 = '快乐童年放飞希望 ^_^';
- var s2 = '国家主席 ^_^';
- var str = '2013 年 5 月 29 日, 中共中央总书记,'+s2+', 中央军委主席习近平在'+
- '北京市少年宫参加"'+s1+'"主题队日活动. 这是习近平在和孩子们谈对环保的认识和'+'理解. 新华社记者李学仁摄';
- document.write(str);
- // 字符模板的写法
- var s1 = '快乐童年放飞希望 ^_^';
- var s2 = '国家主席 ^_^';
var str = `2013 年 5 月 29 日, 中共中央总书记,${s2}, 中央军委主席习近平在北京市少年宫参加 "${s1}" 主题队日活动. 这是习近平在和孩子们谈对环保的认识和理解. 新华社记者李学仁摄 `;
document.write(str);
4. 解构赋值
- // 以前我们给变量赋值, 只能直接指定值
- var a = 1;
- var b = 2;
- var c = 3;
- console.log(a,b,c); // 1 2 3
- // 现在用解构赋值的写法就变得简单了, 只要模式匹配上了就行了, 如下
- // 注意数组是有顺序的
- var [a,b,c] = [11,22,33];
- console.log(a,b,c); // 11 22 33
- var [b,a,c] = [11,22,33];
- console.log(a,b,c); // 22 11 33
- // 当然解构赋值还有嵌套比较复杂的写法, 如下
- let [foo,[[bar],[baz]]] = [111,[[222],[333]]];
- console.log(foo,bar,baz); // 111 222 333
- let [head,...foot] = [1,2,3,4];
- console.log(head,foot); // 1 [2,3,4]
- // 如果解构不成功, 变量的值就等于 undefined, 如下
- var [bar3,foo3] = [1000];
- console.log(bar3,foo3); // 1000 undefined
- // 另一种情况是不完全解构, 即等号左边的模式, 只匹配一部分的等号右边的数组. 这种情况下, 解构依然可以成功
- let [x,y] = [10000,20000,30000];
- console.log(x,y); // 10000 20000
- // 默认值可以引用解构赋值的其他变量, 但该变量必须已经声明
- let [a=1,b=a] = [2,3];
- console.log(a,b); // 2 3
- // 对象的解构也可以指定默认值
- var {x,y=5} = {x:1};
- console.log(x,y); // 1 5
- // 对象的解构赋值解构不仅可以用于数组, 还可以用于对象(json)
- // 对象的解构与数组有一个重要的不同. 数组的元素是按次序排列的, 变量的取值由它的位置决定;
- // 而对象的属性没有次序, 变量必须与属性同名, 才能取到正确的值
- var {a,b} = {a:'apple',b:'banana'};
- console.log(a,b); // apple banana
- var {b,a} = {a:'apple',b:'banana'};
- console.log(a,b); // apple banana
- // 如果变量名与属性名不一致, 必须写成下面这样
- let obj = {first:'hello',last:'world'};
- // first ---> f, 那么此时 f 就是 first, 而不是 undefined 了, 有点类似别名的概念
- let {first:f,last} = obj;
- console.log(f,last); // hello world
- //1. 也就是说, 对象的解构赋值的内部机制, 是先找到同名属性, 然后再赋给对应的变量. 真正被赋值的是后者, 而不是前者
- //2.v 是匹配的模式, n 才是变量. 真正被赋值的是变量 n, 而不是模式 v.
- // 注意, 采用这种写法时, 变量的声明和赋值是一体的
- // v ---> n, 那么此时 n 就是 vue, 而不是 undefined 了
- var {v:n} = {v:'vue',r:'react'};
- console.log(n); // vue
- console.log(v); // Uncaught ReferenceError: v is not defined
- console.log(r); // Uncaught ReferenceError: r is not defined
5. 复制数组
- // 数组的浅拷贝, 引用之间的拷贝, 没有实现数组的真正复制
- var arr1 = [1, 2, 3];
- var arr2 = arr1;
- arr2.push(4);
- console.log(arr1, arr2);
- // 复制数组深拷贝, 传统做法
- var arr1 = [1,2,3];
- var arr2 = [];
- // 通过 for 循环遍历之后将 arr1 数组的每一项赋值给 arr2 数组的每一项, 就实现了数组的深拷贝, 这时候我再去操作 arr2 的数组的时候, arr1 就不会受影响了
- for(var i=0;i<arr1.length;i++){
- arr2[i] = arr1[i];
- }
- // 数组尾部添加
- arr2.push(4);
- console.log(arr1,arr2);
- // ES6 实现的数组的深拷贝方法 1
- var arr1 = [1,2,3];
- var arr2 = Array.from(arr1);
- // 数组尾部添加
- arr2.push(100);
- console.log(arr1,arr2);
- // ES6 实现的数组的深拷贝方法 2
- var arr1 = [1,2,3];
- // 超引用拷贝数组
- var arr2 = [...arr1];
- // 数组尾部添加
- arr2.push(1000);
- console.log(arr1,arr2);
- function show(...args){
- // 此时这个形势参数就是一个数组, 我们可以直接 push 东西进来, 如下
- args.push(5);
- console.log(args);
- }
- // 调用
- show(1,2,3,4); // 1,2,3,4,5
- 6. Map
- var map = new Map();
- // 设置
- // map.set(name,value);
- map.set('a','apple');
- map.set('b','banana');
- // 获取
- // map.get(name);
- console.log(map.get('a') + '' + map.get('b'));
- // 删除之前 map 对象
- console.log(map);
- // 删除
- // map.delete(name);
- map.delete('a');
- // 删除之后 map 对象
- console.log(map);
- // 注意 for..in 是不能循环 map 对象的, 不报错也无任何反应, 稍微注意下
- for(var name in map){
- console.log(name);
- }
- // 实体 map=map.entries()
- for(var name of map){
- // 循环出来的结果就是: a,apple b,banana 循环 key,value
- console.log(name);
- }
- // 循环出来的结果就是: a,apple b,banana 循环 key,value
- for(var [key,value] of map.entries()){
- console.log(key,value);
- }
- // 只循环 key
- for(var key of map.keys()){
- console.log(key);
- }
- // 只循环 value
- for(var val of map.values()){
- console.log(val);
- }
7. for-of 循环
- //for of 一个 arr 对象
- var arr = ['红楼梦','西游记','三国演义','水浒传','金瓶梅'];
- // 只循环 key
- for(var key of arr.keys()){
- console.log(key);
- }
- // 只循环 value, 注意数组是没有. values()
- for(var value of arr){
- console.log(value);
- }
- // 循环 key,value
- for(var [key,value] of arr.entries()){
- console.log(key,value);
- }
- //for in 循环与 for of 循环的区别
- var arr = ['apple','banana','orange','pear'];
- for(var i in arr){
- // i 打印出来的就是 arr 数组对应的索引
- // 0 1 2 3
- console.log(i);
- }
- for(var i of arr){
- // i 值打印出来的就是我们想要的数组具体的值
- // apple banana orange pear
- console.log(i);
- }
- //for of 不能循环 json
- var json = {'a':'apple','b':'banana','c':'orange','d':'pear'};
- for(var name in json){
- // a b c d
- console.log(name);
- // apple
- console.log(json.a);
- // pear
- console.log(json['d']);
- }
- // 注意 for..of 可以循环 arr, 但是不可以循环 json, 会报错, 特别注意下
- for(var name of json){
- Uncaught TypeError: undefined is not a function
- console.log(json);
- }
8. 箭头函数
- // 箭头函数写法 function(){} 变为 ()=>{}
- window.onload = () => {
- var oBox = document.getElementById("box");
- oBox.onclick = () => {
- oBox.style.backgroundColor = '#ff0000';
- };
- };
- // 注意 this 指向会有问题
- var json = {
- a:1,
- b:2,
- showName:() => {
- return this.a;
- }
- };
- // 因为使用了箭头函数 this 指向了 object window 所以 result:undefined
- console.log(json.showName());
- // 如果使用了箭头函数的写法, 那么注意 arguments 将不能继续使用了
- var show = () => {
- console.log(arguments);
- };
- // Uncaught ReferenceError: arguments is not defined
- show(1,2,3);
9. 对象的简洁语法
- // 传统对象_单体模式写法 key-value 模式
- var person = {
- name:'jam',
- age:28,
- showName:function(){
- return this.name;
- },
- showAge:function(){
- return this.age;
- }
- };
- // 调用
- console.log(person.showName()); // jam
- console.log(person.showAge()); // 28
- //ES6_单体模式写法 不需要写 key
- var name = 'xiaokai';
- var age = 2;
- var person = {
- name,
- age,
- showName(){
- return this.name;
- },
- showAge(){
- return this.age;
- }
- };
- // 调用
- console.log(person.showName()); // xiaokai
- console.log(person.showAge()); // 2
10. class 和 extends
- // 传统面向对象写法
- function Person(name, age) { // 类, 构造函数
- this.name = name;
- this.age = age;
- }
- Person.prototype.showName = function() {
- return this.name;
- };
- Person.prototype.showAge = function() {
- return this.age;
- };
- var p1 = new Person('allen', 28);
- var p2 = new Person('xiaoxiaoyou', 101);
- console.log(p1.showName()); // allen
- console.log(p2.showAge()); // 101
- console.log(p1.showName == p2.showName); // true
- console.log(p1.constructor == Person); // true
- //ES6 面向对象写法
- class Person {
- // 构造器
- constructor(name, age) {
- this.name = name;
- this.age = age;
- }
- showName() {
- return this.name;
- }
- showAge() {
- return this.age;
- }
- }
- var p1 = new Person('aaa', 18);
- var p2 = new Person('bbb', 20);
- console.log(p1.name); // aaa
- console.log(p1.showName()); // aaa
- console.log(p2.showAge()); // 20
- console.log(p1.showAge == p2.showAge); // true
- console.log(p1.constructor == Person); // true
- // 面向对象 class 给默认值
- class Person {
- // 构造器
- constructor(name = 'default', age = 0) {
- this.name = name;
- this.age = age;
- }
- showName() {
- return this.name;
- }
- showAge() {
- return this.age;
- }
- }
- var p1 = new Person();
- console.log(p1.name); // 构造器里面给的默认值 default
- console.log(p1.age); // 构造器里面给的默认值 0
- // 传统写法原型继承
- function Person(name, age) { // 类, 构造函数
- this.name = name;
- this.age = age;
- }
- Person.prototype.showName = function() {
- return this.name;
- };
- Person.prototype.showAge = function() {
- return this.age;
- };
- // 工人类
- function Worker(name, age) {
- // 属性继承过来
- Person.apply(this, arguments);
- }
- // 原型继承
- Worker.prototype = new Person();
- var p1 = new Person('allen', 28);
- var w1 = new Person('worker', 1000);
- console.log(w1.showName()); // 确实继承过来了 result:worker
- //ES6 中面向对象实现类继承
- class Person {
- // 构造器
- constructor(name, age) {
- this.name = name;
- this.age = age;
- }
- showName() {
- return this.name;
- }
- showAge() {
- return this.age;
- }
- }
- class Worker extends Person {
- constructor(name, age, job = '拖地的') {
- // 继承超父类的属性
- super(name, age);
- this.job = job;
- }
- showJob() {
- return this.job;
- }
- }
- var p1 = new Person('aaa', 18);
- var w1 = new Person('www', 36);
- var w2 = new Worker('wwwwwwww', 90);
- console.log(w1.showName()); // www
- console.log(w2.showJob()); // 默认给的值 '拖地的'
11. 模块化 - export 和 import
下边的演示文件 mod 代表是导出模块 js, index 代表的是引入模块的 js ,mod 文件跟 index 文件一一对应关系 .
- //mod.js
- // 第一种模块导出的书写方式(一个个的导出)
- // 导出普通值
- export let a = 12;
- export let b = 5;
- // 导出 json
- export let json = {
- a,
- b
- };
- // 导出函数
- export let show = function(){
- return 'welcome';
- };
- // 导出类
- export class Person{
- constructor(){
- this.name = 'jam';
- }
- showName(){
- return this.name;
- }
- }
- //index.js
- // 导出模块如果用 default 了, 引入的时候直接用, 若没有用 default, 引入的时候可以用 {} 的形式
- // 导入模块的方式
- import {
- a,
- b,
- json,
- show,
- Person
- } from './mod.js';
- console.log(a); // 12
- console.log(b); // 5
- console.log(json.a); // 12
- console.log(json.b); // 5
- console.log(show()); // welcome
- console.log(new Person().showName()); // jam
- //mod1.js
- // 第二种模块导出的书写方式
- let a = 12;
- let b = 5;
- let c = 10;
- export {
- a,
- b,
- c as cc // as 是别名, 使用的时候只能用别名, 特别注意下
- };
- //index1.js
- // 导入模块的方式
- import {
- a,
- b,
- cc // cc 是导出的, as 别名
- } from './mod1.js';
- console.log(a); // 12
- console.log(b); // 5
- console.log(cc); // 10
- //mod2.js
- // 第三种模块导出的书写方式 ---> default
- // default 方式的优点, import 无需知道变量名, 就可以直接使用, 如下
- // 每个模块只允许一个默认出口
- var name = 'jam';
- var age = '28';
- export default {
- name,
- age,
- default(){
- console.log('welcome to es6 module of default...');
- },
- getName(){
- return 'bb';
- },
- getAge(){
- return 2;
- }
- };
- //index2.js
- // 导入模块的方式
- import mainAttr from './mod2.js';
- var str = ' ';
- // 直接调用
- console.log(` 我的英文名是:${mainAttr.name}我的年龄是 ${mainAttr.age}`);
- mainAttr.default(); // welcome to es6 module of default...
- console.log(mainAttr.getName()); // bb
- console.log(mainAttr.getAge()); // 2
- //mod3.js
- var name = 'jam';
- var age = '28';
- export function getName(){
- return name;
- };
- export function getAge(){
- return age;
- };
- //index3.js
- // 导入模块的方式
- import * as fn from './mod3.js';
- // 直接调用
- console.log(fn.getName()); // jam
- 12. Promise
- //Promise 对象 ---> 用来传递异步操作过来的数据的
- //Pending(等待, 处理中) ---> Resolve(完成, fullFilled) ---> Reject(拒绝, 失败)
- var p1 = new Promise(function(resolve,reject){
- resolve(1); // 成功了
- // reject(2); // 失败了
- });
- // 接收成功和失败的数据, 通过 then 来传递
- // then 也是返回一个 promise 对象, 会继续往下传递数据, 传递给下一个 then
- p1.then(function(value){
- // resolve
- console.log(value);
- return value + 1; // 1
- alert(` 成功了:${value}`);
- },function(value){
- // reject
- alert(` 失败了:${value}`);
- }).then(function(value){
- console.log(value); // 2
- });
- //catch 捕获异常错误
- var p1 = new Promise(function(resolve,reject){
- resolve('成功了');
- });
- p1.then(function(value){
- console.log(value);
- // throw 是用来抛错误的
- throw '发生了点小意外';
- }).catch(function(e){
- // catch 用来捕获这个错误的 ---> 追踪
- console.log(e);
- });
- //all ---> 全部, 用于将多个 promise 对象, 组合, 包装成
- //Promise.all([p1,p2,p3,...]); 所有的 promise 对象, 都正确, 才走成功
- // 否则, 只要有一个错误, 就走失败
- var p1 = Promise.resolve(1);
- var p2 = Promise.reject(0);
- Promise.all([true,p1,p2]).then(function(obj){
- console.log(` 成功了:${obj}`);
- },function(obj){
- console.log(` 失败了:${obj}`);
- });
- // race ---> 返回的也是一个 promise 对象
- // 最先执行的的 promise 结果, 哪个最快我用哪个
- var p1 = new Promise(function(resolve,reject){
- setTimeout(resolve,50,'one');
- });
- var p2 = new Promise(function(resolve,reject){
- setTimeout(resolve,100,'two');
- });
- Promise.race([p1,p2]).then(function(val){
- console.log(val);
- });
- //resolve ---> 生成一个成功的 promise 对象
- // 语法规则: Promise.resolve(val); // 普通值
- // Promise.resolve(arr); // 数组之类
- //Promise.resolve(promise); // 传递另一个 promise 对象
- // 传递普通值
- Promise.resolve('success').then(function(val){
- // 注意 resolve, 走得是这里
- console.log(val); // success
- },function(err){
- console.log("err:"+ err);
- });
- // 传递数组
- Promise.resolve([1,2,3]).then(function(val){
- // 注意 resolve, 走得是这里
- console.log(val); // [1,2,3]
- },function(err){
- console.log(err);
- });
- // 传递一个 promise 对象
- var p1 = Promise.resolve(520);
- var p2 = Promise.resolve(p1);
- p2.then(function(val){
- // 从 p1 那边传递过来的
- console.log(val); // 520
- });
- 13. Generator,yield
- //Generator ---> 生成器就是一个函数
- // 特点:
- //1. 函数名前面带一个 *, 和普通函数做区分
- //2. 内部使用 yield 语句
- // 调用方式, 如下 var res = show();
- //value 指的是 generator 函数内容 yield 定义的值, done:false 表示还没遍历完
- // 直接找到返回值 return 了, 那么此时 done 才会为 true
- //console.log(res.next());{value:'值 1',done:false}
- function* show(){
- yield 'Hello';
- yield 'World';
- yield 'ES6';
- return 'xx';
- }
- var res = show();
- console.log(res.next()); // {value: "Hello", done: false}
- console.log(res.next()); // {value: "World", done: false}
- console.log(res.next()); // {value: "ES6", done: false}
- console.log(res.next()); // {value: "allen", done: true}
- // 已经找到 return 返回值了, 继续下去就没有意义了
- // console.log(res.next()); // {value: "undefined", done: true}
- //yield 本身没有返回值, 或者可以说每次给你返回的是 undefined
- function* show(){
- var a = yield 'Hello';
- return a;
- }
- var res = show();
- console.log(res.next()); // {value: "Hello", done: false}
- console.log(res.next()); // {value: "undefined", done: true}
- //next 方法是可以带参数的, 死循环的 generator 函数
- function* fn(){
- for(var i=0;true;i++){
- // 如果里面传了一个值, 那么它会把这个参数赋给最近的一个 yield
- var a = yield i;
- if(a) i = -1;
- }
- }
- var d = fn();
- console.log(d.next()); // {value: 0, done: false}
- console.log(d.next()); // {value: 1, done: false}
- console.log(d.next()); // {value: 2, done: false}
- // 如果里面传了一个值, 那么它会把这个参数赋最近的一个 yield
- console.log(d.next(true)); // {value: 0, done: false}
- console.log(d.next()); // {value: 1, done: false}
- console.log(d.next()); // {value: 2, done: false}
- console.log(d.next()); // {value: 3, done: false}
- // for..0f 循环 generator 函数
- function* fn(){
- yield 1;
- yield 2;
- yield 3;
- yield 4;
- yield 5;
- return 6;
- }
- //for..0f 循环 generator 函数, 可以取值
- for(let val of fn()){
- document.write(val); // 12345
- }
- // 对象里使用 generator 函数的特殊写法, 注意下
- var json = {
- *show(){
- yield 'a';
- yield 'b';
- return 'c';
- }
- };
- var res = json.show();
- console.log(res.next()); // {value: "a", done: false}
- console.log(res.next()); // {value: "b", done: false}
- console.log(res.next()); // {value: "c", done: true}
来源: http://www.qdfuns.com/article/44817/410e768e41ae60708e546b955ac0711a.html