es6


ES6

210425

1、介绍

  • ECMA:European Computer Manufacturers Association欧洲计算机制造商协会,这个组织的目标是评估、开发和认可电信和计算机标准,94年改名Ecma国际。

  • ECMAScript是由Ecma国际通过ECMA-262标准化的脚本程序设计语言

  • ES6兼容性:http://kangax.github.io/compat-table/es6/可查看兼容性

2、新特性

2.1. let关键字

  • 变量不能重复声明
  • 块级作用域
    • {}
    • if
    • else
    • while
    • for
  • 不存在变量提升
  • 不影响作用域链

2.2. const关键字

  • 一定要赋初始值
  • 一般常量使用大写(潜规则)
  • 常量的值不能修改
  • 块级作用域
  • 对于数组和对象元素修改,不算做对常量的修改,不会报错(地址未修改,修改数据不会报错)
const ARR = ['cs','ef','1ds',1];
ARR[0] = 'iwo';
const A = 10;
//const B;报错
//A = 11;报错

2.3. 变量解构赋值

ES6 允许按照一定模式从数组和对象中提取值,对变量进行赋值,这被称为解构赋值

  • 数组解构
  • 对象解构
 //1、数组的解构
const F4 = ['唐僧', '孙悟空', '猪八戒', '沙和尚'];
let [ts, swk, zbj, shs] = F4;
console.log(ts); //唐僧
console.log(swk); //孙悟空
console.log(zbj); //猪八戒
console.log(shs); //沙和尚

//2、对象的解构
const person = {
    name: '孙悟空',
    age: 18,
    say: function () {
        console.log("我是唐僧的徒弟");
    }
}

let { name, age, say } = person;
console.log(name); //孙悟空
console.log(age); //18
console.log(say); //function这个函数体
say(); //我是唐僧的徒弟

2.4. 模板字符串

ES6 引入新的声明字符串的方式 ``

//ES6 引入新的声明字符串的方式 `` '' ""
//1、声明
let str = `我也是一个字符串哦!`;
console.log(str, typeof str);//string

//2、内容中可以直接出现换行符
let str2 = `
  • 1
  • 2
  • 3
  • 4
`; //3、变量拼接 ${变量} let a = '孙悟空'; let b = `${a}七十二变`;//孙悟空七十二变 console.log(b);

2.5. 简化对象写法

ES6 允许在大括号里面,直接写入变量和函数,作为对象的属性和方法。这样书写更加简洁

let name = '孙悟空';
let skill = function(){
    console.log('他拥有很多技能!');
}

const person = {
    name,  //name:name
    skill, //skill:skill
    flying(){ //省略冒号和function
        console.log("他会脚踏祥云");
    }
}

console.log(person);

2.6. 函数

2.6.1. 箭头函数

ES6 允许使用箭头 => 定义函数

  • this是静态的,this始终指向函数声明时所在作用域下的this的值
  • 不能作为构造函数实例化对象
  • 不能使用arguments变量
  • 箭头函数的简写
    • 省略小括号,当形参有且只有一个参数时
    • 省略花括号,当代码体只有一条语句时,return必须省略,语句执行结果就是函数的返回值
//声明函数
let fn = (a, b) => {
    return a + b;
}
//调用函数
let res = fn(1, 2);
console.log(res);

//1、this是静态的,this始终指向函数声明时所在作用域下的this的值
function getName() {
    console.log(this.name);
}
let getName2 = () => {
    console.log(this.name);
}

//设置window对象的name属性
window.name = 'phy';
const person = {
    name: '孙悟空'
}

//直接调用
getName();//phy
getName2();//phy

//call方法调用
getName.call(person);//孙悟空
getName2.call(person);//phy

//2、不能作为构造函数实例化对象
let Person = (name,age) => {
    this.name = name;
    this.age = age;
}
let me = new Person('xiao',10);
console.log(me); //Person is not a constructor

