ES6 课堂笔记

ES6

第一章 ECMASript 相关介绍

1.1 什么是 ECMA

ECMA(European Computer Manufacturers Association)中文名称为欧洲计算机制造商协会,这个组织的目标是评估、开发和认可电信和计算机标准。1994 年后该组织改名为 Ecma 国际。

1.2 什么是 ECMAScript

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

1.3 为什么要学习 ES6

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

1.4 ES6 兼容性

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

第二章 ECMAScript 6 新特性

2.1 let 关键字

特性
  • 变量不能重复声明
  • 块儿级作用域
  • 不存在变量提升(不允许在变量声明之前使用变量)
  • 不影响作用域链
应用场景

​ 以后声明变量使用 let 就对了

2.2 const 关键字

特性
  • 声明必须赋初始值
  • 标识符一般为大写
  • 不允许重复声明
  • 值不允许修改
  • 块儿级作用域
注意

​ 对象属性修改和数组元素变化不会出发 const 错误

应用场景

​ 声明对象类型使用 const,非对象类型声明选择 let

2.3 变量的解构赋值

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

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

//对象的解构赋值
const lin = {
    name: '林志颖',
    tags: ['车手', '歌手', '小旋风', '演员'],
    changge: function () {
        console.log('我可以唱歌');
    }
};
let {name, tags} = lin;
console.log(name); // 林志颖
let {cahngge} = lin;
changge(); // 我可以唱歌

2.4 模板字符串

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

特性
  • 字符串中可以出现换行符
  • 可以使用 ${xxx} 的输出变量

2.5 简化对象写法

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

let name = '尚硅谷';
let slogon = '永远追求行业更高标准';
let improve = function () {
    console.log('可以提高你的技能');
}
//属性和方法简写
let atguigu = {
    name,
    slogon,
    improve,
    change() {
        console.log('可以改变你')
    }
};

2.6 箭头函数

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

ES6 允许给函数参数赋初始值

  • 具有默认值的参数,一般靠后
  • 可以与解构赋值结合
注意点
  • 如果形参只有一个,则小括号可以省略
  • 函数体如果只有一条语句,则花括号可以省略,此时 return 必须省略,而且函数的返回值为该条语句的执行结果
  • 箭头函数 this 是静态的,始终指向声明时所在作用域下 this 的值
  • 箭头函数不能作为构造函数实例化
  • 不能使用 arguments
// 通用写法
let fn = (arg1, arg2, arg3) => {
    return arg1 + arg2 + arg3;
}
// 省略花括号的情况
let fn3 = score => score * 20;
应用场景

适合与 this 无关的回调 定时器、数组的方法回调

不适合与 this 有关的回调 事件回调、对象的方法

2.7 rest 参数

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

  • ...args
  • rest参数必须要放到最后
/**
* 作用与 arguments 类似
*/
function add(...args){
    console.log(args); // [1,2,3,4,5]
}
add(1,2,3,4,5);
/**
* rest 参数必须是最后一个形参
*/
function minus(a,b,...args){
    console.log(a);		// 100
    console.log(b);		// 1
    console.log(args);	// [2,3,4,5,19]
}
minus(100,1,2,3,4,5,19);
应用场景

rest 参数非常适合不定个数参数函数的场景

2.8 spread 运算符

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

应用
  1. 数组的合并

    const arr1 = [1, 2];
    const arr2 = [3, 4];
    // const hebing = arr1.concat(arr2); 原先api函数
    const hebing = [...arr1, ...arr2]
    
  2. 数组的克隆

    const arr1 = [1, 2];
    // 注意是 浅克隆
    const hebing = [...arr1,]
    
  3. 将伪数组转为真正的数组

    const divs = document.querySelectAll('div'); // 伪数组
    const divArr = [...divs]
    

2.9 Symbol

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

特点
  • Symbol 的值是唯一的,用来解决命名冲突的问题
  • Symbol 值不能与其他数据进行运算
  • Symbol 定义的 对象属性 不能使用 for…in 循环遍历 ,但是可以 使用 Reflect.ownKeys 来获取对象的所有键名
