【前端】ECMAScript6从入门到进阶

【前端】ECMAScript6从入门到进阶

1.ES6简介及环境搭建

1.1.ECMAScript 6简介

【前端】ECMAScript6从入门到进阶_第1张图片

(1)ECMAScript 6是什么

ECMAScript 6.0(以下简称 ES6)是 JavaScript 语言的下一代标准,已经在2015年6月正式发布了。它的目标,是使得 JavaScript 语言可以用来编写复杂的大型应用程序,成为企业级开发语言。

(2)ECMAScript 和 JavaScript 的关系

ECMAScript是JavaScript的标准,JavaScript是ECMAScript的实现。换句话说,如果说JavaScript是一门语言的话,那么ECMAScript就是这门语言遵循的语法书。

(3)ES6 与 ECMAScript 2015 的关系

2011年的时候,ECMAScript 5.1版本发布,ECMA组织就开始准备6.0版本了。但因为这个版本引入的语法功能太多了,所以不可能通过一个版本就将所有功能涵盖。所以,标准委员会决定,标准在每年的6月份正式发布一次,作为当年的正式版本。接下来的时间,就在这个版本的基础上做改动,直到下一年的6月份,草案就自然变成了新一年的版本。这样一来,就不需要以前的版本号了,只要用年份标记就可以了。

就这样ES6的第一个版本就在2015.6正式发布了,正式名称就是《ECMAScript 2015标准》(简称ES2015)。

1.2.babel工具搭建ES6环境

采用 ECMAScript 2015+ 语法编写的代码转换为向后兼容的 JavaScript 语法,以便能够运行在当前和旧版本的浏览器或其他环境中。

  • 首先确保环境中有node
node安装:http://nodejs.cn/download/
  • 初始化工程项目
// 使用默认配置初始化项目
npm init -y
  • 安装对应的依赖包
// 本地安装babel-cli及对应的转化规则
npm install --save-dev babel-cli babel-preset-es2015

// 阿里巴巴定制的镜像源
npm install -g cnpm --registry=https://registry.npm.taobao.org
  • 创建项目目录

    • src目录用于存放编写的es6代码

    • dist目录用于存放由es6转化后的代码

  • 配置babel

新建.babelrc文件

// 配置用于转化当前代码的规则集
{
  "presets": ["es2015"]
}

babel的基本用法

// -o 参数指定输出文件
node_modules/.bin/babel src/index.js -o dist/index.js

// -d 参数指定输出目录
node_modules/.bin/babel src -d dist

配置package.json文件实时编译

// 配置启动脚本的命令
"scripts": {
  // 监听index.js文件,一发生变化就执行babel转译的命令
  "dev": "babel src -w -d dist",
}

2.新的声明及数据赋值方式

2.1.变量声明let与const

作用域就是变量的有效范围,之前只有全局作用域和函数作用域,现在新增块级作用域。es6中新增let和const两种变量声明方式。

(1)let和const的相同点

  • 只在声明的代码块内有效
if (true) {
  var a = "a";
}
console.log(a);
// let声明变量,const同理
if (true) {
  let b = "b";
}
console.log(b);

【前端】ECMAScript6从入门到进阶_第2张图片

  • 在同一作用域内不允许重复声明

【前端】ECMAScript6从入门到进阶_第3张图片

  • 没有变量提升,在声明变量前,不能使用该变量
console.log(a);
var a = 'a';

console.log(b);
let b = '1';

【前端】ECMAScript6从入门到进阶_第4张图片

用var声明的变量会存在变量提升的问题,如果用let或者const就会消除变量提升问题,在遇到未定义的变量直接抛错。

(2)let和const的区别

  • const用来声明一个只读的变量
const x = 10;
x = 13;
console.log(x);

注意:const声明的变量同时必须立即赋值,如声明的是简单类型的数据,变量的值不可改变。

在这里插入图片描述

2.2.ES6新数据类型Symbol

在ES6之前JavaScript的原始数据类型有Number、String、Boolean、Null、Undefined。ES6中增加新的Symbol独一无二的类型。

对象的属性名容易产生命名冲突,为保证键名的唯一性,故es6引入Symbol这种新的原始类型数据,确保创建的每个变量都是独一无二的。

  • Symbol类型的数据是类似字符串的数据类型。
  • 由于Symbol函数返回的值是原始类型的数据,不是对象,故Symbol函数前不能使用new命令,否则会报错。