//3、不能使用arguments变量
let fn1 = () => {
    console.log(arguments);
}
fn1(1,2,3); //arguments is not defined

//4、箭头函数的简写
//1)省略小括号,当形参有且只有一个参数时
let add = n => {
    return n + n;
}
console.log(add(9)); //18

//2)省略花括号,当代码体只有一条语句时,return必须省略,语句执行结果就是函数的返回值
let pow = n => n*n;
console.log(pow(9)); //81

2.6.2. 参数默认值

  • 形参的初始值,具有默认值的参数,一般位置靠后
  • 与解构赋值结合
//es6允许给函数参数赋初始值
    //1、形参初始值,具有默认值的参数,一般位置要靠后
    function add(a, b, c = 10) {
      return a + b + c;
    }
    console.log(add(1, 2));
    //2、与解构赋值结合
    function connect({ host, username, password, port }) {
      console.log(host);
      console.log(username);
      console.log(password);
      console.log(port);
    }
    connect({
      host: 'baidu.com',
      username: 'root',
      password: 'root',
      port: 3306
    })

2.7. rest参数

ES6引入rest参数,用于获取函数的实参,用来代替arguments

ES5获取实参的方式

function data(){
    console.log(arguments)
}
data('1','2','3') //输出1,2,3 类型object

rest参数

function data(...args){
    console.log(args)
}
data('1','2','3')//1,2,3 类型array,具有数组的方法

//rest参数必须放在参数最后
function fn(a,b,...args){
    console.log(a)
    console.log(b)
    console.log(...args)
}
fn(1,2,3,4,5,6)

2.8. spread扩展运算符

...扩展运算符能将数组转换为逗号分隔的参数序列

const arr = [1,2,3]
function fn(){
    console.log(arguments)
}
fn(...arr) // fn(1,2,3)

扩展运算符应用

  • 数组合并
  • 数组克隆 (有引用数据类型是浅拷贝)
  • 将伪数组转为真正的数组
//1、数组的合并
const arr1 = [1,2,3]
const arr2 = [4,5,6]
const arr3 = [...arr1,...arr2]
console.log(arr3) //[1,2,3,4,5,6]
//2、数组克隆
const arr = ['A','B','C']
const copyarr = [...arr]
console.log(copyarr)
//3、将伪数组转为真正的数组
const allDivs = doucment.querySelectorAll('div')
const arrDiv = [...allDivs]
console.log(arrDiv) //可以使用数组的方法

2.9. Symbol

ES6引入了一种新的原始数据类型Symbol,表示独一无二的值。是JavaScript语言的第七种数据类型,类似于字符串的数据类型

Symbol特点:

  • Symbol的值是唯一的,解决命名冲突的问题
  • Symbol值不能与其他数据进行运算
  • Symbol定义的对象属性不能使用for..in循环遍历,但可以使用Reflect.ownKeys获取对象的所有键名

2.9.1 Symbol基本使用

//创建Symbol
let s = Symbol()
console.log(s,typeof s)
let s2 = Symbol('phy')
let s3 = Symbol('phy')
console.log(s2 === s3)//false 'phy'只是一个标识名称
//Symbol.for创建
let s4 = Symbol.for('phy')
let s5 = Symbol.for('phy')
console.log(s4 === s5) //true函数对象创建

//不能与其他数据进行运算
let res = s + 100//fault
let res = s > 100//fault
let res = s + s//fault

//JavaScript基本数据类型
//u undefined
//s string symbol
//o object
//n null number
//b boolean

symbol创建对象属性

给对象添加独一无二的属性和方法

//向对象中添加方法 up down
//可以为其对象添加up方法,不影响对象已有的up方法
let game = {
    name:"俄罗斯方块",
    up:function(){
        console.log(1)
    }
}
let methods = {
    up: Symbol(),
    down: Symbol()
}
game[methods.up] = function(){
    console.log("我可以改变形状!")
}
game[methods.down] = function(){
    console.log("我可以快速下降!")
}
console.log(game)