// 创建 Symbol
let s = Symbol();
console.log(s, typeof s); // Symbol() "symbol"
let s2 = Symbol('张艺兴'); // 注释作用
let s3 = Symbol('张艺兴');
console.log(s2 === s3); // false
// Symbol.for 创建
let s4 = Symbol.for('张艺兴');
let s5 = Symbol.for('张艺兴');
console.log(s4, typeof s4); // Symbol(张艺兴) "symbol"
console.log(s4 === s5); // true

Symbol['say']: function () {}

内置值

JS 数据类型总结

USONB (you are so niubility)

  • u : undefined
  • s : string Symbol
  • o : object
  • n : null number
  • b : boolean

2.10 迭代器

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

  • ES6 创造了一种新的遍历命令 for…of 循环,Iterator 接口主要供 for…of 消费

    // 声明一个数组
    const xiyou = ['1', '2', '3', '4'];
    
    // 使用 for...of 遍历数组
    for (const v of xiyou) {
        console.log(v);
    }
    
  • 原生具备 iterator 接口的数据(可用 for of 遍历)

  • Array

  • Arguments

  • Set

  • Map

  • String

  • TypedArray

  • NodeList

  • 工作原理

    • 创建一个指针对象,指向当前数据结构的起始位置
    • 第一次调用对象的 next 方法,指针自动指向数据结构的第一个成员
    • 接下来不断调用 next 方法,指针一直往后移动,直到指向最后一个成员
    • 每调用 next 方法返回一个包含 value 和 done 属性的对象
    let iterator = xiyou[Symbol.iterator]();
    
    // 调用对象的 next 方法
    console.log(iterator.next());
    console.log(iterator.next());
    console.log(iterator.next());
    console.log(iterator.next());
    console.log(iterator.next());
    

    运行结果:
    ES6 课堂笔记_第1张图片

应用场景

需要自定义遍历数据的时候,要想到迭代器。

自定义遍历对象
// 声明一个对象
const banji = {
    name: '终极一班',
    stus: [
        'xiaoming',
        'xiaoning',
        'xiaotian',
        'knight'
    ],
    [Symbol.iterator]() {
        // 索引变量
        let index = 0;
        let _this = this;
        return {
            next: function () {
                if (index < _this.stus.length) {
                    const result = {value: _this.stus[index], done: false}
                    // 下表自增
                    index++;
                    // 返回结果
                    return result
                } else {
                    return {value: undefined, done: true}
                }
            }
        }
    }
}

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

2.11 生成器

生成器函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同,起其实就是一个特殊的函数。

// yield 函数代码的分隔符
function * gen() {
    // console.log(111);
    yield '一只没有耳朵';
    // console.log(222);
    yield '一只没有尾巴';
    // console.log(333);
    yield '真奇怪';
    // console.log(444);
}

let iterator = gen();
// 调用 next() 方法才会执行方法
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());

for (const v of gen()) {
    console.log(v);
}

运行截图:
ES6 课堂笔记_第2张图片

生成器函数参数
function * gen(arg) {
    console.log(arg);
    let one = yield '一只没有耳朵';
    console.log(one);
    let two = yield '一只没有尾巴';
    console.log(two);
    let three = yield '真奇怪';
    console.log(three);
}

let iterator = gen('AAA');
// 调用 next() 方法才会执行方法
console.log(iterator.next());
console.log(iterator.next('BBB'));
console.log(iterator.next('CCC'));
console.log(iterator.next('DDD'));

运行截图:
ES6 课堂笔记_第3张图片

实例

2.12 Promise

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

Promise 构造方法