let s = Symbol();
console.log(typeof s);

在这里插入图片描述

let s1 = Symbol();
let s2 = Symbol();
console.log(s1===s2);

let l1 = Symbol('lixiang');
let l2 = Symbol('lixiang');
console.log(l1===l2);

【前端】ECMAScript6从入门到进阶_第5张图片

定义对象的唯一属性名

// 在对象里用Symbol作为属性名的三种写法
let s = Symbol();

// 第一种方式: 借助数组读取s变量,此时不能用点运算符,点运算符默认后面的参数是字符串
let a = {};
a[s] = 'lixiang'

// 第二种方式: 构造时声明
let a = {
  [s]: 'lixiang'
}

// 第三种 Object.defineProperty
let a = {};
Object.defineProperty(a, s, { value: 'lixiang' });

在这里插入图片描述

定义常量

const s = Symbol("李祥");

在这里插入图片描述

2.3.解构赋值详解

(1)什么是解构赋值

解构赋值可以理解为赋值操作的语法糖,它是针对数组或者对象进行模式匹配,然后对其中的变量进行赋值。代码书写上言简意赅,语义明确,也方便了对象数组的读取操作。

ES6中只要某种数据可以循环迭代,都可以进行解构赋值。

(2)数组解构

// 变量多时,对应不上的变成undefined
let [a, b, c] = [1, 2];
console.log(a, b, c);

在这里插入图片描述

// 变量默认值,声明变量时将c默认成6
let [a, b, c = 6] = [1, 2];
console.log(a, b, c);

在这里插入图片描述

// 分割数组,将1赋值给a,2,3成一个新数组
let [a, ...other] = [1, 2, 3];
console.log(a, other);

在这里插入图片描述

// 空内容,将a赋值为1,b赋值为3
let [a,,b] = [1, 2, 3];
console.log(a, b);

在这里插入图片描述

(3)对象解构

//1赋值为a,2赋值为b
let { a, b } = { a: 1, b: 2 };
console.log(a, b);

在这里插入图片描述

//重命名
let { a: aa, b: bb } = { a: 1, b: 2 };
console.log(aa, bb);

在这里插入图片描述

(4)读取接口返回的数据

function fun() {
  return {
    name: "张三",
    hobby: [
      {
        title: "篮球",
      },
      {
        title: "唱",
      },
      {
        title: "RAP",
      },
      {
        title: "跳",
      },
    ],
  };
}
let {
  name,
  hobby: [{ title }],
} = fun();
console.log(name, title);

3.ES6新增的数据操作方法

3.1.ES6提供的新的字符串方法

(1)新增的API

方法 描述
includes(string, index) 判断字符串中是否包含指定字符串,返回值是布尔值
startsWith(string, index) 判断字符串的开头是否包含指定字符串,返回值是布尔值
endsWith(string, index) 判断字符串的尾部是否包含指定字符串,返回值是布尔值
repeat(n) repeat() 方法返回一个新字符串,表示将原字符串重复n 次。
padStart(length, str) 字符串补齐,用于头部补全
padEnd(length, str) 字符串补齐,用于尾部补全
//判断str是否包含an
let str = 'lixiang';
console.log(str.includes('an'));
//从下标为5的字符开始判断是否含an
console.log(str.includes('an',5));

在这里插入图片描述

//判断str是否以l开头
let str = 'lixiang';
console.log(str.startsWith('l'));
//从下标为3的字符开始判断是否以l开头
console.log(str.startsWith('l',3));

在这里插入图片描述

//判断str是否以g结尾
let str = 'lixiang';
console.log(str.endsWith('g'));
//从下标为3的字符开始判断是否以g结尾
console.log(str.startsWith('g',3));

在这里插入图片描述

//入参数字为2,重复两次
let str = 'lixiang';
console.log(str.repeat(2));

在这里插入图片描述

//在lixiang前面补a,补够10位
let str = 'lixiang';
console.log(str.padStart(10, 'a'));

在这里插入图片描述

//在lixiang后面补a,补够10位
let str = 'lixiang';
console.log(str.padEnd(10, 'a'));

在这里插入图片描述

(2)模板字符串

在ES5的时候拼接字符串我们往往这样写。

const name = '李祥';
const age = 18;
const hobbies = '写代码';
const str = '我叫'+name+',今年'+age+'岁,'+'喜欢'+hobbies+'。'

在ES6中新引入的模版字符串,写法如下。