//方法2
let game2 = {
    name:"狼人杀",
    [Symbol('say')]:function(){
        console.log("我可以发言!")
    }
}
console.log(game2)

2.9.2 Symbol内置值

参考文档:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Symbol

  • Symbol.hasInstance 当其他对象使用instanceof运算符,判断是否为该实例对象时,会调用这个方法
  • Symbol.isConcatSpreadable 该属性是一个布尔值,控制对象用于Array.prototype.concat()时,是否可以展开
//Symbol.hasInstance
//可以获取instanceof前的值
//可以自己控制类型检测
class Person{ //类似构造函数
    static [Symbol.hasInstance](param){
        console.log(param) //可以获取instanceof前的值
        console.log("我被用来检测类型")
        return false //可以自己控制类型检测
    }
}
let o = {}
console.log(o instanceof Person) //{} 我被用来检测类型 false

//Symbol.isConcatSpreadable
const arr = [1,2,3]
const arr2 = [4,5,6]
arr2[Symbol.isConcatSpreadable] = false
console.log(arr.concat(arr2)) //1,2,3,[4,5,6]

2.10. 迭代器

2.10.1. 介绍

Iterator是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署Iterator接口(对象的一个属性Symbol.iterator),就可以完成遍历操作。

  • ES6创造了一种新的遍历命令for..of循环,Iterator接口主要供for..of使用
  • 原生具备Iterator接口的数据(可用for of遍历)
    • Array
    • Arguments
    • Set
    • Map
    • String
    • TypeArray
    • NodeList
  • 工作原理
    • 创建一个指针对象,指向当前数据结构的起始位置
    • 第一次调用对象的next方法,指针自动指向数据结构的第一个成员
    • 接下来不断调用next方法,指针一直往后移动,知道指向最后一个成员
    • 每调用next方法返回一个包含value和done属性的对象
  • 注:需要自定义遍历数据时,会使用到迭代器
const xiyou = ['唐僧','孙悟空','猪八戒','沙和尚']
//遍历值
for(let v of xiyou){
    console.log(v)
}//唐僧 孙悟空 猪八戒 沙和尚 

// 遍历下标
for(let v in xiyou){
    console.log(v)
}//0 1 2 3

console.log(xiyou) //Symbol.iterator

let iterator = xiyou[Symbol.iterator]();
//调用对象的next方法
console.log(iterator.next()) //{value: "唐僧", done: false}
console.log(iterator.next()) //{value: "孙悟空", done: false}
console.log(iterator.next()) //{value: "猪八戒", done: false}
console.log(iterator.next()) //{value: "沙和尚", done: false}
console.log(iterator.next()) //{value: undefined, done: true} done判断是否结束

2.10.2. 应用

const banji = {
    name: "终极一班",
    stus: [
        'tom',
        'bob',
        'lisa',
        'susan'
    ],
    [Symbol.iterator]() {
        let index = 0
        let _this = this
        return {
            next: function () {
                if (index < _this.stus.length) {
                    const res = { value: _this.stus[index], done: false }
                    index++
                    return res
                } else {
                    return { value: undefined, done: true }
                }
            }
        }
    }
}

// 遍历这个对象
for (let v of banji.stus) {
    console.log(v)
}

2.11. 生成器

是一个特殊的函数,是一种异步编程解决方案,语法行为与传统函数完全不同

2.11.1. 使用

function* gen1() {
    console.log("hello generator")
}
let iterator1 = gen1()
console.log(iterator1)
// 调用
iterator1.next() //hello generator

function* gen() {
    //函数代码的分隔符 next()执行
    console.log(111)
    yield '一只没有耳朵'
    console.log(222)
    yield '一只没有尾巴'
    console.log(333)
    yield '真奇怪'
    console.log(444)
}
let iterator = gen()
iterator.next()//111
iterator.next()//222
iterator.next()//333
iterator.next()//444
//遍历
for(let v of gen()){
    console.log(v) //yield的值
}