const promise = new Promise(function(resolve, reject) {}

// 实例化 Promise 对象
const p = new Promise(function(resolve, reject) {
    setTimeout(function () {
        // let data = '数据库中的用户数据'
        // resolve(data); // 调用 then 中第一个方法

        let err = '数据读取失败';
        reject(err); // 调用 then 中第二个方法
    }, 1000);
});

// 调用 Promise 对象的 then 方法
p.then(function (value) {
    console.log(value); // 数据库中的用户数据
}, function (reason) {
    console.log(reason); // 数据读取失败
})
Promise 读取文件
// 引入 fs 模块
const fs = require('fs');

const p = new Promise(function (resolve, reject) {
    fs.readFile('./resources/为学.md', 'utf8', (err, data) => {
        if (err) reject(err);
        // 如果成功
        resolve(data);
    })
})

p.then(function (value) {
    console.log(value);
}, function (reason) {
    console.log('读取失败');
})
Promise 封装 AJAX
// 接口地址 http://api.apiopen.top/getJoke

const p = new Promise(function (resolve, reject) {
    // 1. 创建对象
    const xhr = new XMLHttpRequest();

    // 2. 初始化
    xhr.open('GET', 'https://api.apiopen.top/getJoke');

    // 3. 发送
    xhr.send();

    // 4. 绑定事件,处理响应结果
    xhr.onreadystatechange = function () {
        if (xhr.readyState === 4) {
            if (xhr.status >= 200 && xhr.status < 300) {
                resolve(xhr.response)
            } else {
                reject()
            }
        }
    }
})

// 指定回调
p.then(function (value) {
    console.log(value);
}, function (reason) {
    console.log('获取失败');
})
Promise.prototype.then
// 创建 promise 对象
const p = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('用户数据');
        // reject('出错啦');
    }, 1000);
});

// 调用 then 方法  then方法的返回结果是 Promise 对象,对象状态又回调函数的执行结果决定
// 1. 如果回调函数中返回的结果是一个 非Promise 类型的数据,状态为成功,返回值为对象那个的成功值
const result = p.then(value => {
    console.log(value);
    // 1. 非 Promise 类型的数据
    // return 123;
    // 2. 是 Promise 对象
    // return new Promise((resolve, reject) => {
    //   // resolve('ok');
    //   reject('出错')
    // })
    // 3. 抛出错误
    // throw new Error('出错啦')
}, reason => {
    console.warn(reason);
});
console.log(result);
链式调用
// 链式调用 可以避免回调地狱的形成
p.then(value=>{

},reason=>{

}).then(value=>{

})

另外,then 方法中的两个方法 不一定需要全有

案例-读取多个文件
// 引入 fs 模块
const fs = require('fs');

// 之前的方法 - 回调地狱
// fs.readFile('./resources/为学.md', 'utf8', (err, data1) => {
//   fs.readFile('./resources/插秧诗.md', 'utf8', (err, data2) => {
//     fs.readFile('./resources/观书有感.md', 'utf8', (err, data3) => {
//       let result = data1 + '\r\n' + data2 + '\r\n' + data3;
//       console.log(result);
//     })
//   })
// })

// 使用 Promise 实现
const p = new Promise((resolve, reject) => {
    fs.readFile('./resources/为学.md', 'utf8', (err, data) => {
        resolve(data);
    })
})

p.then(value => {
    return new Promise((resolve, reject) => {
        fs.readFile('./resources/插秧诗.md', 'utf8', (err, data) => {
            resolve([value, data]);
        })
    })
}).then(value => {
    return new Promise((resolve, reject) => {
        fs.readFile('./resources/观书有感.md', 'utf8', (err, data) => {
            value.push(data);
            resolve(value);
        })
    })
}).then(value => {
    console.log(value.join('\r\n'));
})
Promise catch 方法

不用不影响开发,catch 的作用只是简化,可以只写后面错误的函数,不需要写前面的。

const p = new Promise((resolve, reject) => {
    setTimeout(() => {
        // 设置 p 对象的状态为失败,并设置失败的值
        reject('出错啦!')
    }, 1000);
})

p.then(value => {}, reason => {
    console.error(reason);
})

p.catch(reason => {
    console.warn(reason);
})

2.13 Set

ES6 提供了新的数据结构 Set(集合)。

