一、概述
1、什么是 ECMA
先来个学习视频的网站:https://www.bilibili.com/video/BV1uK411H7on?p=2&spm_id_from=pageDriver ECMA(European Computer Manufacturers Association)中文名称为欧洲计算机制造商协会,这个组织的目标是评估、开发和认可电信和计算机标准。1994 年后该组织改名为 Ecma 国际;
2、什么是 ECMAScript
ECMAScript 是由 Ecma 国际通过 ECMA-262 标准化的脚本程序设计语言;百度百科:https://baike.baidu.com/history/ECMAScript/1889420/144946978
3、什么是 ECMA-262
Ecma 国际制定了许多标准,而 ECMA-262 只是其中的一个,所有标准列表查看:http://www.ecma-international.org/publications/standards/Standard.htm
4、ECMA-262 历史
ECMA-262(ECMAScript)历史版本查看网址:http://www.ecma-international.org/publications/standards/Ecma-262-arch.htm
5、谁在维护ECMA-262
TC39(Technical Committee 39)是推进 ECMAScript 发展的委员会。其会员都是公司(其中主要是浏览器厂商,有苹果、谷歌、微软、因特尔等)。TC39 定期召开会议,会议由会员公司的代表与特邀专家出席;
6、为什么要学习 ES6
ES6 的版本变动内容最多,具有里程碑意义;
ES6 加入许多新的语法特性,编程实现更简单、高效;
ES6 是前端发展趋势,就业必备技能;
7、ES6 兼容性
查看网址:http://kangax.github.io/compat-table/es6
二、ES6
let关键字
特性: let 关键字用来声明变量,使用 let 声明的变量有几个特点:
- 不允许重复声明;
- 块儿级作用域(局部变量);
- 不存在变量提升;
- 不影响作用域链;
let代码示例:
// let关键字使用示例:
let a; // 单个声明
let b,c,d; // 批量声明
let e = 100; // 单个声明并赋值
let f = 521, g = 'iloveyou', h = []; // 批量声明并赋值
// 1. 不允许重复声明;
let dog = "狗";
let dog = "狗";
// 报错:Uncaught SyntaxError: Identifier 'dog' has already been declared
// 2. 块儿级作用域(局部变量);
{
let cat = "猫";
console.log(cat);
}
console.log(cat);
// 报错:Uncaught ReferenceError: cat is not defined
什么是变量提升:
就是在变量创建之前使用(比如输出:输出的是默认值),let不存在,var存在;
// 3. 不存在变量提升;
// 什么是变量提升:就是在变量创建之前使用(比如输出:输出的是默认值),let不存 在,var存在;
console.log(people1); // 可输出默认值
console.log(people2); // 报错:Uncaught ReferenceError: people2 is not defined
var people1 = "大哥"; // 存在变量提升
let people2 = "二哥"; // 不存在变量提升
应用场景:以后声明变量使用 let 就对了;
const 关键字
特性:const 关键字用来声明常量,const 声明有以下特点:
- 声明必须赋初始值;
- 标识符一般为大写(习惯);
- 不允许重复声明;
- 值不允许修改;
- 块儿级作用域(局部变量);
const创建变量代码示例:
<script>
// const声明常量
const DOG = "旺财";
console.log(DOG);
</script>
// 1. 声明必须赋初始值;
const CAT; //报错
// 2. 不允许重复声明;
const CAT = "喵喵";
const CAT = "喵喵";
// 3. 值不允许修改;
// 注意:对数组元素的修改和对对象内部的修改是可以的(数组和对象存的是引用地址);
const CAT = "喵喵";
CAT = "咪咪";
// 4. 块儿级作用域(局部变量);
{
const CAT = "喵喵";
console.log(CAT);
}
console.log(CAT);
应用场景:声明对象类型使用 const,非对象类型声明选择 let; (留有疑问)
解构赋值
什么是解构赋值:
ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构赋值; 解构赋值的好处:相比数组和对象直接赋值是引用关系,利用结构赋值可以避免这种引用关系,实现深层克隆。
代码演示及相关说明:
1、数组的解构赋值
<script>
const F4 = ["大哥","二哥","三哥","四哥"];
// 1. 将数组解构出来
let [a,b,c,d] = F4;
console.log(a + b + c + d); // 大哥二哥三哥四哥
// 2. 利用结构赋值添加新的元素
let F5 = [...F4,"五哥"]
console.log(F5) //['大哥', '二哥', '三哥', '四哥', '五哥']
</script>
2、对象的解构赋值
<script>
// 1.解构对象中的数据
const F3 = {
name : "大哥",
age : 22,
sex : "男",
xiaopin : function(){
console.log("我会演小品!");
}
}
let {name,age,sex,xiaopin} = F3; // 注意解构对象这里用的是{}
console.log(name + age + sex + xiaopin); // 大哥22男
xiaopin(); // 此方法可以正常调用
// 1.1 如果想创建的变量名和对象的属性名不一致,可以这么写:
const {a:a1} = obj;
console.log(a1);// 1
//1.2 补充 ES6的解构赋值虽然好用。但是要注意解构的对象不能为undefined、null。否则会报错,故要给被解构的对象一个默认值。
const {a,b,c,d,e} = obj || {};
//2. 深层克隆;合并多个对象
const F3 = {
name : "大哥",
age : 22,
sex : "男",
xiaopin : function(){
console.log("我会演小品!");
}
}
let F4 = { wife:'王五' }
let F5 = {...F3,...F4}
console.log(F5) // 输出 {name: '大哥', age: 22, sex: '男', wife: '王五', xiaopin: ƒ }
F5.wife = '李四'
console.log(F4.wife) //输出王五
</script>
应用场景:频繁使用对象方法、数组元素,就可以使用解构赋值形式;
模板字符串
概述:
模板字符串(template string)是增强版的字符串,用反引号(`)标识,特点:
- 字符串中可以出现换行符;
- 可以使用 ${xxx} ,在{ }中可以放入任意的javaScript表达式,可以进行运算,以及引用对象属性和变量
代码演示及相关说明:
<script>
// 声明字符串的方法:单引号('')、双引号("")、反引号(``)
// 声明
let string = `我也一个字符串哦!`;
console.log(string);
// 特性
// 1、字符串中可以出现换行符
let str = `<ul>
<li>大哥</li>
<li>二哥</li>
<li>三哥</li>
<li>四哥</li>
</ul>`;
console.log(str);
// 2、可以使用 ${xxx} 形式引用变量
let s = "大哥";
let out = `${s}是我最大的榜样!`;
// 3.可以${xxx} 中写入任意js表达式
const name = '小明';
const score = 59;
const result = `${name}${score > 60?'的考试成绩及格':'的考试成绩不及格'}`;
// 4. 动态对象属性名
// 原代码
// let obj = {};
// let index = 1;
// let key = `topic${index}`;
// obj[key] = '话题内容';
//改进
let obj = {};
let index = 1;
obj[`topic${index}`] = '话题内容';
</script>
简化对象和函数写法
概述:
ES6 允许在大括号里面,直接写入变量和函数,作为对象的属性和方法。这样的书写更加简洁;
代码示例及相关说明:
<script>
// ES6允许在对象的大括号内直接写入变量和函数作为对象的属性和方法
// 变量和函数
let name = "訾博";
let change = function(){
console.log("活着就是为了改变世界!");
}
//创建对象
const school = {
// 完整写法
// name:name,
// change:change
// 简化写法
name, //相当于 name:name
change, //相当于 change:change
// 声明方法的简化
say(){
console.log("言行一致!");
}
}
school.change();
school.say();
</script>
箭头函数
概述:
ES6允许使用箭头(=>)定义函数,箭头函数提供了一种更加简洁的函数书写方式,箭头函数多用于匿名函数的定义;
箭头函数的注意点:
- 如果形参只有一个,则小括号可以省略;
- 函数体如果只有一条语句,则花括号可以省略,函数的返回值为该条语句的执行结果;
- 箭头函数 this 指向声明时所在作用域下 this 的值;
- 箭头函数不能作为构造函数实例化;
- 不能使用 arguments;
特性:
- 箭头函数的this是静态的,始终指向函数声明时所在作用域下的this的值;
- 不能作为构造实例化对象;
- 不能使用 arguments 变量;
代码演示及相关说明:
注意:箭头函数不会更改 this 指向,用来指定回调函数会非常合适;
<script>
// ES6允许使用箭头(=>)定义函数
// 传统写法:无参数
var say = function(){
console.log("hello!");
}
say();
// ES写法2:无参数
let speak = () => console.log("hello 哈哈!");
speak();
// 传统写法:一个参数
var hello = function(name){
return "hello " + name;
}
console.log(hello("訾博"));
// ES6箭头函数:一个参数
let hi = name => "hi " + name;**运行结果:**
console.log(hi("訾博"));
// 传统写法:多个参数
var sum = function(a,b,c){
return a + b + c;
}
console.log(sum(1,2,3));
// ES6箭头函数:多个参数
let he = (a,b,c) => a + b + c;
console.log(he(1,2,3));
// 特性
// 1、箭头函数的this是静态的,始终指向函数声明时所在作用域下的this的值
const school = {
name : "大哥",
}
// 传统函数
function getName(){
console.log("getName:" + this.name);
}
// 箭头函数
getName1 = () => console.log("getName1:" + this.name);
window.name = "訾博";
// 直接调用
getName();
getName1();
// 使用call调用
getName.call(school);
getName1.call(school);
// 结论:箭头函数的this是静态的,始终指向函数声明时所在作用域下的this的值
// 2、不能作为构造实例化对象
// let Persion = (name,age) => {
// this.name = name;
// this.age = age;
// }
// let me = new Persion("訾博",24);
// console.log(me);
// 报错:Uncaught TypeError: Persion is not a constructor
// 3、不能使用 arguments 变量
// let fn = () => console.log(arguments);
// fn(1,2,3);
// 报错:Uncaught ReferenceError: arguments is not defined
</script>
函数参数的默认值
概述:ES允许给函数的参数赋初始值;
代码示例及相关说明:
<script>
//ES6 允许给函数参数赋值初始值
//1. 形参初始值 具有默认值的参数, 一般位置要靠后(潜规则)
function add(a,b,c=10) {
return a + b + c;
}
let result = add(1,2);
console.log(result); // 13
//2. 与解构赋值结合
// 注意这里参数是一个对象
function connect({host="127.0.0.1", username,password, port}){
console.log(host)
console.log(username)
console.log(password)
console.log(port)
}
connect({
host: 'atguigu.com',
username: 'root',
password: 'root',
port: 3306
})
</script>
rest参数
概述:ES6 引入 rest 参数,用于获取函数的实参,用来代替 arguments;
参考文章:https://www.jianshu.com/p/50bcb376a419
代码示例及相关说明:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>rest参数</title>
</head>
<body>
<script>
// ES6 引入 rest 参数,用于获取函数的实参,用来代替 arguments;
// ES5获取实参的方式
function data(){
console.log(arguments);
}
data("大哥","二哥","三哥","四哥");
// ES6的rest参数...args,rest参数必须放在最后面
function data(...args){
console.log(args); // fliter some every map
}
data("大哥","二哥","三哥","四哥");
</script>
</body>
</html>
扩展运算符
介绍:
- … 扩展运算符能将数组转换为逗号分隔的参数序列;
- 扩展运算符(spread)也是三个点(…)。它好比 rest 参数的逆运算,将一个数组转为用逗号分隔的参数序列,对数组进行解包;
基本使用:
<script>
// ... 扩展运算符能将数组转换为逗号分隔的参数序列
//声明一个数组 ...
const tfboys = ['易烊千玺', '王源', '王俊凯'];
// => '易烊千玺','王源','王俊凯'
// 声明一个函数
function chunwan() {
console.log(arguments);
}
chunwan(...tfboys); // chunwan('易烊千玺','王源','王俊凯')
// 应用
//1. 数组去重与合并(set和扩展运算符)
const a = [1,2,3];
const b = [1,5,6];
const c = [...new Set([...a,...b])];//[1,2,3,5,6]
const obj1 = {a:1,}
const obj2 = {b:1,}
const obj = {...obj1,...obj2};//{a:1,b:1}
//2. 数组的克隆
const sanzhihua = ['E','G','M'];
const sanyecao = [...sanzhihua];// ['E','G','M']
console.log(sanyecao);
//3. 将伪数组转为真正的数组
const divs = document.querySelectorAll('div');
const divArr = [...divs];
console.log(divArr);// arguments
</script>
Symbol
Symbol概述:
ES6 引入了一种新的原始数据类型 Symbol,表示独一无二的值。它是JavaScript 语言的第七种数据类型,是一种类似于字符串的数据类型; 参考文章:https://blog.csdn.net/fesfsefgs/article/details/108354248
Symbol 特点:
- Symbol 的值是唯一的,用来解决命名冲突的问题;
- Symbol 值不能与其他数据进行运算;
- Symbol 定义的对象属性不能使用for…in循环遍历 ,但是可以使用Reflect.ownKeys 来获取对象的所有键名;
基本使用:
</script>
//创建Symbol
let s = Symbol();
// console.log(s, typeof s);
let s2 = Symbol('尚硅谷');**Symbol****创建对象属性:**
let s3 = Symbol('尚硅谷');
console.log(s2==s3); // false
//Symbol.for 创建
let s4 = Symbol.for('尚硅谷');
let s5 = Symbol.for('尚硅谷');
console.log(s4==s5); // true
//不能与其他数据进行运算
// let result = s + 100;
// let result = s > 100;
// let result = s + s;
// USONB you are so niubility
// u undefined
// s string symbol
// o object
// n null number
// b boolean
</script>
Symbol实例 创建对象属性
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Symbol 创建对象属性</title>
</head>
<body>
<script>
//向对象中添加方法 up down
let game = {
name:'俄罗斯方块',
up: function(){},
down: function(){}
};
//声明一个对象
// let methods = {
// up: Symbol(),
// down: Symbol()
// };
// game[methods.up] = function(){
// console.log("我可以改变形状");
// }
// game[methods.down] = function(){
// console.log("我可以快速下降!!");
// }
// console.log(game);
//
let youxi = {
name:"狼人杀",
[Symbol('say')]: function(){
console.log("我可以发言")
},
[Symbol('zibao')]: function(){
console.log('我可以自爆');
}
}
console.log(youxi)
</script>
</body>
</html>
Symbol内置值:
概述:
除了定义自己使用的 Symbol 值以外,ES6 还提供了 11 个内置的 Symbol 值,指向语言内部使用的方法。可以称这些方法为魔术方法,因为它们会在特定的场景下自动执行;
方法:
特别的: Symbol内置值的使用,都是作为某个对象类型的属性去使用;
演示:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Symbol内置属性</title>
</head>
<body>
<script>
// class Person{
// static [Symbol.hasInstance](param){
// console.log(param);
// console.log("我被用来检测类型了");
// return false;
// }
// }
// let o = {};
// console.log(o instanceof Person);
// const arr = [1,2,3];
// const arr2 = [4,5,6];
// arr2[Symbol.isConcatSpreadable] = false;
// console.log(arr.concat(arr2));
</script>
</body>
</html>
迭代器
概述:遍历器(Iterator)就是一种机制。它是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署 Iterator 接口,就可以完成遍历操作;
特性:
ES6 创造了一种新的遍历命令 for…of 循环,Iterator 接口主要供 for…of 消费;
原生具备 iterator 接口的数据(可用 for of 遍历):
- Array;
- Arguments;
- Set;
- Map;
- String;
- TypedArray;
- NodeList;
工作原理:
- 创建一个指针对象,指向当前数据结构的起始位置;
- 第一次调用对象的 next 方法,指针自动指向数据结构的第一个成员;
- 接下来不断调用 next 方法,指针一直往后移动,直到指向最后一个成员;
- 每调用 next 方法返回一个包含 value 和 done 属性的对象;
注:需要自定义遍历数据的时候,要想到迭代器;
代码示例及相关说明:
<script>
// 声明一个数组
const xiyou = ['唐僧', '孙悟空', '猪八戒', '沙僧'];
// 使用 for...of 遍历数组
for(let v of xiyou){
console.log(v);
}
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());
// 重新初始化对象,指针也会重新回到最前面
let iterator1 = xiyou[Symbol.iterator]();
console.log(iterator1.next());
</script>
迭代器自定义遍历对象:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>自定义遍历数据</title>
</head>
<body>
<script>
//声明一个对象
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 (let v of banji) {
console.log(v);
}
</script>
</body>
</html>
生成器
概述:生成器函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同;
基本使用:
<script>
// 生成器其实就是一个特殊的函数
// 异步编程 纯回调函数 node fs ajax mongodb
// yield:函数代码的分隔符
function* gen() {
console.log(111);
yield '一只没有耳朵';
console.log(222);
yield '一只没有尾部';
console.log(333);
yield '真奇怪';
console.log(444);
}
let iterator = gen();
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log("遍历:");
//遍历
for(let v of gen()){
console.log(v);
}
</script>
生成器函数的参数传递:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>生成器函数参数</title>
</head>
<body>
<script>
function * gen(arg){
console.log(arg);
let one = yield 111;
console.log(one);
let two = yield 222;
console.log(two);
let three = yield 333;
console.log(three);
}
//执行获取迭代器对象
let iterator = gen('AAA');
console.log(iterator.next());
//next方法可以传入实参
console.log(iterator.next('BBB'));
console.log(iterator.next('CCC'));
console.log(iterator.next('DDD'));
</script>
</body>
</html>
生成器函数实例1:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>生成器函数实例</title>
</head>
<body>
<script>
// 异步编程 文件操作 网络操作(ajax, request) 数据库操作
// 1s 后控制台输出 111 2s后输出 222 3s后输出 333
// 回调地狱
// setTimeout(() => {
// console.log(111);
// setTimeout(() => {
// console.log(222);
// setTimeout(() => {
// console.log(333);
// }, 3000);
// }, 2000);
// }, 1000);
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();
</script>
</body>
</html>
生成器函数实例2:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>生成器函数</title>
</head>
<body>
<script>
//模拟获取 用户数据 订单数据 商品数据
function getUsers(){
setTimeout(()=>{
let data = '用户数据';
//调用 next 方法, 并且将数据传入
iterator.next(data);
}, 1000);
}
function getOrders(){
setTimeout(()=>{
let data = '订单数据';
iterator.next(data);
}, 1000)
}
function getGoods(){
setTimeout(()=>{
let data = '商品数据';
iterator.next(data);
}, 1000)
}
function * gen(){
let users = yield getUsers();
let orders = yield getOrders();
let goods = yield getGoods();
}
//调用生成器函数
let iterator = gen();
iterator.next();
</script>
</body>
</html>
运行结果:
Promise
概述:Promise 是 ES6 引入的异步编程的新解决方案。语法上 Promise 是一个构造函数,用来封装异步操作并可以获取其成功或失败的结果;
- Promise 构造函数: Promise (excutor) {};
- Promise.prototype.then 方法;
- Promise.prototype.catch 方法;
基本使用:
<script>
// 实例化 Promise 对象
// Promise 对象三种状态:初始化、成功、失败
const p = new Promise(function(resolve,reject){
setTimeout(function(){
// 成功
// let data = "数据";
// 调用resolve,这个Promise 对象的状态就会变成成功
// resolve(data);
// 失败
let err = "失败了!";
reject(err);
},1000);
});
// 成功
// 调用 Promise 对象的then方法,两个参数为函数
p.then(function(value){ // 成功
console.log(value);
}, function(season){ // 失败
console.log(season);
});
</script>
Promise封装读取文件:
一般写法:
// 1、引入 fs 模块
const fs = require("fs");
// 2、调用方法,读取文件
fs.readFile("resources/text.txt",(err,data)=>{
// 如果失败则抛出错误
if(err) throw err;
// 如果没有出错,则输出内容
console.log(data.toString());
});
Promise封装:
//1. 引入 fs 模块
const fs = require('fs');
//2. 调用方法读取文件
// fs.readFile('./resources/为学.md', (err, data)=>{
// //如果失败, 则抛出错误
// if(err) throw err;
// //如果没有出错, 则输出内容
// console.log(data.toString());
// });
//3. 使用 Promise 封装
const p = new Promise(function(resolve, reject){
fs.readFile("./resources/为学.mda", (err, data)=>{
//判断如果失败
if(err) reject(err);
//如果成功
resolve(data);
});
});
p.then(function(value){
console.log(value.toString());
}, function(reason){
console.log("读取失败!!");
});
运行结果:
Promise封装Ajax请求:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>发送 AJAX 请求</title>
</head>
<body>
<script>
// 接口地址: https://api.apiopen.top/getJoke
const p = new Promise((resolve, reject) => {
//1. 创建对象
const xhr = new XMLHttpRequest();
//2. 初始化
xhr.open("GET", "https://api.apiopen.top/getJ");
//3. 发送
xhr.send();
//4. 绑定事件, 处理响应结果
xhr.onreadystatechange = function () {
//判断
if (xhr.readyState === 4) {
//判断响应状态码 200-299
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>
</body>
</html>
运行结果:
Promise-then方法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Promise.prototype.then</title>
</head>
<body>
<script>
//创建 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 'iloveyou';
// //2. 是 promise 对象
// // return new Promise((resolve, reject)=>{
// // // resolve('ok');
// // reject('error');
// // });
// //3. 抛出错误
// // throw new Error('出错啦!');
// throw '出错啦!';
// }, reason=>{
// console.warn(reason);
// });
//链式调用
p.then(value=>{
}).then(value=>{
});
</script>
</body>
</html>
运行结果:
Promise-catch方法
catch是promise函数失败的回调函数,是一个语法糖,相当于then方法的第二个参数
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>catch方法</title>
</head>
<body>
<script>
const p = new Promise((resolve, reject)=>{
setTimeout(()=>{
//设置 p 对象的状态为失败, 并设置失败的值
reject("出错啦!");
}, 1000)
});
// p.then(function(value){}, function(reason){
// console.error(reason);
// });
p.catch(function(reason){
console.warn(reason);
});
</script>
</body>
</html>
Promise实践练习 - “回调地狱”方式写法:
//引入 fs 模块
const fs = require("fs");
fs.readFile('./resources/为学.md', (err, data1)=>{
fs.readFile('./resources/插秧诗.md', (err, data2)=>{
fs.readFile('./resources/观书有感.md', (err, data3)=>{
let result = data1 + '\r\n' +data2 +'\r\n'+ data3;
console.log(result);
});
});
});
Promise实践练习 - “回调地狱”改良:
//引入 fs 模块
const fs = require("fs");
//使用 promise 实现
const p = new Promise((resolve, reject) => {
fs.readFile("./resources/为学.md", (err, data) => {
resolve(data);
});
});
p.then(value => {
return new Promise((resolve, reject) => {
fs.readFile("./resources/插秧诗.md", (err, data) => {
resolve([value, data]);
});
});
}).then(value => {
return new Promise((resolve, reject) => {
fs.readFile("./resources/观书有感.md", (err, data) => {
//压入
value.push(data);
resolve(value);
});
})
}).then(value => {
console.log(value.join('\r\n'));
});
set集合
概述:
ES6 提供了新的数据结构 Set(集合)。它类似于数组,但成员的值都是唯一的,集合实现了 iterator接口,所以可以使用『扩展运算符』和『for…of…』进行遍历,集合的属性和方法:
- size 返回集合的元素个数;
- add 增加一个新元素,返回当前集合;
- delete 删除元素,返回 boolean 值;
- has 检测集合中是否包含某个元素,返回 boolean 值;
- clear 清空集合,返回 undefined;
基本使用:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>集合</title>
</head>
<body>
<script>
let s = new Set();
console.log(s,typeof s);
let s1 = new Set(["大哥","二哥","三哥","四哥","三哥"]);
console.log(s1); // 自动去重
// 1. size 返回集合的元素个数;
console.log(s1.size);
// 2. add 增加一个新元素,返回当前集合;
s1.add("大姐");
console.log(s1);
// 3. delete 删除元素,返回 boolean 值;
let result = s1.delete("三哥");
console.log(result);
console.log(s1);
// 4. has 检测集合中是否包含某个元素,返回 boolean 值;
let r1 = s1.has("二姐");
console.log(r1);
// 5. clear 清空集合,返回 undefined;
s1.clear();
console.log(s1);
</script>
</body>
</html>
Set集合实践:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Set 实践</title>
</head>
<body>
<script>
let arr = [1,2,3,4,5,4,3,2,1];
//1. 数组去重与合并(set和扩展运算符)
const a = [1,2,3];
const b = [1,5,6];
const c = [...new Set([...a,...b])];//[1,2,3,5,6]
const obj1 = {a:1,}
const obj2 = {b:1,}
const obj = {...obj1,...obj2};//{a:1,b:1}
console.log(result);
//2. 交集
let arr2 = [4,5,6,5,6];
// let result = [...new Set(arr)].filter(item => {
// let s2 = new Set(arr2);// 4 5 6
// if(s2.has(item)){
// return true;
// }else{
// return false;
// }
// });
// let result = [...new Set(arr)].filter(item => new Set(arr2).has(item));
// console.log(result);
//3. 并集
// let union = [...new Set([...arr, ...arr2])];
// console.log(union);
//4. 差集
let diff = [...new Set(arr)].filter(item => !(new Set(arr2).has(item)));
console.log(diff);
</script>
</body>
</html>
map集合
概述:
ES6 提供了 Map 数据结构。它类似于对象,也是键值对的集合。但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。Map 也实现了iterator 接口,所以可以使用『扩展运算符』和『for…of…』进行遍历;
Map 的属性和方法:
- size 返回 Map 的元素个数;
- set 增加一个新元素,返回当前 Map;
- get 返回键名对象的键值;
- has 检测 Map 中是否包含某个元素,返回 boolean 值;
- clear 清空集合,返回 undefined;
基础使用:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Map</title>
</head>
<body>
<script>
//声明 Map
let m = new Map();
//添加元素
m.set('name','尚硅谷');
m.set('change', function(){
console.log("我们可以改变你!!");
});
let key = {
school : 'ATGUIGU'
};
m.set(key, ['北京','上海','深圳']);
//size
// console.log(m.size);
//删除
// m.delete('name');
//获取
// console.log(m.get('change'));
// console.log(m.get(key));
//清空
// m.clear();
//遍历
for(let v of m){
console.log(v);
}
// console.log(m);
</script>
</body>
</html>
calss类
概述:
ES6 提供了更接近传统语言的写法,引入了 Class(类)这个概念,作为对象的模板。通过 class 关键字,可以定义类。基本上,ES6 的 class 可以看作只是一个语法糖,它的绝大部分功能,ES5 都可以做到,新的 class 写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已;
知识点:
- class 声明类;
- constructor 定义构造函数初始化;
- extends 继承父类;
- super 调用父级构造方法;
- static 定义静态方法和属性;
- 父类方法可以重写;
class初体验:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>类声明</title>
</head>
<body>
<script>
//手机
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);
//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);
</script>
</body>
</html>
class静态成员
静态方法:类相当于实例的原型,所有在类中定义的方法,都会被实例继承。如果在一个方法前,加上static关键字,就表示该方法不会被实例继承,而是直接通过类来调用,这就称为“静态方法”。
静态属性:静态属性指的是Class本身的属性,即Class.propname,而不是定义在实例对象(this)上的属性。ES6使用静态属性和实例属性:
代码实现:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>静态成员</title>
</head>
<body>
<script>
// function Phone(){
// }
// Phone.name = '手机';
// Phone.change = function(){
// console.log("我可以改变世界");
// }
// Phone.prototype.size = '5.5inch';
// let nokia = new Phone();
// console.log(nokia.name);
// // nokia.change();
// console.log(nokia.size);
class Phone{
//静态属性
static name = '手机';
static change(){
console.log("我可以改变世界");
}
}
let nokia = new Phone();
console.log(nokia.name);
console.log(Phone.name);
</script>
</body>
</html>
运行结果:
ES5构造函数实现继承:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>对象继承</title>
</head>
<body>
<script>
//手机
function Phone(brand, price){
this.brand = brand;
this.price = price;
}
Phone.prototype.call = 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.playGame = function(){
console.log("我可以玩游戏");
}
const chuizi = new SmartPhone('锤子',2499,'黑色','5.5inch');
console.log(chuizi);
</script>
</body>
</html>
ES6class类继承:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>类继承-2</title>
</head>
<body>
<script>
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);// Phone.call(this, brand, price)
this.color = color;
this.size = size;
}
photo(){
console.log("拍照");
}
playGame(){
console.log("玩游戏");
}
call(){
console.log('我可以进行视频通话');
}
}
const xiaomi = new SmartPhone('小米',799,'黑色','4.7inch');
// console.log(xiaomi);
xiaomi.call();
xiaomi.photo();
xiaomi.playGame();
</script>
</body>
</html>
子类对父类方法重写:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>ES6class类继承</title>
</head>
<body>
<script>
// ES6class类继承
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;
}
// 子类对父类方法重写
// 直接写,直接覆盖
// 注意:子类无法调用父类同名方法
call(){
console.log("我可以进行视频通话!");
}
photo(){
console.log("我可以拍照!");
}
game(){
console.log("我可以玩游戏!");
}
}
const chuizi = new SmartPhone("小米",1999,"黑色","5.15inch");
console.log(chuizi);
chuizi.call();
chuizi.photo();
chuizi.game();
</script>
</body>
</html>
class中的 get | set
代码实现:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>get 和 set</title>
</head>
<body>
<script>
// get 和 set
class Phone{
get price(){
console.log("价格属性被读取了");
return 'iloveyou';
}
set price(newVal){
console.log('价格属性被修改了');
}
}
//实例化对象
let s = new Phone();
// console.log(s.price);
s.price = 'free';
</script>
</body>
</html>
运行结果:
数值扩展
1. Number.EPSILON:
Number.EPSILON 是 JavaScript 表示的最小精度; EPSILON 属性的值接近于 2.2204460492503130808472633361816E-16;
2. 二进制和八进制:
ES6 提供了二进制和八进制数值的新的写法,分别用前缀 0b 和 0o 表示;
3. Number.isFinite() 与 Number.isNaN() :
Number.isFinite() 用来检查一个数值是否为有限的; Number.isNaN() 用来检查一个值是否为 NaN;
4. Number.parseInt() 与 Number.parseFloat():
ES6 将全局方法 parseInt 和 parseFloat,移植到 Number 对象上面,使用不变;
5. Math.trunc:
用于去除一个数的小数部分,返回整数部分;
6. Number.isInteger:
Number.isInteger() 用来判断一个数值是否为整数;
7. Math.sign
判断一个数到底为正数 负数 还是零
代码实现和相关说明:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>数值扩展</title>
</head>
<body>
<script>
//0. 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))
//1. 二进制和八进制
// let b = 0b1010;
// let o = 0o777;
// let d = 100;
// let x = 0xff;
// console.log(x);
//2. Number.isFinite 检测一个数值是否为有限数
// console.log(Number.isFinite(100));
// console.log(Number.isFinite(100/0));
// console.log(Number.isFinite(Infinity));
//3. Number.isNaN 检测一个数值是否为 NaN
// console.log(Number.isNaN(123));
//4. Number.parseInt Number.parseFloat字符串转整数
// console.log(Number.parseInt('5211314love'));
// console.log(Number.parseFloat('3.1415926神奇'));
//5. Number.isInteger 判断一个数是否为整数
// console.log(Number.isInteger(5));
// console.log(Number.isInteger(2.5));
//6. Math.trunc 将数字的小数部分抹掉
// console.log(Math.trunc(3.5));
//7. Math.sign 判断一个数到底为正数 负数 还是零
console.log(Math.sign(100));
console.log(Math.sign(0));
console.log(Math.sign(-20000));
</script>
</body>
</html>
对象方法扩展
概述:
ES6 新增了一些 Object 对象的方法:
- Object.is 比较两个值是否严格相等,与『===』行为基本一致(+0 与 NaN);
- Object.assign 对象的合并,将源对象的所有可枚举属性,复制到目标对象;
- proto、setPrototypeOf、 setPrototypeOf 可以直接设置对象的原型;
代码实现及相关说明:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>对象方法扩展</title>
</head>
<body>
<script>
//1. Object.is 判断两个值是否完全相等
// console.log(Object.is(120, 120));// ===
// console.log(Object.is(NaN, NaN));// ===
// console.log(NaN === NaN);// ===
//2. Object.assign 对象的合并
// const config1 = {
// host: 'localhost',
// port: 3306,
// name: 'root',
// pass: 'root',
// test: 'test'
// };
// const config2 = {
// host: 'http://atguigu.com',
// port: 33060,
// name: 'atguigu.com',
// pass: 'iloveyou',
// test2: 'test2'
// }
// console.log(Object.assign(config1, config2));
//3. Object.setPrototypeOf 设置原型对象 Object.getPrototypeof
const school = {
name: '尚硅谷'
}
const cities = {
xiaoqu: ['北京','上海','深圳']
}
Object.setPrototypeOf(school, cities);
console.log(Object.getPrototypeOf(school));
console.log(school);
</script>
</body>
</html>
运行结果:待补充
模块化
概述:模块化是指将一个大的程序文件,拆分成许多小的文件,然后将小文件组合起来;
模块化的好处:
模块化的优势有以下几点:
- 防止命名冲突;
- 代码复用;
- 高维护性;
模块化规范产品:
ES6 之前的模块化规范有:
- CommonJS => NodeJS、Browserify;
- AMD => requireJS;
- CMD => seaJS;
ES6 模块化语法:
- 模块功能主要由两个命令构成:export 和 import;
- export 命令用于规定模块的对外接口(导出模块);
- import 命令用于输入其他模块提供的功能(导入模块);
模块导出 | 模块暴露:
// 1.分别暴露 - export关键字
export let school = '尚硅谷';
export function teach() {
console.log("我们可以教给你开发技能");
}
// 2.统一暴露
let school = '尚硅谷';
function findJob(){
console.log("我们可以帮助你找工作!!");
}
// 统一暴露的语法在这里
export {school, findJob};
//3.默认暴露 - default关键字
export default {
school: 'ATGUIGU',
change: function(){
console.log("我们可以改变你!!");
}
}
模块引入 | 使用模块:
//入口文件 -> 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);
m1.teach();
m2.findJob();
m3.default.change();
运行结果:
ES6导入模块语法汇总:
模块化.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>模块化</title>
</head>
<body>
<script type="module">
// 通用方式
// 引入m.js模块内容
import * as m from "./js/m.js";
console.log(m);
console.log(m.school);
m.teach();
// 引入n.js模块内容
import * as n from "./js/n.js";
console.log(n);
console.log(n.school);
n.findJob();
// 引入o.js模块内容
import * as o from "./js/o.js";
console.log(o);
// 注意这里调用方法的时候需要加上default
console.log(o.default.school);
o.default.change();
// 解构赋值形式
import {school,teach} from "./js/m.js";
// 重名的可以使用别名
import {school as xuexiao,findJob} from "./js/n.js";
// 导入默认导出的模块,必须使用别名
import {default as one} from "./js/o.js";
// 直接可以使用
console.log(school);
teach();
console.log(xuexiao);
console.log(one);
console.log(one.school);
one.change();
// 简便形式,只支持默认导出
import oh from "./js/o.js";
console.log(oh);
console.log(oh.school);
oh.change();
</script>
</body>
</html>
ES7新特性
1、includes
判断数组中是否包含某元素,语法:arr.includes(元素值);
概述:
Includes 方法用来检测数组中是否包含某个元素,返回布尔类型值; 判断数组中是否包含某元素,语法:arr.includes(元素值);
代码实现:
<script>
// 老式写法 => 关于if中判断条件
if( type == 1 || type == 2 || type == 3 || type == 4 || ){
//...
}
// includes 妙用
const condition = [1,2,3,4];
if( condition.includes(type) ){
//...
}
</script>
2、指数操作
幂运算的简化写法,例如:2的10次方:2**10;
概述:
在 ES7 中引入指数运算符「**」,用来实现幂运算,功能与 Math.pow 结果相同;幂运算的简化写法,例如:2的10次方:2**10;
代码实现:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>指数操作符</title>
</head>
<body>
<script>
// 指数操作符
console.log(Math.pow(2,10))
console.log(2**10);
</script>
</body>
</html>
ES8新特性
1、async 和 await
概述:
async 和 await 两种语法结合可以让异步代码看起来像同步代码一样;简化异步函数的写法,实现代码的扁平化;
async函数:
概述:
- async 函数的返回值为 promise 对象;
- promise 对象的结果由 async 函数执行的返回值决定;
代码实现:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>async函数</title>
</head>
<body>
<script>
// async函数:异步函数
async function fn(){
// return 123; // 返回普通数据
// 若报错,则返回的Promise对象也是错误的
// throw new Error("出错啦!");
// 若返回的是Promise对象,那么返回的结果就是Promise对象的结果
return new Promise((resolve,reject)=>{
// resolve("成功啦!");
reject("失败啦!");
})
}
const result = fn();
// console.log(result); // 返回的结果是一个Promise对象
// 调用then方法
result.then(value => {
console.log(value);
},reason => {
console.warn(reason);
});
</script>
</body>
</html>
await表达式:
概述:
- await 必须写在 async 函数中;
- await 右侧的表达式一般为 promise 对象;
- await 返回的是 promise 成功的值;
- await 的 promise 失败了, 就会抛出异常, 需要通过 try…catch 捕获处理; 备注: promise如果返回 reject 需要用try catch 来捕获错误
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>await表达式</title>
</head>
<body>
<script>
// async函数 + await表达式:异步函数
// 创建Prmise对象
const p = new Promise((resolve,reject)=>{
resolve("成功啦!");
})
async function fn(){
// await 返回的是 promise 成功的值
let result = await p;
console.log(result); // 成功啦!
}
fn();
</script>
</body>
</html>
async 和 await 读取文件案例:
代码实现:
/ 导入模块
const fs = require("fs");
// 读取
function readText() {
return new Promise((resolve, reject) => {
fs.readFile("../resources/text.txt", (err, data) => {
//如果失败
if (err) reject(err);
//如果成功
resolve(data);
})
})
}
function readTest1() {
return new Promise((resolve, reject) => {
fs.readFile("../resources/test1.txt", (err, data) => {
//如果失败
if (err) reject(err);
//如果成功
resolve(data);
})
})
}
function readTest2() {
return new Promise((resolve, reject) => {
fs.readFile("../resources/test2.txt", (err, data) => {
//如果失败
if (err) reject(err);
//如果成功
resolve(data);
})
})
}
//声明一个 async 函数
async function main(){
//获取为学内容
let t0 = awai readText();
//获取插秧诗内容
let t1 = await readTest1();
// 获取观书有感
let t2 = await readTest2();
console.log(t0.toString());
console.log(t1.toString());
console.log(t2.toString());
}
main();
async 和 await 结合发送ajax请求:
代码实现:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>async 和 await 结合发送ajax请求</title>
</head>
<body>
<script>
// async 和 await 结合发送ajax请求
function sendAjax(url){
return new Promise((resolve,reject)=>{
// 1、创建对象
const x = new XMLHttpRequest();
// 2、初始化
x.open("GET",url);
// 3、发送
x.send();
// 4、事件绑定
x.onreadystatechange = function(){
if(x.readyState == 4){
if(x.status>=200 && x.status<=299){
// 成功
resolve(x.response);
}else{
// 失败
reject(x.status);
}
}
}
});
}
// 测试
// const result = sendAjax("https://api.apiopen.top/getJoke");
// result.then(value=>{
// console.log(value);
// },reason=>{
// console.warn(reason);
// })
// 使用async和await
async function main(){
let result = await sendAjax("https://api.apiopen.top/getJoke");
console.log(result);
}
main();
</script>
</body>
</html>
2、对象方法扩展
Object.values、Object.entries和Object.getOwnPropertyDescriptors:
- Object.values()方法:返回一个给定对象的所有可枚举属性值的数组;
- Object.entries()方法:返回一个给定对象自身可遍历属性 [key,value] 的数组;
- Object.getOwnPropertyDescriptors()该方法:返回指定对象所有自身属性的描述对象;
代码实现:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>对象方法扩展</title>
</head>
<body>
<script>
// 对象方法扩展
let school = {
name : "訾博",
age : 24,
sex : "男"
}
// 获取对象所有的键
console.log(Object.keys(school));
// 获取对象所有的值
console.log(Object.values(school));
// 获取对象的entries
console.log(Object.entries(school));
// 创建map
const map = new Map(Object.entries(school));
console.log(map);
console.log(map.get("name"));
// 返回指定对象所有自身属性的描述对象
console.log(Object.getOwnPropertyDescriptors(school));
// 参考内容:
const obj = Object.create(null,{
name : {
// 设置值
value : "訾博",
// 属性特性
writable : true,
configuration : true,
enumerable : true
}
});
</script>
</body>
</html>