const str = `我叫${name},今年${age}岁,喜欢${hobbies}`
console.log(str);

在这里插入图片描述

(3)使用模板字符串的注意事项

  • 使用模板字符串表示多行字符串时,所有的空格和缩进都会被保留在输出之中。
  • 模板字符串中引入变量,要用 ${变量名} 这样的形式引入才可以。
  • 模板字符串中的${…} 大括号内部可以放入任意的 JavaScript 表达式,可以进行运算、可以引用对象属性、可以调用函数、可以甚至还能嵌套,甚至还能调用自己本身。
3.2.ES6扩展运算符的使用

(1)深拷贝一维数组

const list = [1, 2, 3, 4, 5];
const listCopy = [...list];
console.log(listCopy);

【前端】ECMAScript6从入门到进阶_第6张图片

(2)分割数组

const list = [1, 2, 3, 4, 5];
const [, ...list1] = list;
console.log(list1);

【前端】ECMAScript6从入门到进阶_第7张图片

(3)将数组转化成参数传递给函数

const list = [1, 2];
function fun(a, b) {
  console.log(a + b);
}
fun(...list);

在这里插入图片描述

3.3.ES6数组的扩展方法

(1)fill:替换数组中的元素,会改变原数组。想要不改变原数组的值,可以采用深拷贝。

const list = [1, 2, 3, 4, 5];
//全部替换成6
const list1 = [...list].fill(6);
//下标从1开始到下表为4之间左闭右开,全部替换成6
const list2 = [...list].fill(6, 1, 4);
console.log(list);
console.log(list1);
console.log(list2);

在这里插入图片描述

(2)find:查询数组中符合条件的元素。

const list = [
  { name: "李祥", age: 15 },
  { name: "张三", age: 10 },
  { name: "李四", age: 19 },
  { name: "王武", age: 20 },
];
const result = list.find(function (item) {
  return item.name === "李祥";
});
console.log(result);

在这里插入图片描述

(3)findIndex:查询数组中符合条件的元素的索引。

const result = list.findIndex(function (item) {
  return item.name === "李祥";
});
console.log(result);

在这里插入图片描述

(4)flat:用于合并数组。

const list = [1, 2, 3, [4, 5, 6, [ 7, 8]]];
const list2 = list.flat(2);
console.log(list2);

【前端】ECMAScript6从入门到进阶_第8张图片

(5)filter:过滤出符合条件的元素,与find不同的是filter返回一个数组。

const result = list.filter(function (item) {
  return item.name === "李祥";
});
console.log(result);

【前端】ECMAScript6从入门到进阶_第9张图片

3.4.ES6数组中map方法

map用于将一个类型的数字转换成另外一个类型。

const list = [
  { name: "李祥", age: 15 },
  { name: "张三", age: 10 },
  { name: "李四", age: 19 },
  { name: "王武", age: 20 },
];
//遍历集合中每一项,创建obj对象,将原对象属性复制到新的obj中
//然后给obj增加一个属性state
const mapList = list.map(function (i) {
  let obj = {};
  //对象拷贝
  Object.assign(obj, i);
  obj.sex = 0;
  return obj;
});
console.log(mapList);

【前端】ECMAScript6从入门到进阶_第10张图片

3.5.ES6对象的新特性

创建对象

const a = {
  name: 'lixiang',
  age: 21,
  address: {
    city: 'BeiJing',
    town: 'ChangYang'
  },
};

(1)深拷贝简单对象

const b = { ...a };
console.log(b);

【前端】ECMAScript6从入门到进阶_第11张图片

(2)给对象设置默认值

const b = { ...a, name: 'zhangsan' };
console.log(b);

在这里插入图片描述

(3)合并对象

const b = { sex:'0' };
const c = {...a,...b}
console.log(c);

在这里插入图片描述

(4)属性初始化、方法的简写

【前端】ECMAScript6从入门到进阶_第12张图片

(5)Object新增的方法

  • Object.is:判断两个对象是否相等
let res = Object.is({name:'lx'}, {name:'lx'});
console.log(res);
let res1 = Object.is(NaN, NaN);
console.log(res1);

在这里插入图片描述

  • Object.assign:对象复制
let a = { name: 'lx', age: 24 };
let b = {};
let c = Object.assign(b, a);
console.log(c);

在这里插入图片描述

  • Object.keys:获取对象所有的key
let a = { name: 'lx', age: 24 };
const arr = Object.keys(a);
console.log(arr);