2.11.2. 生成器函数参数

  • 函数可以传形参
  • next方法种可以传入实参
//可以对函数传参
function * gen(arg){
    console.log(arg) //AAA
    let one = yield 111
    console.log(one) //BBB
    let two = yield 222
    console.log(two) //CCC
    let three = yield 333
    console.log(three) //DDD
}
let iterator = gen('AAA')
// next方法可以传入实参
console.log(iterator.next()) //{value: 111, done: false}
// 参数将会作为上一个yield语句的返回结果
console.log(iterator.next('BBB')) //{value: 222, done: false}
console.log(iterator.next('CCC')) //{value: 333, done: false}
console.log(iterator.next('DDD')) //{value: undefined, done: true}

2.11.3. 生成器函数实例

// 生成器解决回调地狱问题
function one() {
    setTimeout(() => {
        console.log(111)
        iterator.next()
    }, 1000)
}
function two() {
    setTimeout(() => {
        console.log(222)
        iterator.next()
    }, 2000)
}
function three() {
    setTimeout(() => {
        console.log(333)
        iterator.next()
    }, 3000)
}
function* gen() {
    yield one()
    yield two()
    yield three()
}
// 调用生成器函数
let iterator = gen()
iterator.next()
// 模拟获取 用户数据订单数据商品数据
function getNames() {
    setTimeout(()=>{
        let data = '用户数据'
        // 调用next方法,传入数据
        iterator.next(data)//第二次调用next,data将会作为第一个yield的实参
    },1000)
}
function getOrders() {
    setTimeout(()=>{
        let data = '订单数据'
        iterator.next(data)
    },1000)
}
function getGoods() {
    setTimeout(()=>{
        let data = '商品数据'
        iterator.next(data)
    },1000)
}
function * gen(){
    let name = yield getNames()
    console.log(name) //用户数据
    let order = yield getOrders()
    console.log(order) //订单数据
    let good = yield getGoods()
    console.log(good) //商品数据
}
//调用生成器函数
let iterator = gen()
iterator.next()

2.12. Promise

是ES6引入的异步编程的新解决方案。语法上Promise是一个构造函数,用来封装异步操作并可以获取其成功或失败的结果

  • Promise构造函数:Promise(excutor){}
  • Promise.prototype.then()方法
  • Promise.prototype.catch()方法

2.12.1. 使用

//实例化Promise对象,可以通过resolve与reject改变p的状态
const p = new Promise(function (resolve, reject) {
    // let data = '数据库中的用户数据'
    // resolve(data)
    let err = '读取数据失败'
    reject(err)
})

// 调用promise对象的then方法
p.then(function (value) {
    console.log(value)
}, function (err) {
    console.log(err)
})

2.12.2. promise读取文件

const fs = require('fs')
// fs.readFile('./1.txt',(err,data)=>{
//   if(err) throw err
//   console.log(data.toString())
// })
// 使用promise封装
const p = new Promise((resolve, reject) => {
  fs.readFile('./1.txt', (err, data) => {
    if (err) reject(err)
    resolve(data)
  })
})

p.then(function (value) {
  console.log(value.toString())
}, function (reason) {
  console.log("读取失败!!")
})

2.12.3. promise封装AJAX

const p = new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();
    xhr.open('get', 'https://api.apiopen.top/getJoke')
    xhr.send()
    xhr.onreadystatechange = function () {
        if (xhr.readyState === 4) {
            if (xhr.status >= 200 && xhr.status < 300)
                resolve(xhr.response)
            else
                reject(xhr.status)
        }
    }
})
p.then(function (value) {
    console.log(value)
}, function (reason) {
    console.error(reason)
})

2.12.4. promise-then方法

const p = new Promise((resolve,reject)=>{
    setTimeout(()=>{
        resolve('用户数据')
    },1000)
})

