[转载]ES6学习笔记

ECMAScript是一种由Ecma国际(前身为欧洲计算机制造商协会,European Computer Manufacturers Association)通过ECMA-262标准化的脚本程序设计语言

JavaScript ,它包含了三大部分:ECMAScript、DOM、BOM ECMAScript:ECMAScript是JavaScript这门语言的核心组成,是这门语言的精髓所在。ECMAScript包括变量定义,函数,语法,作用域等等语法,需要我们去不断钻研 ECMAScript 和 JavaScript 的关系是,前者是后者的语法规范,后者是前者的一种实现(另外的 ECMAScript 方言还有 JScript 和 ActionScript)

1 ECMAScript版本

2011年 ,ECMAScript 5.1版发布

2015年,ECMAScript 6正式版发布,即ECMAScript 2015。简称ES6

2016年,ECMAScript 7发布 2017年,ECMAScript 8发布;

2018年,ECMAScript 9发布

2 为什么要学习ES6

ES6 的版本变动内容最多,具有里程碑意义 ES6 加入许多新的语法特性,编程实现更简单、高效 ES6 是前端发展趋势,就业必备技能

3 ES6新特性

let和const关键字

let 关键字用来声明变量,const关键字用来声明常量。 let和const的区别是:let是变量可以修改,const是常量不可以修改 let和const的相同点: 1.都不能重复声明 2.支持块级作用域,在作用域内定义的变量或常量只能在作用域内使用

变量的解构赋值

ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构赋值。 数组的解构赋值: 把数组的元素赋给多个变量

const arr = ['张学友', '刘德华', '黎明', '郭富城'];
let [zhang, liu, li, guo] = arr;

对象的解构赋值: 把对象的属性值赋给相应的变量

const lin={
    name:'林志颖',
    tags:['车手','歌手','演员']
};
let {name,tags}=lin;

注意:声明和赋值不能分开,必须在一句话里完成

模板字符串