在这里插入图片描述

  • Object.values:获取对象所有的value
let a = { name: 'lx', age: 24 };
const arr = Object.values(a);
console.log(arr);

在这里插入图片描述

  • Object.entries:获取key和value
let a = { name: 'lx', age: 24 };
const arr = Object.entries(a);
console.log(arr);

在这里插入图片描述

3.6.ES6新增Map与WeakMap

JavaScript中的对象,实质就是键值对的集合,但是在对象里却只能用字符串作为键名。在一些特殊的场景里就满足不了我们的需求了,正因为此,Map这一数据提出了,它是JavaScript中的一种更完善Hash结构。

Map对象:用于保存键值对,任何值(对象或者原始值)都可以作为一个键名或一个值。

  • 属性及方法
属性/方法 作用 例子
size 返回键值对的数量 m.size
clear() 清除所有键值对 m.clear()
has(key) 判断键值对中是否有指定的键名,返回值是布尔值 m.has(key)
get(key) 获取指定键名的键值,如不存在则返回undefined m.get(key)
set(key, value) 添加键值对,如键名已存在,则更新键值对 m.set(key, value)
delete(key) 删除指定键名的键值对 m.delete(key)

(1)创建一个Map

//创建一个空map
let map = new Map();
//创建一个带有默认值的map
let mapDef = new Map([
    ['name','lx'],
    ['age',12]
]);
console.log(map);
console.log(mapDef);

在这里插入图片描述

(2)API演示

//创建一个空map
let map = new Map();
//map中增加一个元素
map.set('name','lx');
map.set('age',20);
console.log(map);
//map中修改一个元素
//map中set方法如果有key则覆盖,没有则新增
map.set('name','zs');
console.log(map);
//返回键值对的数量
console.log(map.size);
//判断是否有某个key
console.log(map.has('name'));
//获取某个key的value
console.log(map.get('name'));
//删除某个key
map.delete('name');
console.log(map);
//清空
map.clear();
console.log(map);

【前端】ECMAScript6从入门到进阶_第13张图片

(3)遍历器生成函数

const keys = map.keys();
const values = map.values();
const entries = map.entries();
console.log(Array.from(keys));
console.log(Array.from(values));
console.log(Array.from(entries));

【前端】ECMAScript6从入门到进阶_第14张图片

WeakMap:只接受对象作为键名,而且无法遍历

const weakMap = new WeakMap([[{ name: 'lx' ,age: 21},{id:1,hobby:'唱、跳、rap、篮球'}]]);
console.log(weakMap);

在这里插入图片描述

【前端】ECMAScript6从入门到进阶_第15张图片

3.7.ES6新增Set与WeakSet

Set是ES6给开发者提供的一种类似数组的数据结构,可以理解为值的集合。它和数组的最大的区别就在于: 它的值不会有重复项。

Set保证成员值唯一,用于集合去重。

  • 属性及方法
属性/方法 作用 例子
add 新增元素 s.add(key)
size 返回成员个数 s.size
clear() 清除所有成员 s.clear()
has(value) 判断键值对中是否有指定的值,返回值是布尔值 s.has(key)
delete(value) 删除指定值 s.delete(key)

(1)创建一个Set

const a = { name: 'lx' };
const set = new Set([a]);
console.log(set);

const list = new Set([1, 2, 3, 4]);
console.log(list);

【前端】ECMAScript6从入门到进阶_第16张图片

(2)API演示

const set = new Set([1, 2, 3, 4]);
console.log(set);
//获取set长度
console.log(set.size);
//判断是否存在2元素
console.log(set.has(2));
//删除2元素
set.delete(2);
console.log(set.has(2));

【前端】ECMAScript6从入门到进阶_第17张图片

WeakSet:数组成员必须是对象

  • WeakSet结构也提供了add( ) 方法,delete( ) 方法,has( )方法给开发者使用,作用与用法跟Set结构完全一致。
  • WeakSet 结构不可遍历。因为它的成员都是对象的弱引用,随时被回收机制回收,成员消失。所以WeakSet 结构不会有keys( ),values( ),entries( ),forEach( )等方法和size属性。
3.8.Array与Set的转换
// 数组转set
const list = [1, 2, 3];
const set = new Set(list);
console.log(set);

// set转数组
const arr = Array.from(set);
console.log(arr);
3.9.Object与Map的转换
// 对象转map
const obj = { nane: 'lx', age:24 };
const map = new Map(Object.entries(obj));
console.log(map);