//调用then方法 then方法得返回结果是promise对象,对象状态由回调函数的执行结果决定
//1、如果回调函数中返回的结果是非promise类型的属性,状态为成功,返回值为对象的成功的值
const res = p.then(value => {
    console.log(value)
    //1、非promise类型的属性:undefined字符串数字
    //return 123
    //2、是promise对象
    return new Promise((resolve,reject)=>{
        //会影响then方法的状态
        //resolve('ok')
        reject('error')
    })
    //3、抛出错误
    //throw new Error('出错啦!')
    throw '出错啦!'
},reason => {
    console.warn(reason)
})
console.log(res)

2.12.5. promise读取多个文件内容

const fs = require('fs')
const p = new Promise((resolve, reject) => {
  fs.readFile('./1.txt', (err, data) => {
    resolve(data)
  })
})
p.then(value => {
  return new Promise((resolve, reject) => {
    fs.readFile('./2.txt', (err, data) => {
      resolve([value, data])
    })
  })
}).then(value => {
  return new Promise((resolve, reject) => {
    fs.readFile('./3.txt', (err, data) => {
      value.push(data)
      resolve(value)
    })
  })
}).then(value => {
  console.log(value.join('\r\n'))
})

2.12.6. promise-catch方法

处理拒绝的情况

const p = new Promise((resolve,reject)=>{
    setTimeout(()=>{
        reject("出错啦!");
    },1000)
})
p.catch((reson)=>{
    console.warn(reason)
})

2.13. Set

新的数据结构Set(集合),类似于数组,但成员的值都是唯一的,集合实现了iterator接口,可以使用扩展运算符for..of..进行遍历。

集合的属性和方法:

  • size 返回集合的元素个数
  • add 增加一个新的元素,返回当前集合
  • delete 删除元素,返回boolean值
  • has 检测集合中是否包含某个元素,返回boolean值
  • clear 清空

2.13.1. 使用

//声明一个集合
let s = new Set()
let s2 = new Set(['A','B','C','D','A'])
//元素个数
console.log(s2.size) //4
//添加元素
s2.add('N')  //'A','B','C','D','N'
//删除元素
s2.delete('D') //'A','B','C','N'
//检测
s2.has('M') //false
//清空
s2.clear()
console.log(s2)

for(let v of s2){
    console.log(v)
}

2.13.2. 集合实践

let arr = [1,2,1,3,4,5,4,6,4,0,7,8,9]
//1、数组去重
let res = [...new Set(arr)]
console.log(res)
//2、交集
let arr2 = [4,4,3,1,2]
let res2 = [...new Set(arr)].filter(item => {
    let s2 = new Set(arr2)
    if(s2.has(item)){
       return true
    }else{
        return false
    }
})
let res3 = [...new Set(arr)].filter(item => new Set(arr2).has(item))
console.log(res3)
//并集
let union = [...new Set([...arr,...arr2])]
//差集
let diff = [...new Set(arr)].filter(item =>!(new Set(arr2).has(item)))

2.14. Map

类似于对象,键值对集合。键的范围不限于字符串,各种类型的值(包括对象)都可以当作键,Map也实现了iterator接口,可以使用扩展运算符for..of..进行遍历。

  • Map对象保存键值对,按键的原始插入顺序,任何值都可以作为一个键或一个值
  • 计算一个Map的条目数量,使用Map.prototype.size,不用length
  • Map.prototype.clear()移出Map对象所有的键值对
  • Map.prototype.get(key)返回键对应的值
  • Map.prototype.has(key)判断是否包含键对应的值
  • Map.prototype.set(key,value)设置Map对象中键的值
  • Map.prototype.keys()获取Map对象中所有的键
  • Map.prototype.values()获取Map对象中所有的值
  • Map.prototype.forEach(callback)为Map对象中的每一个键值对调用一次callback函数
  • Map.prototype.entries()包含Map对象中每个元素的key和value数组
//声明
let m = new Map()
//添加元素
m.set('name','phy')
m.set('change',function(){
	console.log("你会变得更好!")
})
let key = {
    province:'CHANGSHA'
}
m.set(key,['橘子洲','五一广场','坡子街','国金中心'])