模板字符串(template string)是增强版的字符串,用反引号(`)标识,特点:

  • 字符串中可以出现换行符

  • 可以使用 ${xxx} 形式输出变量

let star = '王宁';
let result = `${star}在前几年离开了开心麻花`;
//当遇到字符串与变量拼接的情况使用模板字符串

对象的简化写法

key和value的名字一样的时候,可以省略value

let a = 1; let b = 2;
let json1 = {a: a, b: b, c: 3};
let json2= {a, b, c: 3}; //简写
console.log(json2);
json内函数简写,可以将函数的:function去掉,直接写函数名()
let obj = {  
    a: "helloWorld",   
   say(){  
       console.log(this.a);   }
};
 obj.say();//helloWorld
//对象简写形式简化了代码,所以以后用简写就对了

箭头函数

箭头函数: 省略function关键字,参数部分和函数体之间用箭头连接

let fn=(a)=> { return a * 2; }
console.log(fn(5));

箭头函数简写:如果没有形参,不能省略(),如果只有一个形参可以省略(),如果函数体只有一个return语句,可以省略{}和return关键字

let fn=()=>{
    return "Hellow";
}
console.log(fn());
let fn=a=>a*2;
console.log(fn(5));
let fn2=(a,b)=>a*b;
console.log(fn2(2,6));

注意:箭头函数不会更改this指向,用来指定回调函数会非常合适. 箭头函数定义回调函数的示例

setTimeout(()=>{
    console.log(this);//this指向window对象
    console.log('3s后显示');
},3000);

rest 参数

ES6中用...args表示rest参数,用于获取函数的实参,它类似于java的可变参数。

let fn1=function(...args){
    console.log(args);
}
fn1(1,2,3);//[1,2,3]
fn1(1,2,3);//[2,3,5]
//注意:rest参数适用于参数个数不确定的函数,且只能在参数列表的最后面

spread 扩展运算符

扩展运算符(spread)也是三个点(...)。它好比 rest 参数的逆运算,将一个数组转为用逗号分隔的参数序列,展开数组。

const city1=["北京","上海","重庆"];
const city2=["南京","杭州"];
let citys=[...city2,...city1];
console.log(citys);

迭代器

迭代器(Iterator)就是一种接口,为各种不同的数据结构提供统一的访问机制(也叫"遍历器")。任何数据结构只要部署 Iterator接口,就可以认为是"可遍历的",可完成遍历操作。部署Iterator接口就是一个数据结构具有Symbol.iterator属性。
原生具备 iterator 接口的数据类型如下,可统一使用 for ...of 进行遍历 a) Array b) Set c) Map d) String e) TypedArray f) NodeList 注意 1). for..of循环与for..in循环相比,for..in只能遍历出key(数组的索引),for..of直接得到value. 如果要通过for...of循环获取数组的索引,可借助数组实例的keys方法.

const westTravel=["唐僧","孙悟空","猪八戒","沙僧"];
console.log(westTravel);
for(let v of westTravel){
    console.log(v);
}
console.log('***********************');
const emps=[{
    eid=001,
    name='路仁贾',
    sex='男'
},{
    eid:002,
    name='肖兵倚',
    sex='女'
}];
//for...of遍历索引
for(let index of emps.keys()){
    console.log(index,emps[index]);
}

2). for..of循环与forEach循环相比, for..of可和break、continue配合使用,而forEach不能用break,continue,但能用return

Set类型

ES6 提供了新的数据结构 Set(集合)。它类似于数组,但成员的值都是唯 一的,集合实现了 iterator 接口,所以可以使用『扩展运算符』和『for…of…』进 行遍历,集合的属性和方法:

  1. size: 返回集合的元素个数

  2. add(): 增加一个新元素,返回当前集合

  3. delete(): 删除元素,返回 boolean 值

  4. has(): 检测集合中是否包含某个元素,返回 boolean 值

  5. clear(): 清空集合,返回 undefined

let s1=new set([1,2,3,2,3]);
console.log(s1.size);
console.log(s1.add(4));
for(const e of s1){
    console.log(e);
}
console.log(s1.delete(2));
console.log(s1.has(2));
console.log(s1.clear());

Map类型

ES6 提供了Map数据结构。它类似于对象,也是键值对的集合。但是key可以是各种类型的值(包括对象)。Map 也实现了iterator 接口,所以可以使用『扩展运算符』和『for…of…』进行遍历。Map 的属性和方法:

  1. size: 返回 Map 的元素个数

  2. set(): 增加一个新元素,返回当前 Map

  3. get(): 返回键名映射的键值

  4. has(): 检测 Map 中是否包含某个元素,返回 boolean 值

  5. clear(): 清空集合,返回 undefined

class类

ES6 提供了更接近传统语言的写法,引入了 Class(类)这个概念,作为对象的模板。通过 class 关键字,可以定义类。新的 class 写法让对象原型的写法更加清晰、更像面向对象编程的语法而已。 知识点:

  1. class 声明类

  2. constructor 定义构造函数

  3. extends 继承父类

  4. super 调用父级构造方法

  5. static定义静态方法和属性

  6. 父类方法可以重写

class Phone{ //父类
    constructor(brand,color,price){ //构造方法
        this.brand=brand;
        this.color=color;
        this.price=price;
    }
    call(){ //对象方法
        console.log(this.brand +'品牌手机比较好')
    }
}
class SmartPhone extends Phone{ //子类
    constructor(brand,color,price,pixel){
        super(brand,color,price);
        this.pixel=pixel;
    }
    playGame(){ //子类方法
        console.log('玩游戏流畅');
    }
    call(){ //方法重写
        console.log('网络通畅');
    }
    static run(){
        console.log('程序运行速度快');
    }
}

数值扩展方法

Math.trunc(): 用于去除一个数的小数部分,返回整数部分。 Number.isInteger(): 用来判断一个数值是否为整数. Number.parseInt() 与 Number.parseFloat():这两个方法和全局方法 parseInt 和parseFloat的作用一样

数组扩展方法

Array.of():将一组数值转换为数组 find():数组实例方法,返回数组中第一个满足条件的元素,如果没有满足条件的元素,返回undefined

findIndex():数组实例方法,返回第一个符合条件的元素的索引,若无满足条件的元素,返回-1 keys(),values()和entries():它们都是数组实例的方法,都返回一个遍历器对象。 keys()返回可遍历所有键的Iterator,values返回可遍历所有值的Iterator,entries()返回可遍历所有键值的Iterator。利用for..of可以完成遍历操作 filter():去掉数组中不满足条件的数据,返回满足条件的数据 下面的示例保留可被5整除的数

const a1=[3,5,12,15,9];
let a2=a1.filter(item=>item % 5==0);
console.log(a2);

map(): 按某个条件对原数组进行检测,将元素映射到一个新数组中

const emps=[{
    name:"张鸣",
    salary:5600
},{
    name:"李华",
    salary:6100
},{
    name:"王亮",
    salary:7200
}];
let result=emps.map((value)=>{
    (if(value.salary>6000){
        return value.name;
    }
    return value.salary;
    })

模块化

模块化是指将一个大的js程序文件,拆分成若干小的文件,然后将小文件组合起来。 当项目变的复杂的时候,一个html页面可能需要加载好多个js文件,这时很容易出现命名冲突(如a.js和b.js中定义了同名的变量s),并且多个js文件之间不能相互引用。 我们可通过模块化来解决上述问题。 模块化是一种管理方式,即把特定的功能封装到一个模块(文件)中,模块之间相互隔离,但可以通过特定的接口公开内部成员,也可以依赖别的模块。 模块化开发的好处:方便代码的重用,提升开发效率,方便后期的维护。

ES6之前的模块化规范

(1)CommonJS => NodeJS、Browserify (2)AMD => requireJS (3)CMD => seaJS

CommonJS是Node中的模块化规范,其特点如下: 1).模块分为单文件模块与包 2).模块成员导出:module.exports和exports 3).模块成员导入:require('模块标识符')

ES6的模块化规范

ES6模块化规范中有如下定义: 1). 每个js文件都是一个独立的模块 2). 导入模块成员使用import关键字 3). 暴露模块成员使用export关键字

基于Babel体验ES6模块化

Babel是一个javascript编译器,可将ECMAScript 2015+ 版本的代码转换为向后兼容的JavaScript 语法。简单的说,就是将ES6代码转为ES5代码,从而在现有环境执行(有些浏览器可能不兼容ES6)。 要使用Babel这款js语法转换器,需要做如下操作: (1).全局安装babel-cli和browserify(编译)

npm install babel-cli browserify -g

(2).在项目中定义package.json文件 (在项目根目录下执行npm init -y命令可自动生成该文件) 参考内容如下:

{ "name": "es6-babel", "version": "1.0.0" }

(3).在项目中安装预设(转换器)

npm install babel-preset-latest --save-dev 或
npm i babel-preset-latest -D

(4).在项目中添加.babelrc配置文件 该文件在项目的根目录下,用来设置转码规则和插件,基本格式如下。

{
    "presets": [],
    "plugins": []
}

parsets字段设定转换规则,官方提供以下规则集。 ES2015转码规则

  npm install babel-preset-es2015 --save-dev 

最新转码规则

npm install babel-preset-latest --save-dev

最后将转换规则加入.babelrc.例如 将最新转码规则加入

{
    "presets": ["latest"],
    "plugins": []
}

(5).在项目中编码,创建不同的模块 分别在src/js目录下创建2个js文件(模块),用来导出成员 module1.js: 导出模块成员方式1:分别暴露

export function foo() {console.log('module1 foo()');} 
export let bar = function () {console.log('module1 bar()');} 
export const  DATA_ARR=[1,3,5]

module2.js: 导出模块成员方式2:统一暴露

let data = 'module2 data' function fun1() {console.log('module2 fun1() ' + data);}
function fun2() {console.log('module2 fun2() ' + data);}
export {fun1,fun2}

再创建main.js用来导入上面的模块 //引入其它的模块 import xxx from '路径' /以下{foo,bar}是解构赋值的写法,相当于解析module1实例的属性foo,bar(其值为函数),并赋值给foo和bar变量/

 import {foo, bar, DATA_ARR} from './module1'
 import {fun1, fun2} from './module2'
 foo(); bar(); 
console.log(DATA_ARR);
 fun1(); fun2();

(6).进行转码 首先创建输出目录,再执行如下命令

babel 源目录 -d 输出目录
browserify 源文件 -o 输出文件
其中-d参数指定输出目录,用browserify编译js
例如:babel src/js -d dist
browserify dist/main.js -o dist/index.js

这样在dist目录下就生成了转换后的index.js文件,它可兼容旧浏览器. 我们在页面上引入index.js文件,访问页面就能看到执行效果了,模块化成功! 补充:ES6规范中,导出模块成员除了上面用到的两种外,还有一种默认导出export default

let func=function(){
    console.log("module3 func");
}
export default{
    a,b,func
}

对于默认导出的方式,在导入时要import 模块实例名 from '路径'

//导入默认导出的模块成员
import m3 from './module3'
//调用默认导出的模块成员
m3.func();
console.log(m3.a);

附录(html补充说明代码)

01.es6的let和const

    /* let和const关键字
    let 关键字用来声明变量,const关键字用来声明常量。
    let和const的区别是:let是变量可以修改,const是常量不可以修改
    let和const的相同点:
    1.都不能重复声明 2.支持块级作用域,在作用域内定义的变量或常量只能在作用域内使用 */

    let a = 10;
    const city = '武汉';
    console.log('a=' + a, city);
    // city = '北京';
    a = 20;
    console.log('a=' + a, city);
    if (true) {
        let b = 15;
        console.log(b);
    }
    //console.log(b); // 'b' is not defined
    //在ES5中,没有专门声明常量的关键字,统一用var声明,es5中声明的变量不支持块级作用域
    if (true) {
        var s = 16;
    }
    console.log(s);
    //city='南京';

02.变量的解构赋值

        //数组的解构赋值:把数组中的元素赋给变量
        const arr = ['张学友', '刘德华', '黎明', '郭富城'];
        let [zhang, liu, li, guo] = arr;
        console.log(zhang, liu, li, guo);

        const star = {
            name: '黎明',
            tags: ['歌神', '影帝']
        };
        //对象的解构赋值:把对象的属性值赋给变量,变量名要和对象的属性名一样
        let {
            name,
            tags
        } = star;
        console.log(name);
        console.log(tags);

03.模板字符串

        let city = '南京';
        console.log(`李明在${city}工作`);

04.对象的简写

        //对象的简写
        let name = "张三";
        let p = {
            name, //等价于name:name
            work() {
                console.log(`${this.name}正在工作!`);
            }
        }

        p.work();
        //ES5中不能用对象的简写

06.rest参数与扩展运算符

        //rest参数:...args
        //实现对任意个参数求和,并返回
        function totalSum(...args) {
            let sum = 0;
            //args能收集所有的实参,把args当成数组来使用
            if (args != null && args.length > 0) {
                //for..in循环数组时,变量i代表索引
                for (let i in args) {
                    sum += args[i];
                }
            }
            return sum;
        }

        let result = totalSum();
        console.log(result); //0
        result = totalSum(2, 3);
        console.log(result); //5
        result = totalSum(2, 3, 9);
        console.log(result); //14
        //Spread扩展运算符:将一个数组转为用逗号分隔的参数序列,展开数组
        const city1 = ['武汉', '南京'];
        const city2 = ['北京', ...city1, '上海'];
        console.log(city2);

07.迭代器

        const westEast = ['唐僧', '孙悟空', '八戒', '沙师弟'];
        console.log(westEast);
        //for...of遍历数组,element表示每个元素本身
        for (let element of westEast) {
            console.log(element);
        }
        //for..in遍历数组,element代表索引(从0开始)
        for (let element in westEast) {
            console.log(element);
        }
        console.log('*************************');
        //for...of遍历数组,数组.keys()得到所有的索引(数组)
        for (let element of westEast.keys()) {
            if (element == 2) {
                continue;
            }
            console.log(element, westEast[element]);
        }
        console.log('*************************');
        //ES5中的forEach循环,它传入一个回调函数,参数e代表每个元素,i代表索引
        westEast.forEach((e, i) => {
            console.log(i, e);
            if (i == 2) {
                return; //结束当前这次循环
            }
        });

08.Set

        const set = new Set([1, 2, 3, 2, 4]);
        console.log('size:' + set.size);
        //新增成员
        let result = set.add(5);
        console.log(result);
        console.log(result.has(5));;
        //遍历
        for (let item of result) {
            console.log(item);
        }

09.Map

        const bookMap = new Map([
            ['id', 'b001']
        ]);

        //新增成员
        bookMap.set('name', '红楼梦');
        bookMap.set('price', 108);
        console.log(bookMap);
        console.log(bookMap.get('name'));
        console.log(bookMap.has('price'));
        //遍历:item代表key,value的键值对,键值对构成了数组
        for (let item of bookMap.entries()) {
            console.log(`key:${item[0]},value:${item[1]}`);
        }

10.class定义类

        //父类
        class Phone {
            //构造函数
            constructor(brand, color) {
                this.brand = brand;
                this.color = color;
            }
            //实例方法
            call() {
                console.log(`${this.brand}品牌的手机可以打电话!`);
            }
        }
        //子类
        class HuaWei extends Phone {
            //构造函数
            constructor(brand, color, price) {
                //调用父类的构造函数
                super(brand, color);
                this.price = price;
            }
            //子类方法
            playGame() {
                console.log(this.price + '元的手机玩游戏', '品牌:' + this.brand, '颜色:' + this.color);
            }
            //重写父类的方法
            call() {
                console.log('我可以打视频电话');
            }
            //静态方法
            static run() {
                console.log('我可以运行大应用程序');
            }
        }
        //创建对象
        const parent = new Phone('苹果', '灰色');
        parent.call();
        console.log('******************************');
        const child = new HuaWei('华为', '银色',
            6800);
        child.playGame();
        child.call();
        //调用静态方法
        HuaWei.run();

11.数组的扩展方法

        // Array.of(): 将一组数值转换为数组
        const arr = Array.of(10, true, 'Hello');
        console.log(arr);
        //find(): 数组实例方法,返回数组中第一个满足条件的元素,如果没有满足条件的元素,返回undefined
        const arr2 = [3, 4, 6, 8, 9];
        let result = arr2.find(item => item > 5)
        console.log(result);

        /*  keys() , values()和 entries():它们都是数组实例的方法,都返回一个遍历器对象。
         keys()返回可遍历所有键的Iterator,values返回可遍历所有值的Iterator,entries()返回可遍历所有键值的Iterator。利用for..of可以完成遍历操作 */
        for (let i of arr2.keys()) {
            console.log('index:' + i); //key就是索引
        }
        console.log('*******************************');
        for (let v of arr2.values()) {
            console.log(`value:${v}`);
        }
        console.log('*******************************');
        for (let entry of arr2.entries()) {
            console.log(`key:${entry[0]},value:${entry[1]}`);
        }
        console.log('*******************************');
        const a1 = [3, 5, 15, 12, 19]
        let a2 = a1.filter(value =>
            value % 5 == 0
        )
        console.log(a2);
        console.log('*******************************');

        const stus = [{
            name: '张明',
            score: 78
        }, {
            name: '王亮',
            score: 58
        }, {
            name: '朱云',
            score: 90
        }]
        let a3 = stus.map(value => {
            if (value.score > 80) {
                return '优秀'
            } else if (value.score >= 60) {
                return '良好'
            } else {
                return '不及格'
            }
        })
        console.log(a3); 

本文章使用limfx的vscode插件快速发布