// map转对象
const obj1 = Object.fromEntries(map);
console.log(obj1);

4.ES6新增高阶知识点

4.1.ES6中新增代理Proxy

(1)Proxy简介

正如Proxy的英译"代理"所示,Proxy是ES6为了操作对象引入的API。它不直接作用在对象上,而是作为一种媒介,如果需要操作对象的话,需要经过这个媒介的同意。

(2)使用方式

/* @params
** target: 用Proxy包装的目标对象
** handler: 一个对象,对代理对象进行拦截操作的函数,如set、get
*/
let p = new Proxy(target, handler)

(3)案例实战

const house = {
  name: '三室一厅-次卧',
  price: 1000,
  phone: '18823139921',
  id: '20230131',
  state: '**',
};

const handle = {
  get: function (obj, key) {
    switch (key) {
      case 'price':
        return obj[key] + 500;
      case 'phone':
        return obj[key].substring(0, 3) + '****' + obj[key].substring(7);
      default:
        return obj[key];
    }
  },
  set: function (obj, key, value) {
    if (key === 'state') {
      obj[key] = value;
    }
  },
};

const houseproxy = new Proxy(house, handle);
console.log(houseproxy.id);
console.log(houseproxy.phone);
console.log(houseproxy.price);
houseproxy.state='****';
console.log(houseproxy.state);

在这里插入图片描述

4.2.ES6中新增反射Refect

(1)Reflect简介

与Proxy相同,ES6引入Reflect也是用来操作对象的,它将对象里一些明显属于语言内部的方法移植到Reflect对象上,它对某些方法的返回结果进行了修改,使其更合理,更具语义化,并且使用函数的方式实现了Object的命令式操作。

  • 属性及方法
属性/方法 作用
Reflect.apply(target, thisArg, args) 对一个函数进行调用操作,同时可以传入一个数组作为调用参数。
Reflect.construct(target, args) 对构造函数进行 new 操作,相当于执行 new target(…args)。
Reflect.get(target,name, receiver) 获取对象身上某个属性的值,类似于 target[name]。如果没有该属性,则返回undefined。
Reflect.set(target, name,value, receiver) Reflect.defineProperty方法基本等同于Object.defineProperty,直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,不同的是,Object.defineProperty返回此对象。而Reflect.defineProperty会返回布尔值
Reflect.has(target,name) 判断一个对象是否存在某个属性,和 in 运算符 的功能完全相同。
Reflect.ownKeys(target) 返回一个包含所有自身属性(不包含继承属性)的数组。(类似于 Object.keys(), 但不会受enumerable影响, Object.keys返回所有可枚举属性的字符串数组).
Reflect.isExtensible(target) 判断一个对象是否是可扩展的(是否可以在它上面添加新的属性),类似于 Object.isExtensible()。返回表示给定对象是否可扩展的一个Boolean 。(Object.seal 或 Object.freeze 方法都可以标记一个对象为不可扩展。)
Reflect.preventExtensions(target) 让一个对象变的不可扩展,也就是永远不能再添加新的属性。
4.3.Proxy实现数据双向绑定

(1)需求

实现一个双向的数据绑定。

在这里插入图片描述

(2)实现

  • 编写html代码
<body>
    请输入内容:<input type="text" id = "input"/><br/>
    实时内容展示:<span id = "span">span>
    <script src="./js/index.js">script>
body>
  • 编写js代码
// 获取dom节点
const input = document.getElementById("input");
const span = document.getElementById("span");
//定义双向绑定的对象
let obj = {};

//定义代理对象的handle方法
const handle = {
  get: function (target, key) {
    return target[key];
  },
  set: function (target, key, value) {
    if (key === "text" && value) {
      span.innerHTML = value;
      return (target[key] = value);
    }
  },
};

//创建代理对象
const proxy = new Proxy(obj, handle);

//创建键盘的监听事件
input.addEventListener("keyup", function (e) {
  proxy.text = e.target.value;
  console.log(proxy.text);
});

5.函数的扩展、类及模块化

5.1.函数参数的扩展

(1)函数参数可设置默认值

//求和方法,当a和b都不传值时,默认都为1
function sum(a = 1, b = 1) {
  return a + b;
}
console.log(sum());
console.log(sum(3));
console.log(sum(3,5));

在这里插入图片描述