//输出长度
console.log(m.size)
//删除
m.delete('name')
//获取
console.log(m.get('change'))
//清空
m.clear()
//遍历,输出数组键值
for(let v of m){
    console.log(v)
}

2.15. class类

通过class关键字,可以定义类。基本上ES6的class可以看作只是一个语法糖,绝大部分功能,ES5可以实现,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。

  • class声明类
  • constructor定义构造函数初始化
  • extends继承父类
  • super调用父级构造方法
  • static定义静态方法和属性
  • 父类方法可以重写

2.15.1. 基本使用

// ES5
function Phone(brand, price) {
    this.brand = brand
    this.price = price
}
//add method
Phone.prototype.call = function () {
    console.log("i can make a phone call")
}
//实例化对象
let xm = new Phone('小米',3999)
xm.call()
console.log(xm)

//ES6
class Phone{
    // 构造方法 名字不能修改
    constructor(brand,price){
        this.brand = brand
        this.price = price
    }
    // 方法必须使用‘函数名()’的形式,不能使用ES5的对象完整形式
    call(){
        console.log('i can make a phone call')
    }
}
let xm = new Phone('xiaomi',3299)
xm.call()
console.log(xm)

2.15.2. 类的静态成员

//属于类不属于实例对象
//es5
class Phone{}
Phone.name = 'phone'
Phone.change = function(){
    console.log('i can change the world')
}
Phone.prototype.size = '5.5inch'
let xm = new Phone()
console.log(xm.name) //undefined
console.log(xm.size) //5.5inch
//es6
class Phone{
    static name = 'phone'
	static change(){
		console.log("i can change the world")
    }
}
let xm = new Phone()
console.log(xm.name) //undefined
console.log(Phone.name) //phone

2.15.3. 对象继承

//es5
// 父类
function Phone(brand, price) {
    this.brand = brand
    this.price = price
}
Phone.prototype.call = function () {
    console.log('i can make a phone call')
}
//  智能手机
function SmartPhone(brand, price, color, size) {
    Phone.call(this, brand, price)
    this.color = color
    this.size = size
}
// 设置子级构造函数的原型
SmartPhone.prototype = new Phone
SmartPhone.prototype.constructor = SmartPhone
//声明子类的方法
SmartPhone.prototype.photo = function () {
    console.log('take phone')
}
SmartPhone.prototype.play = function () {
    console.log('play game')
}
const xm = new SmartPhone('xiaomi', 3299, 'black', '5.6inch')
console.log(xm)

//es6
class Phone{
    constructor(brand,price){
        this.brand = brand
        this.price = price
    }
    call(){
        console.log("i can make a phone call")
    }
}

class SmartPhone extends Phone{
    constructor(brand,price,color,size){
        super(brand,price)
        this.color = color
        this.size = size
    }
    photo(){
        console.log("take photo")
    }
    play(){
        console.log('play game')
    }
    //重写 不能调用父类同名的方法
    call(){
        console.log('i can video call')
    }
}
const xm = new SmartPhone('xiaomi',3499,'red','6.5inch')
console.log(xm)
xm.photo()
xm.call()

2.15.4. set-get

class Phone{
    get price(){
        console.log("价格属性被读取了")
        return 'a'
    }
    set price(newVal){
        console.log("价格属性被修改了")
    }
}
// 实例化对象
let s = new Phone()
s.price
s.price = 'free'

2.16. 数值扩展

// 0.Number.EPSILON是Javascript表示的最小精度
// EPSILON属性的值接近于2.22-16
console.log(0.1 + 0.2 === 0.3) //false
function equal(a, b) {
    if (Math.abs(a - b) < Number.EPSILON)
        return true
    else
        return false
}
console.log(0.1 + 0.2 === 0.3) //false
console.log(equal(0.1 + 0.2, 0.3)) //true