它类似于数组,但成员的值都是唯一的,集合实现了 iterator 接口,所以可以使用『扩展运算符』和『for…of…』进行遍历。

属性&方法
  • size 返回集合的元素个数
  • add 增加一个新元素,返回当前集合
  • delete 删除元素,返回 boolean 值
  • has 检测集合中是否包含某个元素,返回 boolean 值
  • clear 清空集合,返回 undefined
// 声明一个 Set
let s = new Set();
let s2 = new Set(['大事儿', '小事儿', '好事儿', '坏事儿', '小事儿']);
console.log(s, typeof s);
console.log(s2); // 自动去重 {"大事儿", "小事儿", "好事儿", "坏事儿"}

// 元素的个数
console.log(s2.size); // 4
// 添加新的元素
s2.add('喜事儿');
console.log(s2); // {"大事儿", "小事儿", "好事儿", "坏事儿", "喜事儿"}
// 删除元素
s2.delete('坏事儿');
console.log(s2); // {"大事儿", "小事儿", "好事儿", "喜事儿"}
// 检测
console.log(s2.has('好事儿')); // true
// 清空
s2.clear();
console.log(s2); // {}

// 也可实现 for...of 遍历
for (const v of s2) {
    console.log(v);
}
Set 集合实践
var arr = [1,2,3,4,5,4,3,2,1];
// 1. 数组去重
// let result = [...new Set(arr)];
// console.log(result);
// 2. 交集
let arr2 = [4,5,6,5,6];
// let result = [...new Set(arr)].filter(item => {
//   let s2 = new Set(arr2);
//   if (s2.has(item)) {
//     return true;
//   } else {
//     return false;
//   }
// })
// 简化
let result = [...new Set(arr)].filter(item => new Set(arr2).has(item))
console.log(result); // [4, 5]

// 3. 并集
let union = [...new Set([...arr, ...arr2])]
console.log(union);  // [1, 2, 3, 4, 5, 6]

// 4. 差集
let diff = [...new Set(arr)].filter(item => !(new Set(arr2).has(item)))
console.log(diff);   // [1, 2, 3]

2.14 Map

ES6 提供了 Map 数据结构。它类似于对象,也是键值对的集合。但是“键”
的范围不限于字符串,各种类型的值(包括对象)都可以当作键。Map 也实现了iterator 接口,所以可以使用『扩展运算符』和『for…of…』进行遍历。

属性&方法
  • size 返回 Map 的元素个数
  • add 增加一个新元素,返回当前 Map
  • get 返回键名对象的键值
  • has 检测 Map 中是否包含某个元素,返回 boolean 值
  • clear 清空集合,返回 undefined
// 声明 Map
let m = new Map();

// 添加元素
m.set('name', '张艺兴')
m.set('change', function () {
    console.log('张艺兴是最帅的');
})
let key = {
    school : 'AgoniLay'
}
m.set(key, ['北京', '上海', '深圳'])

// size
console.log(m.size); // 3

// 删除
m.delete('name')

// 获取
// console.log(m.get('change'));
console.log(m.get(key)); // ["北京", "上海", "深圳"]

// 清空
// m.clear();

// 遍历
for (const v of m) {
    console.log(v);
}

console.log(m);

2.15 Class 类

ES6 提供了更接近传统语言的写法,引入了 Class(类)这个概念,作为对
象的模板。通过 class 关键字,可以定义类。基本上,ES6 的 class 可以看作只是一个语法糖,它的绝大部分功能,ES5 都可以做到,新的 class 写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。

知识点
  • class 声明类
  • constructor 定义构造函数初始化
  • extends 继承父类
  • super 调用父级构造方法
  • static 定义静态方法和属性
  • 父类方法可以重写
ES5 方法
// ES5
// 手机
function Phone(brand, price) {
    this.brand = brand;
    this.price = price;
}

// 添加方法
Phone.prototype.call = function () {
    console.log('我可以打电话');
}

// 实例化对象
let huawei = new Phone('华为', 5999);