(2)rest参数,可变参数

//求和方法,可变参数
function sum(...rest) {
    let num = 0;
    rest.forEach((e)=>{
        num+=e;
    })
  return num;
}
console.log(sum(...[1,2]));
console.log(sum(...[1,2,4]));

在这里插入图片描述

5.2.ES6新增箭头函数

(1)箭头函数简介

ES6中允许使用=>来定义函数。箭头函数相当于[匿名函数,并简化了函数定义。

箭头函数在语法上比普通函数简洁多。箭头函数就是采用箭头=>来定义函数,省去关键字function。

无参:()=>{},等同于:function (){}
有参:(a,b)=>{},等同于:function (a,b){}

(2)箭头函数不绑定this

//箭头函数this指当前块级作用域
const obj = {
  num: 10,
  sum() {
    setTimeout(() => {
      console.log(this.num);
    }, 1000);
  },
};
obj.sum();

在这里插入图片描述

如果不是箭头函数,setTimeout()函数调用指的是当前window。

const obj = {
  num: 10,
  sum() {
    setTimeout(function (){
      console.log(this);
    }, 1000);
  },
};
obj.sum();

在这里插入图片描述

(3)什么情况下不能箭头函数

  • 定义对象的方法
const obj = {
  num: 10,
  sum:() => {
    setTimeout(() => {
      console.log(this.num);
    }, 1000);
  },
};
obj.sum();

在这里插入图片描述

  • 箭头函数没有arguments
const fun = () => {
  console.log(arguments);
};
fun();

【前端】ECMAScript6从入门到进阶_第18张图片

  • 定义构造函数
const Car = () => {
  console.log(this);
};
let car = new Car();

在这里插入图片描述

  • 定义DOM事件的回调函数
const span = document.getElementById("span");
span.addEventListener("click", () => {
  console.log(this);
  this.innerHTML = "触发事件";
});

【前端】ECMAScript6从入门到进阶_第19张图片

在这里插入图片描述

const span = document.getElementById("span");
span.addEventListener("click", function () {
  console.log(this);
  this.innerHTML = "触发事件";
});

在这里插入图片描述

5.3.ES6中新引入类的概念

ES6之前javascript中只有对象,没有类的概念。它是基于原型的面向对象语言。原型对象特点就是将自身的属性共享给新对象。

(1)定义类

class Person {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }
  sayHello() {
    console.log(`我是${this.name},今年${this.age}`);
  }
}
const person = new Person("张三", 18);
person.sayHello();
console.log(person);

在这里插入图片描述

(2)类的继承,重写父类的方法

class Person {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }
  hello() {
    console.log(`我是${this.name},今年${this.age}`);
  }
}

class Student extends Person {
  //子类重写父类属性
  constructor(name, age, sex) {
    super(name, age);
    this.sex = sex;
  }
  hello() {
    console.log(`我是${this.name},今年${this.age}岁,性别:${this.sex === '1'?'男':'女'}`);
  }
}

const person = new Student('张三', 18,'1');
person.hello();
console.log(person);

【前端】ECMAScript6从入门到进阶_第20张图片

(3)静态方法和静态属性

//静态方法和静态属性只能由类名进行调用
class Person {
  static eyes = '眼睛';
  static hello(){
    console.log(`我是${this.name}`);
  }
}

console.log(Person.eyes);
Person.hello();

在这里插入图片描述

5.4.ES6新增模块化开发

ES6之前是没有类的概念的,也就没有模块这一说法。理想情况下,开发者应该只注重核心业务的开发,对于其他有一定通用性的业务可以直接引入,也就是模块。多人开发,本应如此。

  • CommonJS:Commonjs是作为Node中模块化规范以及原生模块面世的。
  • AMD和RequireJs:AMD是"Asynchronous Module Definition"的缩写,意思就是"异步模块定义"。它采用异步方式加载模块,模块的加载不影响它后面语句的运行。所有依赖这个模块的语句,都定义在一个回调函数中,等到所有依赖加载完成之后(前置依赖),这个回调函数才会运行。

Import 和 export案例

  • export.js
const name = '李祥';

function hello(){
  console.log('hello word');
}

class Car{
  constructor(name){
    this.name=name;
  }
  run(){
    console.log(this.name+'跑起来了');
  }
}

export default{
  name,
  hello,
  Car,
}
  • Import.js
import test from './export.js';
console.log(test.name);
test.hello();
  • html中js引入要改成module类型
