目录
5.3 Number.isFinite() 与 Number.isNaN()
5.4 Number.parseInt() 与 Number.parseFloat()
6.3 setPrototypeOf()、setPrototypeOf()
一、Promise(重要)
1.1 Promise介绍和基本使用
Promise 是 ES6 引入的异步编程的新解决方案。语法上 Promise 是一个构造函数,用来封装异步操作,并可以获取其成功或失败的结果。
- Promise 构造函数:Promise(excutor){}
- Promise.prototype.then 方法
- Promise.prototype.catch 方法
// 实例化 Promise 对象
const p = new Promise(function(resolove, reject){
setTimeout(function(){
// let data = '数据库中的用户数据';
// resolove(data);
let err = '数据读取失败';
reject(err);
});
}, 1000);
// 调用 promise 对象的 then方法
p.then(function(value){
console.log(value);
},function(reason){
console.log(reson);
})
1.2 Promise封装读取文件
// 1. 引入fs 模块
const fs = require('fs');
// 2. 一般写法 调用方法读取文件
// fs.readFile('./测试.md', (err, data) => {
// // 如果失败,则抛出错误
// if(err) throw err;
// // 如果未出错,则输出内容
// console.log(data.toString());
// });
// 3. 使用 Promse 封装
const p = new Promise(function(resolve, reject){
fs.readFile('./测试.md', (err, data)=>{
if(err) reject(err);
resolve(data);
});
});
p.then(function(value){
console.log(value.toString());
},function(reason){
console.log('读取失败');
});
1.3 Promise封装AJAX请求
可以自己创建一个服务器尝试
server.js
const express = require('express');
// 2. 创建应用对象
const app = express();
// 3. 创建路由规则
// request 是对请求报文的封装
// response 是对响应报文的封装
app.get('/server', (request,response)=>{
// 设置响应头 设置允许跨域
response.setHeader('Access-Control-Allow-Origin','*');
// 设置响应体
response.send('HELLO AJAX-2');
});
app.post('/server', (request,response)=>{
// 设置响应头 设置允许跨域
response.setHeader('Access-Control-Allow-Origin','*');
// 设置响应体
response.send('HELLO AJAX POST');
});
promise封装AJAX请求.html
<script>
const p = new Promise((resolve, reject)=>{
// 1. 创建对象
const xhr = new XMLHttpRequest();
// 2. 初始话
xhr.open('GET','http://127.0.0.1:8000/server');
// 3. 发送
xhr.send();
// 4. 绑定事件,处理响应结果
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);
});
</script>
1.4 Promise-then方法
then方法返回结果是 Promise 对象, 对象状态由调用函数的执行结果决定
首先创建Promise对象
// 创建 Promise对象
const p = new Promise((resolve, reject)=>{
setTimeout(()=>{
resolve('用户数据')
},1000);
});
1.4.1 返回的结果是 非promise 类型
调用then方法
如果调用函数中返回的结果是 非promise 类型的属性,状态为成功,返回值为对象的成功的值,且then方法返回 Promise 对象状态为成功
注意:默认值undefined 同样为非promise类型
// 调用then方法
// 如果调用函数中返回的结果是 非promise 类型的属性,状态为成功,返回值为对象的成功的值
const result = p.then(value=>{
console.log(value);
// 1. 非prominse 类型的属性,注意 默认值undefined 同样为非promise类型
return 123;
}, reason=>{
console.warn(reason);
});
console.log(result);
1.4.2 返回的结果是 Promise 对象
当返回的结果是 Promise 对象,该 Promise 对象 状态为成功,then方法返回结果的Promise 对象 返回值为 该Promise 对象的返回值,反之亦然
const result = p.then(value=>{
console.log(value);
// 2. 是promise 对象
return new Promise((resolve, reject)=>{
resolve('ok')
});
}, reason=>{
console.warn(reason);
});
console.log(result);
该Promised对象,状态为失败时,then方法返回结果的Promise 对象 与之相对应
// 2. 是promise 对象
return new Promise((resolve, reject)=>{
reject('error')
});
then方法返回的结果也为失败
1.4.3 返回结果为抛出错误
抛出错误时,then方法返回结果的Promise 对象状态也为失败
const result = p.then(value=>{
console.log(value);
// 3. 抛出错误
// throw new Error('出错啦');
throw '出错啦';
}, reason=>{
console.warn(reason);
});
console.log(result);
1.4.4 then方法的链式调用
通过链式调用改变回调地狱现象
p.then(value=>{},reason=>{}).then(value=>{},reason=>{});
1.4.5 Promise 案例练习 - 多个文件内容读取
依据 then方法的链式调用 解决回调地狱现象
传统方式
const fs = require('fs');
fs.readFile('./测试.md', (err,data1)=>{
fs.readFile('./测试2.md', (err,data2)=>{
fs.readFile('./测试3.md', (err,data3)=>{
let result = data1 + '\r\n' + data2 + '\r\n' + data3;
console.log(result);
});
});
});
使用 promise 实现
// 使用 promise 实现
const p = new Promise((resolve,reject)=>{
fs.readFile('./测试.md', (err,data)=>{
resolve(data);
});
});
p.then(value=>{
return new Promise((resolve,reject)=>{
fs.readFile('./测试2.md', (err,data)=>{
resolve([value,data]);
});
});
}).then(value=>{
return new Promise((resolve,reject)=>{
fs.readFile('./测试3.md', (err,data)=>{
value.push(data);
resolve(value);
});
});
}).then(value=>{
console.log(value.join('\r\n'));
});
1.5 Promise对象catch方法
catch方法是.then(null, reject)的别名,用于指定发生错误时的回调函数
<script>
const p = new Promise((resolve, reject)=>{
setTimeout(()=>{
reject('出错!');
}, 1000);
});
p.catch(function(reason){
console.warn(reason);
});
</script>
二、Set(集合)
ES6 提供了新的数据结构 Set(集合)。它类似于数组,但成员的值都是唯一的,集合实现了 iterator接口,所以可以使用 扩展运算符( ... ) 和 for…of… 进行遍历
2.1 集合属性和方法
size | 返回集合的元素个数 |
add | 增加一个新元素,返回当前集合 |
delete | 删除元素,返回 boolean 值 |
has | 鉴差集合中是否包含某个元素,返回boolean值 |
let s = new Set();
let s2 = new Set(['电脑','手机','座机','电视','手机']);
// 元素个数
// console.log(s2.size);
// 添加新元素
// s2.add('游戏机');
// 删除元素
// s2.delete('电脑');
// 检测
// console.log(s2.has('游戏机'));
// console.log(s2);
for(let v of s2){
console.log(v);
}
2.2 集合案例练习
let arr = [1,2,3,4,5,4,3,2,1];
2.2.1 数组去重
// 数组去重
let result = [...new Set(arr)];
console.log(result);
2.2.2 交集
let arr2 = [4,5,6,8,4,5];
let result = [...new Set(arr)].filter(item=>{
let s2 = new Set(arr2);
if(s2.has(item)){
return true;
} else {
return false;
}
});
console.log(result);
简化写法
let result2 = [...new Set(arr)].filter(item => new Set(arr2).has(item));
console.log(result2);
2.2.3 并集
let arr2 = [4,5,6,8,4,5];
let union = [...new Set([...arr, ...arr2])];
console.log(union);
2.2.4 差集
let arr2 = [4,5,6,8,4,5];
let diff = [...new Set(arr)].filter(item => !(new Set(arr2).has(item)));
console.log(diff);
三、Map
ES6 提供了 Map 数据解构。它类似于对象,也是键值对的集合。但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以作为键。Map 也实现了 iterator 接口,所以可以使用 扩展与算符( ... )和 for...of... 进行遍历
2.1 Map的属性和方法
size | 返回Map的元素个数 |
set | 增加一个新元素,返回当前Map |
get | 返回键名对象的键值 |
has | 检测Map中是否包含某个元素,返回boolean值 |
clear | 清空集合,返回undefined |
// 声明 Map
let m = new Map();
// 添加元素
m.set('name','承太郎');
m.set('boxing',function(){
console.log('会拳击');
});
let key = {
artName : 'JOJO'
};
m.set(key,['白金之星','欧拉','世界'])
// size
// console.log(m.size);
// 删除
// 获取
// console.log(m.get('boxing'));
// console.log(m.get(key));
// 清空
// m.clear();
// 遍历
for(let v of m){
console.log(v);
}
console.log(m);
四、Class类
4.1 Class介绍
ES6 提供了更接近传统语言的写法,引入Class(类)这个概念,作为对象的模板。通过 class 关键字,可以定义类。基本上,ES6的 class 类可以看作只是一个语法糖,它的绝大部分功能,ES5 都可以做到,新的 class 写法只是让对象原型的写法更清晰、更面向对象编程的语法而已
知识点:
- class声明类
- constructor 定义构造函数初始化
- extends 继承父类
- super 调用父级构造方法
- static 定义静态方法和属性
- 父类方法可以重写
4.2 constructor 定义构造函数初始化
4.2.1 ES5 语法
// ES5 语法
function Phone(brand, price){
this.brand = brand;
this.price = price;
}
// 添加方法
Phone.prototype.call = function(){
console.log('通话功能');
}
// 实例化对象
let Huawei = new Phone('华为', 5999);
Huawei.call();
console.log(Huawei);
4.2.2 ES6 class语法
// class 语法
class Phone2{
// 构造方法 名字不能修改
constructor(brand,price){
this.brand = brand;
this.price = price;
}
// 方法必须使用该语法,不能使用 ES5 的对象完整形式
call(){
console.log('通话功能');
}
}
let xiaomi = new Phone2('xiaomi', 1999);
console.log(xiaomi);
4.3 static 定义静态方法和属性
被static 标注的属性和方法属于类,而不属于实例化对象
class Phone{
static name = '手机';
static call(){
console.log('通话功能');
}
}
let xiaomi = new Phone();
console.log(xiaomi.name);
console.log(Phone.name);
4.4 extends 继承父类
4.4.1 ES5 构造函数继承
// 父类
function Phone(brand,price){
this.brnad = brand;
this.price = price;
}
Phone.prototype.callme = function(){
console.log('通话功能');
}
// 子类
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('拍照功能');
}
smartPhone.prototype.game = function(){
console.log('支持游戏功能');
}
const xiaomi = new smartPhone('小米', 1999, '红色', '5.51inch');
console.log(xiaomi);
4.4.2 class的类继承
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('拍照功能');
}
game(){
console.log('支持游戏功能');
}
}
const xiaomi = new smartPhone('小米', 999, '黑色', '4.7inch');
console.log(xiaomi);
4.5 子类对父类方法的重写
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('拍照功能');
}
game(){
console.log('支持游戏功能');
}
// 子类对父类方法重写
call(){
console.log('视频通话功能');
}
}
const xiaomi = new smartPhone('小米', 999, '黑色', '4.7inch');
xiaomi.call();
4.6 class中的getter和setter设置
// get 和 set
class Phone{
get price(){
console.log('价格属性被读取了');
return '价格';
}
set price(newVal){
console.log('价格属性被修改了');
}
}
let s = new Phone();
// console.log(s.price);
s.price = 'free';
五、ES6的数值扩展
5.1 Number.EPSILON
Number.EPSILON 是 JavaScript 表示最小精度
EPSILON 属性的值接近于 2.2204460492503130808472633361816E-16
一般应用于浮点数运算
function equal(a,b){
if(Math.abs(a-b) < Number.EPSILON){
return true;
} else {
return false;
}
}
console.log(0.1 + 0.2 === 0.3);
console.log(equal(0.1 + 0.2, 0.3));
5.2 二进制和八进制
ES6 提供了二进制和八进制数值的新的写法,分别用前缀 0b 和 0o 表示
十六进制:0x
let b = 0b1010; // 二进制
let o = 0o777; // 八进制
let d = 100; // 十进制
let x = 0xff; // 十六进制
console.log(b);
console.log(o);
console.log(d);
console.log(x);
5.3 Number.isFinite() 与 Number.isNaN()
Number.isFinite() 检测一个数值是否为有限数
console.log(Number.isFinite(100));
console.log(Number.isFinite(100/0));
console.log(Number.isFinite(Infinity));
Number.isNaN() 检测一个数值是否为NaN
console.log(Number.isNaN(123));
5.4 Number.parseInt() 与 Number.parseFloat()
Number.parseInt() 与 Number.parseFloat() 字符串转整数
console.log(Number.parseInt('4564321aasdsd'));
console.log(Number.parseFloat('3.15462184asdasd'));
ES6 将全局方法 parseInt 和 parseFloat,移植到 Number 对象上面,使用方式不变
5.5 Number.isInteger()
Number.isInteger() 判断一个数是否为整数
console.log(Number.isInteger(12));
console.log(Number.isInteger(1.2));
5.6 Math.trunc()
Math.trunc() 用于将数字的小数部分抹掉
console.log(Math.trunc(3.14));
5.7 Math.sign()
Math.sign() 用于判断一个数到底为正数、负数 还是 零
console.log(Math.sign(100));
console.log(Math.sign(0));
console.log(Math.sign(-100));
六、ES6的对象方法扩展
6.1 Object.is()
Object.is() 用于判断两个值是否完全相等,与( === )行为基本一致,但在NaN的比较上有区别
console.log(Object.is(10,11)); // false
console.log(Object.is(10,10)); // true
console.log(Object.is(NaN,NaN)); // true
console.log(NaN === NaN); // false
6.2 Object.assign()
Object.assign(object1, object2) 用于对象的合并
注意:
- 对象中相同名称的属性,object2 会覆盖 object1
- 如果 object1 含有 object2 中含有的属性,则以 object1 中为准
const server1 = {
host: 'localhost',
port: 8000,
name: 'root',
pass: 'root',
test: 'test'
}
const server2 = {
host: 'http://127.0.0.1',
port: 8080,
name: 'admin',
pass: 'admin',
test2: 'test2'
}
console.log(Object.assign(server1, server2));
6.3 setPrototypeOf()、setPrototypeOf()
setPrototypeOf()、setPrototypeOf() 用于直接设置对象的原型
const person = {
name: '王小明'
}
const skill = {
jineng: ['唱歌','跳舞','钢琴']
}
// 并不建议采用这种方法设置对象原型
Object.setPrototypeOf(person, skill);
console.log(Object.getPrototypeOf(person));
console.log(person);
七、模块化
7.1 模块化介绍
模块化是指将一个大的程序文件,拆分成许多小的文件,然后将小文件组合起来
7.1.1 模块化的好处
- 防止命名冲突
- 代码复用
- 高维护性
7.1.2 模块化规范产品
ES6之前的模块化规范:
- CommonJS => NodeJS、Browserify
- AMD => requireJS
- CMD => seaJS
7.2 ES6模块化语法
模块功能主要由两个命令构成:export 和 import
- export 命令用于规定模块的对外接口
- import 命令用于输入其他模块提供的功能
m1.js(导出模块)
export let person = '周星星';
export function movie(){
console.log('会指导电影拍摄');
}
简单模块化使用.html(导入和使用模块)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script type="module">
// 引入 m1.js 模块内容
import * as m1 from './js/m1.js';
console.log(m1);
</script>
</body>
</html>
7.3 ES6暴露(导出)数据语法汇总
7.3.1 逐个导出模块
m1.js
// 分别暴露(导出)
export let person = '周星星';
export function movie(){
console.log('会指导电影拍摄');
}
7.3.2 统一导出模块
m2.js
// 统一暴露(导出)
let person = '周星星';
function sing(){
console.log('会唱歌');
}
export {person, sing};
7.3.3 默认导出模块
m3.js
// 默认暴露(导出)
export default {
person: 'JOJO',
boxing: function(){
console.log('会拳击');
}
}
注意:默认导出模块的语法,在需要调用该模块内容时需要添加default
<script type="module">
// 引入 m1.js 模块内容(分别导出)
import * as m1 from './js/m1.js';
// 引入 m2.js 模块内容(统一导出)
import * as m2 from './js/m2.js';
// 引入 m3.js 模块内容(默认导出)
import * as m3 from './js/m3.js';
// console.log(m3);
m3.default.boxing();
</script>
7.4 ES6引入数据语法汇总
7.4.1 通用的导入方式
// 1. 通用的导入方式
// 引入 m1.js 模块内容(分别导出)
import * as m1 from './js/m1.js';
// 引入 m2.js 模块内容(统一导出)
import * as m2 from './js/m2.js';
// 引入 m3.js 模块内容(默认导出)
import * as m3 from './js/m3.js';
7.4.2 解构赋值形式
注意:
- 属性重名时,可以采用 as 设置别名
- 遇到默认导出模块语法时,需要采用 as 设置别名
// 2. 解构赋值形式
import {person, movie} from './js/m1.js';
import {person as people, sing} from './js/m2.js';
import {default as m3} from './js/m3.js';
7.4.3 简便形式(针对默认导出语法)
// 3. 简便形式 针对默认暴露(导出)
import m3 from './js/m3.js';
7.5 浏览器使用ES6模块化方式二
script标签 src 属性引入相关文件,将 js 语法整合到一个文件app.js
<script src="./js/app.js" type="module"></script>
app.js
// 入口文件
// 模块引入
import * as m1 from './m1.js';
import * as m2 from './m2.js';
import * as m3 from './m3.js';
console.log(m1);
console.log(m2);
console.log(m3);
7.6 babel对ES6模块化代码转化
Babel 中文网 · Babel - 下一代 JavaScript 语法的编译器 (babeljs.cn)https://www.babeljs.cn/Babel 是一个 JavaScript 编译器
Babel 能够将新的ES规范语法转换成ES5的语法
因为不是所有的浏览器都支持最新的ES规范,所以,一般项目中都需要使用Babel进行转换
步骤:
- 使用Babel转换JS代码
- 打包成一个文件
- 使用时引入即可
7.6.1 步骤
1)安装工具babel-cli(命令行工具) babel-preset-env(ES转换工具) browserify(打包工具, 项目中使用的是(webpack)
2)初始化项目
npm init --yes
3)安装相关工具
npm i babel-cli babel-preset-env browserify
npm i(i 是 install缩写) babel-cli babel-preset-env browserify -D(这样安装是局部安装)
注意:用npm i安装的模块无法用npm uninstall删除,用npm uninstall i才卸载掉
4)使用babel转化
npx babel js(js目录) -d dist/js(转化后的js目录)
npx babel js(js目录) -d dist/js(转化后的js目录) --presets=babel-preset-env(命令行传参)
5)打包
npx browserify dist/js/app.js -o dist/bundle.js
6)在使用时引入bundle.js
<script src="dist/bundle.js" type="module"></script>
7)注意:如果后续有修改,需要重新使用babel转化,再重新打包
八、ES6模块化引入NPM包
8.1 安装
以jquery为例
npm i jquery
npm i (npm包)
8.2 导入
以jquery为例
import $ from 'jquery'; // 与 const $ = require('jquery'); 功能一样
import $ from 'npm包名';