console.log(huawei);
// huawei.call();
ES6 class
class Shouji {
    // 构造方法 名字不能修改
    constructor (brand, price) {
        this.brand = brand;
        this.price = price;
    }

    // 方法必须使用该语法,不能使用 ES5 的对象完整形式
    call () {
        console.log('我可以打电话');
    }
}

let onePlus = new Shouji('1+', 1999);
console.log(onePlus);
静态成员
class Phone {
    // 静态属性
    static name = '手机';
static change = function () {
    console.log('我可以改变世界');
};
}

let nokia = new Phone();
console.log(nokia.name); // undefined
console.log(Phone.name); // 手机
类继承
class Phone {
    // 构造方法
    constructor (brand, price) {
        this.brand = brand;
        this.price = price;
    }

    // 父类的成员属性
    call () {
        console.log('我可以打电话');
    }
}

class SmartPhone extends Phone {
    // 构造方法
    constructor (brand, price, color, size) {
        super(brand, price);
        this.color = color;
        this.size = size;
    }

    photo () {
        console.log('拍照');
    }

    playGame () {
        console.log('打游戏');
    }
}

const xiaomi = new SmartPhone('小米', 799, '黑色', '4.7inch');
console.log(xiaomi);
xiaomi.call();
xiaomi.photo();
xiaomi.playGame();

子类可以进行对父类方法的重写

注:但是不能通过super()调用父类重名方法

set 和 get

获取时,触发 get 方法

修改赋值时,触发 set 方法

注:set 方法必须有一个参数

class Phone {
    get price () {
        console.log('价格属性被读取了');
        return 111
    }

    set price (newV) {
        console.log('价格属性被修改了');
    }
}

// 实例化对象
let s = new Phone();
console.log(s.price); // 111	// 触发 get
s.price = 'free';				// 触发 set

2.16 数值扩展

Number.EPSILON

Number.EPSILON 是 JavaScript 表示的最小精度 ε

EPSILON属性的值接近于:2.2204460492503130808472633361816E-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(equal(0.1 + 0.2, 0.3));	// true
二进制和八进制

ES6 提供了二进制和八进制数值的新的写法,分别用前缀 0b 和 0o 表示。

let b = 0b1010;		// 二进制
let b = 0o777;		// 八进制

let d = 100;		// 十进制
let x = 0xff;		// 十六进制
Number.isFinite()

用来检查一个数值是否为有限的,返回 boolean

Number.isNaN()

用来检查一个值是否为 NaN,返回 boolean

Number.parseInt() & Number.parseFloat()

移植到了 Number 对象下,使用不变,(截取整数,截取浮点数)

Number.isInteger()

用来判断一个数值是否为整数, 返回 boolean

Math.trunc()

将数字的小数部分抹掉

Math.sign()

判断一个数是 正数(1) 负数(-1) 还是 0(0) 括号内为相应的返回值

2.17 对象方法

Object.is(a,b)

判断两个值是否完全相等

与全等号 === 区别:

console.log(Object.is(NaN, NaN)); // true
console.log(NaN === NaN); 		  // false
Object.assign(a,b)

对象的合并,后面的将前面的覆盖掉

可以用于更新对象

const config1 = {
    host: 'localhost',
    prot: 3306,
    name: 'root',
    pass: 'root',
    test: 'test'
}
const config2 = {
    host: 'http://www.baidu.com',
    prot: 33060,
    name: 'AgoniLay',
    pass: '020316'
}

console.log(Object.assign(config1, config2));
/*
	host: "http://www.baidu.com"
    name: "AgoniLay"
    pass: "020316"
    prot: 33060
    test: "test"
*/
Object.setPrototypeof & Object.getPrototypeof

设置原型对象,一般不使用

console.log(Object.assign(config1, config2));
// Object.setPrototypeof  Object.getPrototypeof
const school = {
    name: '张艺兴'
}
const cities = {
    xiaoqu: ['北京', '上海', '深圳']
}