//1.二进制和八进制
let b = 0b1010 //二进制
let o = 0o777 //八进制
let d = 100 //十进制
let x = 0xff //十六进制
console.log(b,o,d,x)

//2、Number.isFinite 检测一个数值是否为有限
console.log(Number.isFinite(100)) //true
console.log(Number.isFinite(100/0)) //false
console.log(Number.isFinite(Infinity)) //false

//3、Number.isNaN 检测一个数值是否为NaN
console.log(Number.isNaN(123))

// 4、Number.parseInt Number.parseFloat字符串转整数
console.log(Number.parseInt('19328djd')) //19328
console.log(Number.parseFloat('3.1415926jsiodj')) //3.1415926

// 5、Number.isInteger判断一个数是否为整数
console.log(Number.isInteger(5))//true
console.log(Number.isInteger(5.5)) //false

//6、Math.trunc将数字的小数部分抹掉
console.log(Math.trunc(3.5)) //3

//7、Math.sign判断一个数是正数、负数、0
console.log(Math.sign(100)) //1
console.log(Math.sign(0)) //0
console.log(Math.sign(-100)) //-1

2.17. 对象扩展

//1、Object.is 判断两个数是否完全相等
console.log(Object.is(12,12))//true
console.log(Object.is(NaN,NaN))//true
console.log(NaN===NaN)//false
//2、Object.assign 对象的合并
const obj1 = {
    name: 'phy',
    age: 18
}
const obj2 = {
    name: 'Tom'
}
//两个对象中相同元素会被覆盖
console.log(Object.assign(obj1,obj2)) //{name:"Tom",age:18}
//3、Object.setPrototypeOf设置原型对象 Object.getPrototypeOf
const area = {
    name: 'China'
}
const cities = {
    province:['chnagsha','beijing','shanghai']
}
Object.setPrototypeOf(area,cities)
console.log(Object.getPrototypeOf(area))
console.log(school)

2.18. 模块化

模块化是指将一个大的程序文件,拆分为许多小的文件,将小文件组合起来。

模块化的优势

  • 防止命名冲突
  • 代码复用
  • 高维护性

模块化规范产品

  • CommonJS => NodeJS,Browserify
  • AMD => requireJS
  • CMD => seaJS

ES6模块化语法

模块功能主要由两个命令构成:export和import

  • export命令用于规定模块的对外接口
  • import命令用于输入其他模块提供的功能

使用

方法一:


m.js

//分别暴露
export let name = 'phy'
export function moody(){
  console.log("unhappy,today is terrible")
}
//统一暴露
export {name,moody}
//默认暴露
export default{
    change: function(){
		console.log('we will change you')
    }
}

方法二:

app.js

import * as m from './m.js'

html


Babel

将es6语法转换成es5浏览器可以识别的JavaScript

  1. 安装工具 babel-cli(命令行工具) babel-preset-env(转换工具) browserify(打包工具)

    npm i babel-cli babel-preset-env browserify -D

  2. npm babel 源文件目录src/js -d 保存至文件目录dist/js

  3. 打包 npx browserify dist/js/app.js -o dist/bundle.js

  4. 问题

    babel & browserify 报错 'import' and 'export' may appear only with 'sourceType: module'

    新建.babelrc文件

    {
      "presets": ["es2015","stage-0"]
    }
    

    安装

    cnpm i -D babel-preset-stage-0
    #使用
    #转换
    npx babel js -d dist/js --presets-babel-preset-env
    #打包
    npx browserify dist/js/app.js -o dist/bundle.js
    

ES6中模块引入NPM包

  • 安装npm i jquery -S
  • 转换npx babel js -d dist/js --presets-babel-preset-env
  • 打包npx browserify dist/js/app.js -o dist/bundle.js
  • 浏览器打开html文件即可

app.js

import * as m from './m.js'
import $ from 'jquery'
$('body').css('background','pink')
m.moody()
console.log(m.name)

m.js

export let name = 'phy'
export function moody(){
  console.log("unhappy,today is terrible")
}

index.html