<script src="./js/import.js" type="module"></script>

在这里插入图片描述

6.ES6改进异步编程

6.1.Promise简介及案例

(1)什么是回调地狱

当异步操作想要有顺序时,只能在一个异步成功以后的回调函数里面嵌套另一个异步的操作,如果嵌套的层数过多就形成了回调地狱。

回调地狱的弊端:后期代码维护比较困难。

promise就是用来解决回调地狱。

promise封装了异步操作。创建一个promise对象,写一个函数作为参数,这个函数参数有两个参数,分别是resolve和reject。函数内部写异步操作,成功调resolve,失败调reject。这时promise对象就可以知道异步操作的状态。p.then(成功执行)p.catch(失败执行)。

promise本质就是一个状态机,记录异步内部操作的状态。

在es6之前写法代码耦合,出错时,无法排除。

function request() {
  axios.get("a.json").then((res) => {
    if (res && res.data.code === 0) {
      console.log(res.data.data.data);
      axios.get("b.json").then((res) => {
        if (res && res.data.code === 0) {
          console.log(res.data.data.data);
          axios.get("c.json").then((res) => {
            console.log(res.data.data.data);
          });
        }
      });
    }
  });
}

request();
  • 简单说Promise就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。
  • 从语法上说,Promise 是一个对象,从它可以获取异步操作的的最终状态(成功或失败)。
  • Promise 是一个构造函数,提供统一的 API,Promise里不仅可以存放着异步的代码,也可以放同步的代码。
// 准备阶段
new Promise((resolve, reject) => {})

// 成功状态
new Promise((resolve, reject) => {
  resolve('成功'); // 同步代码
}).then((res) => {
  console.log(res);
});

// 失败状态
new Promise((resolve, reject) => {
  reject('失败');
}).catch((err) => {
  console.log(err);
});

在这里插入图片描述

  • Promise对象的状态不受外界影响

    • pending 初始状态

    • resolve 成功状态

    • rejected 失败状态

      Promise 有以上三种状态,只有异步操作的结果可以决定当前是哪一种状态,其他任何操作都无法改变这个状态

  • Promise的状态一旦改变,就不会再变,任何时候都可以得到这个结果,状态不可以逆,只能由 pending变成resolve或者由pending变成rejected

(2)Promise解决回调地狱案例

//先定义三个函数
function requestA() {
  return new Promise((resolve, reject) => {
    axios.get("a.json").then((res) => {
      resolve(res);
    });
  });
}

function requestB() {
  return new Promise((resolve, reject) => {
    axios.get("b.json").then((res) => {
      resolve(res);
    });
  });
}

function requestC() {
  return new Promise((resolve, reject) => {
    axios.get("c.json").then((res) => {
      resolve(res);
    });
  });
}
function request() {
  requestA().then((res) => {
      console.log(res);
      return requestB();
    }).then((res) => {
      console.log(res);
      return requestC();
    }).then((res) => {
      console.log(res);
    });
}
request();

(3)Promise.all方法

  • Promise.all 实际上是一个函数,它接受一个 promise 数组并返回一个 promise。然后当所有的 promise 都完成时会得到结果数组或者当其中一个被拒绝时会抛出错误。
  • 返回值将会按照参数内的 promise 顺序排列,而不是由调用 promise 的完成顺序决定。
function requestAll() {
  Promise.all([requestA(), requestB(), requestC()])
    .then((res) => {
      console.log(res);
    })
    .catch((err) => {
      console.log(err);
    });
}
requestAll();

(4)Promise.race方法

Promse.race就是赛跑的意思,传入的promise 数组里面哪个结果获得的快,就返回那个结果,不管结果本身是成功状态还是失败状态。

function requestRace() {
  Promise.race([requestA(), requestB(), requestC()])
    .then((res) => {
      console.log(res);
    })
    .catch((err) => {
      console.log(err);
    });
}
requestRace();
6.2.优雅的异步编程async

(1)什么是async

async是异步的简写,Generator(生成器)的语法糖,用于声明一个函数是异步函数。

async function sum(a,b) {
  await console.log(a+b);
}
sum(1,2);

async 写在函数前,返回一个Promise对象。

async await改造promise.then异步调用。

async function request() {
  try {
    const a = await requestA();
    const b = await requestB();
    const c = await requestC();
    console.log(a, b, c);
  } catch (err) {
    console.log(err);
  }
}
request();

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