Object.setPrototypeOf(school, cities)
console.log(Object.getPrototypeOf(school));
console.log(school);

2.18 模块化

概述

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

好处
  • 防止命名冲突
  • 代码复用
  • 高维护性
语法

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

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

模块化规范

浏览器端
  1. AMD:Request.js (http://www.requirejs.cn/)
  2. CMD:Sea.js (https://seajs.github.io/seajs/docs/)
服务器端
  • CommonJS:NodeJS
    1. 模块分为 单文件模块 与 包
    2. 模块成员导出:module.exports 和 exports
    3. 模块成员导入:require(‘模块标识符’)

2.19 大一统的模块化规范 - ES6模块化

是 浏览器端 与 服务器端 通用的模块化开发规范

  • 每一个 js 文件都是一个独立的模块
  • 导入模块成员使用 import 关键字
  • 暴露模块成员使用 export 关键字

Node.js 中 babel 体验 ES6 模块化

步骤
  1. 安装工具

    npm install --save-dev @babel/core @babel/cli @babel/preset-env @babel/node
    
    npm install --save @babel/polyfill
    
  2. 根目录下新建 babel.config.js 文件 写入:

    const presets = [
        ["@babel/env", {
            targets: {
                edge: "17",
                firefox: "60",
                chrome: "67",
                safari: "11.1"
            }
        }]
    ]
    
    module.exports = { presets }
    
  3. 执行代码

    npx babel-node index.js
    

基本语法

默认导出 与 默认导入
  • 默认导出:export default 默认导出的成员
  • 默认导入:import 接收名称 from '模块标识符/路径'

注意点:

  1. 在每个模块中,只允许使用唯一的一次 export default,否则会报错
  2. 在模块中如果没有默认导出,那么将会 是一个空对象 {}
按需导出 与 按需导入
  • 按需导出:export let s1 = 10
  • 按需导入:import { s1 } from '模块标识符/路径'

注意点:

  1. 在一个模块中,可以使用多次按需导出
直接导入并执行模块代码

import '模块标识符/路径'

直接执行代码,没有导出。

2.20 webpack

当前 Web开发 面临的困境:

  • 文件以来关系错综复杂
  • 静态资源请求效率低
  • 模块化支持不友好
  • 浏览器对高级 JavaScript 特性兼容程度较低

webpack 概述

webpack 是一个流行的前端项目构建工具(打包工具),可以解决当前 web 开发中所面临的困境。

提供了友好的模块化支持,以及代码压缩混淆处理 js 兼容问题性能优化等强大的功能,提高了开发效率和项目的可维护性。

基本使用

1.创建列表隔行变色项目
  1. 创建项目空白目录,并运行 npm init -y 命令,进行初始化包管理配置文件 package.json
  2. 新建 src 源代码目录
  3. 新建 src -> index.html 首页
  4. 初始化首页基本结构
  5. 运行 npm install jquery -S 命令, 安装 jQuery
  6. 通过模块化的形式,实现列表隔行变色效果
2. 在项目中安装和配置 webpack
  1. 运行 npm insatll webpack webpack-cli -D 命令,安装 webpack 相关的包

  2. 在项目根目录中,创建名为 webpack.config.js 的 webpack 配置文件

  3. 在 webpack 的配置文件中,初始化如下基本配置:

    module.exports = {
    	mode: 'development' // mode 用来指定构建模式
    }
    

    注意:开发阶段 mode 值一般设置为 development ,上线时才设置成 production (会进行压缩与混淆,转换时间会更长)

  4. 在 package.json 配置文件中的 scripts 节点下,新增 dev 脚本如下:

    "scripts": {
        "dev": "webpack" // script 节点下的脚本,可以通过 npm run 执行
    }
    
  5. 在终端中运行 npm run dev 命令,启动 webpack 进行项目打包。

注意:主页面中导入的应该为打包生成后的 dist 文件夹下的 js 文件

3. 配置打包的入口和出口

webpack 的 4.x 版本中默认约定:

  • 打包的 入口文件 为 src -> index.js
  • 打包的 输出文件 为 dist -> main.js

修改打包的入口(entry)和出口(output),可以在 webpack.config.js 中增加如下配置:

const path = require('path')

module.exports = {
    entry: path.join(__dirname, './src/index.js'), // 打包入口文件的路径
    output: {
        path: path.join(__dirname, './dist'), // 输出文件的存放路径
        filename: 'bundle.js' // 输出文件的名称
    }
}
4. 配置 webpack 的自动打包功能
  1. 运行 npm install webpack-dev-server -D 命令,安装支持项目自动打包的工具

  2. 修改 package.json -> scripts 中的 dev 命令如下:

    "scripts": {
        "dev": "webpack server"
    },
    
  3. 将 src -> index.html 中,script 脚本的引用路径,修改为 “/bundle.js”

  4. 运行 npm run dev 命令,重新进行打包

  5. 在浏览器中访问 http://localhost:8080 地址,查看自动打包效果。

5. 配置 html-webpack-plugin 生成预览页面
  1. 运行 npm install html-webpack-plugin -D 命令,安装生成预览页面的插件

  2. 修改 webpack.config.js 文件头部区域,添加如下配置信息:

    const HtmlWebpackPlugin = require('html-webpack-plugin')
    
    const htmlPlugin = new HtmlWebpackPlugin({
        template: './src/index.html',
        filename: 'index.html'
    })
    
  3. 修改 webpack.config.js 文件中向外暴露的配置对象,新增如下配置节点:

    module.exports = {
        plugins: [ htmlPlugin ] // plugins 数组时 webpack 打包期间会用到的一些插件列表
    }
    
6. 配置自动打包相关的参数
  • –open 打包完成自动打开浏览器页面
  • –host 配置 IP 地址
  • –port 配置端口
"scripts": {
    "dev": "webpack server --open --host 127.0.0.1 --port 8080"
},

webpack 中的加载器

报错解决

控制台报错:

DevTools failed to load SourceMap: Could not load content for webpack:///node_modules/sockjs-client/

解决:

webpack.config.js 中配置一项

module.exports = {
    devtool: 'inline-source-map'
}
通过 loader 打包非 js 模块
  • less-loader 可以打包处理 .less 相关的文件
  • sass-loader 可以打包处理 .scss 相关的文件
  • url-loader 可以打包处理 css 中与 url 路径相关的文件
基本使用
1. 打包处理 css 文件
  1. 运行 npm install style-loader css-loader -D 命令,安装处理 css 文件的 loader

  2. 在 webpack.config.js 的 module -> rules 数组中,添加 loader 规则如下:

    module: {
        rules: [
            {test: /\.css$/, use: ['style-loader', 'css-loader']}
        ]
    }
    

    其中,test 表示匹配的文件类型,use 表示对应要调用的 loader

注意:

  • use 数组中指定的 loader 顺序是固定的
  • 多个 loader 的调用顺序是:从后往前调用
2. 打包处理 less 文件
  1. 运行 npm i less-loader less -D 命令,

  2. 在 webpack.config.js 的 modeule -> rules 数组中,添加 loader 规则如下:

    module: {
        rules: [
            {test: /\.less$/, use: ['style-loader', 'css-loader', 'less-loader']}
        ]
    }
    
3. 打包处理 scss 文件
  1. 运行 npm i sass-loader node-sass -D 命令,

    运行不通使用:

    1. 首先删除 node_modules 中的 sass-loader 和 node-sass 目录

    2. 配置淘宝镜像

      npm install -g cnpm --registry=https://registry.npm.taobao.org

    3. 用 cnpm 重新安装一次
      cnpm install node-sass -D
      cnpm install sass-loader -D

  2. 在 webpack.config.js 的 modeule -> rules 数组中,添加 loader 规则如下:

    module: {
        rules: [
            {test: /\.scss$/, use: ['style-loader', 'css-loader', 'sass-loader']}
        ]
    }
    
4. 配置 postCSS 自动添加 css 的兼容前缀
  1. 运行 npm i postcss-loader autoprefixer -D 命令,

  2. 在项目根目录中创建 postcss 的配置文件 postcss.config.js,并初始化如下配置:

    // 导入自动添加前缀的插件
    const autoprefixer = require('autoprefixer')
    
    module.exports = {
        plugins: [ autoprefixer ] // 挂载插件
    }
    
  3. 在 webpack.config.js 的 modeule -> rules 数组中,修改 css 的 loader 规则如下:

    module: {
        rules: [
            {test: /\.css$/, use: ['style-loader', 'css-loader', 'postcss-loader']}
        ]
    }
    
5. 打包样式表中的图片和字体文件
  1. 运行 npm i url-loader file-loader -D 命令,

  2. 在 webpack.config.js 的 modeule -> rules 数组中,添加 loader 规则如下:

    module: {
        rules: [
            { test: /\.jpg|png|gif|bmp|ttf|eot|svg|woff|woff2$/, use: 'url-loader?limit=32417' },
        ]
    }
    

    注:? 后 limit参数是文件的大小(单位是字节),小于此大小 才会编译为 base64 格式

6. 打包处理 js 文件中的高级语法
  1. 运行

    npm i babel-loader @babel/core @babel/runtime -D
    

    命令,安装 babel 转换器相关的包

  2. 运行

    npm i @babel/preset-env @babel/plugin-transform-runtime @babel/plugin-proposal-class-properties -D
    

    命令,安装babel语法插件相关的包

  3. 在项目根目录下,创建 babel 配置文件 babel.config.js 并初始化基本配置如下:

    module.exports = {
      presets: ['@babel/env'],
      plugins: ['@babel/plugin-transform-rutime', '@babel/plugin-proposal-class-properties']
    }
    
  4. 在 webpack.config.js 的 modeule -> rules 数组中,添加 loader 规则如下:

    // exclude 为排除项,表示 babel-loader 不需要处理 node_modules 中的 js 文件
    module: {
        rules: [
            { test: /\.js$/, use: 'babel-loader', exclude: /node_modules/ }
        ]
    }
    

    npm 安装不了,就用 cnpm 安装

7. 配置 vue 组件的加载器
  1. 运行 npm i vue-loader vue-template-compiler -D 命令,

  2. 在 webpack.config.js 的 modeule -> rules 数组中,添加 loader 规则如下:

    const VueLoaderPlugin = require('vue-loader/lib/plugin')
    
    module.exports = {
        module: {
            rules: [
                { test: /\.vue$/, use: 'vue-loader' }
            ]
        },
        plugin: [
            new VueLoaderPlugin()
        ]
    }
    

webpack 中使用 Vue

  1. 运行 npm i vue -S 安装 vue
  2. 在 src -> index.js 入口文件中,通过 ipmort Vue from 'vue' 来导入 vue 构造函数
  3. 创建 vue 的实例对象,并且要控制的 el 区域
  4. 通过 render 函数渲染 App 根组件

index.js

import Vue from 'vue'
// 导入 单文件组件
import App from './components/App.vue'

const vm = new Vue({
  el: '#app',
  render: h => h(App)
})

报错处理

Error: Cannot find module ‘@babel/preset-preset.env’

解决:

将 babel.config.js 配置文件中的 preset-env ,改为 env

webpack 打包发布

上线之前需要通过 webpack 将应用进行整体打包,可以通过 package.json 文件配置打包命令:

{
    "scripts": {
        "build": "webpack"
    },
}

第三章 ES7 新特性

3.1 Array.prototype.includes

Includes 方法用来检测数组中是否包含某个元素,返回 boolean 类型值

3.2 指数运算符

在 ES7 中引入指数运算符「**」,用来实现幂运算,功能与 Math.pow 结果相同

console.log(2 ** 10); // 1024
console.log(Math.pow(2, 10)); // 1024

你可能感兴趣的:(javascript,es6,前端)