1 ES介绍
2 ES6的新特性
2.1 let关键字
2.1.1 声明变量
let a;
let b,c,d;
let e=100;
let f=521,g="iloveyou",h=[]
2.1.1 特点
let 关键字用来声明变量,使用 let 声明的变量有几个特点:
- 变量不能重复声明
let star='罗志祥';
let star='小猪' //error
//但使用var 重复定义 star 不会报错,因此要使用let,防止变量污染
- let有块级作用域
全局,函数,eval
{
let girl='周扬青'
}
console.log(girl) //error
不仅仅针对花括号,例如if 、else、while、for里面
- 不存在变量提升
console.log(song) //error
let song='恋爱达人'
//var可变量提升,在变量定义之前可以使用,不会报错
- 不影响作用域链
{
let school='abc'
function fn(){
console.log(school) //abc
}
fn()
}
应用场景:以后声明变量使用 let 就对了
2.1.3 案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div>
<div class="item" style="width: 50px;height: 50px;background-color: red"></div>
<div class="item" style="width: 50px;height: 50px;background-color: red"></div>
<div class="item" style="width: 50px;height: 50px;background-color: red"></div>
</div>
<script>
let items=document.getElementsByClassName("item");
for (var i=0;i<items.length;i++){
items[i].οnclick=function (){
items[i].style.backgroundColor='pink';
}
}
console.log(windows.i) //3 error
// 当var=3的时候,点击事件开始向外层作用域找,找不到,就是windows.i,此时是3,
// 如果是let i,具有块级作用域,所以每一次触碰事件的i都是不同的。
// 将var换成let即不会报错,功能正常
</script>
</body>
</html>
2.2 const 特性
2.2.1 声明变量
const ABC = 'abc'
2.2.2 特点
const 关键字用来声明常量,const 声明有以下特点:
- 一定要赋初始值
const A; //error
- 一般常量使用大写(潜规则)
- 常量的值不能修改
- 也具有块级作用域
{
const pyaler = 'uzi'
}
console.log(player) //error
- 对于数组和对象的元素修改,不算作对常量的修改
const TEAM = ['uzi','MXLG','Ming','Letme'];
TEAM.push('Meiko'); //不报错,常量地址没有发生变化
TEAM = 100 //error
2.2.3 注意和应用场景
注意: 对象属性修改和数组元素变化不会出发 const 错误
应用场景:声明对象类型使用 const,非对象类型声明选择 let
2.3 变量的解构赋值
ES6 允许按照一定模式从数组和对象中提取值,对变量进行赋值,这被称为解构赋值。
数组的解构(不常用)
const F4 = ['小沈阳','刘能','赵四','宋小宝']
let [xiao,liu,zhao,song] = F4;
console.log(xiao)
console.log(liu)
console.log(zhao)
console.log(song)
对象的解构(常用)
const zhao = {
name : '赵本山',
age: '不详',
xiaopin: function(){
console.log("我可以演小品")
}
}
let {name,age,xiaopin} = zhao;
console.log(name);
console.log(age);
console.log(xiaopin);
xiaopin();
// 不用以上方法的话,使用xiaopin方法时,需要 zhao.xiaopin()
// 使用以上方法结构,只需要 xiaopin() ,不用带前面的 zhao.
复杂结构
let wangfei = {
name: '王菲',
age: 18,
songs: ['红豆', '流年', '暧昧', '传奇'],
history: [
{name: '窦唯'},
{name: '李亚鹏'},
{name: '谢霆锋'}
]
};
let {songs: [one, two, three], history: [first, second, third]} =
wangfei;
注意:频繁使用对象方法、数组元素,就可以使用解构赋值形式
2.4 模板字符串
模板字符串(template string)是增强版的字符串,用反引号(`)标识,特点:
- 字符串中可以出现换行符
- 可以使用 ${xxx} 形式输出变量
// 声明
let str = `我也是一个字符串`
console.log(str,typeof str);
// 特性1:内容中可以直接出现换行符
// 否则之前使用 ""+ 进行拼接
let str = `<ul>
<li>沈腾</li>
<li>玛丽</li>
<li>魏翔</li>
<li>艾伦</li>
</ul>`;
// 特性2:变量拼接
let lovest = '魏翔';
let out = `${lovest}在前几年离开了开心麻花`;
console.log(out)
注意:当遇到字符串与变量拼接的情况使用模板字符串
2.5 简化对象写法
ES6 允许在大括号里面,直接写入变量和函数,作为对象的属性和方法。这样的书写更加简洁。
属性名和变量名相同的话,可以进行简化。
let name = '尚硅谷';
let slogon = '永远追求行业更高标准';
let improve = function () {
console.log('可以提高你的技能');
}
//属性和方法简写
let atguigu = {
name, //name:name, 简写成 name
slogon, //slogon:slogon, 简写成 slogon
improve,
change() {
console.log('可以改变你')
}
}
注意:对象简写形式简化了代码,所以以后用简写就对了
2.6 箭头函数
ES6 允许使用「箭头」(=>)定义函数。
/**
* 1. 通用写法
*/
let fn = (arg1, arg2, arg3) => {
return arg1 + arg2 + arg3;
}
fn(1,2,3)
2.6.1 特性
- this是静态的,this始终指向函数声明时所在作用域下的this的值
function A(){
console.log(this.name)
}
let B = () => {
console.log(this.name);
}
window.name = '尚硅谷';
const school = {
name: 'ATGUIGU'
}
//直接调用
A() //尚硅谷
B() //尚硅谷
//call 改变作用域
A.call(school); //ATGUIGU
B.call(school); //尚硅谷 箭头函数的this值未改变
- 不能作为构造实例化对象
let A = (name,age) => {
this.name=name;
this.age=age;
}
let me = new A('xiao',123);
console.me //error
- 不能使用arguments变量
(arguments变量是用来保存实参的)
let fn = () => {
console.log(arguments);
}
fn(1,2,3) //error
- 简写
- 省略小括号,当形参有且只有一个的时候
let add = n => {
return n + 1;
}
- 省略花括号,当代码体只有一条语句的时候,此时return也必须省略
let add = n => n+1;
注意:箭头函数不会更改 this 指向,用来指定回调函数会非常合适
2.6.2 实战
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>箭头函数实践</title>
<style>
div {
width: 200px;
height: 200px;
background: #58a;
}
</style>
</head>
<body>
<div id="ad"></div>
<script>
//需求-1 点击 div 2s 后颜色变成『粉色』
//获取元素
let ad = document.getElementById('ad');
// 绑定事件
// 方法1:
ad.addEventListener("click", function(){
//保存 this 的值
let _this = this; //将外层的this值进行保存,下面函数里面就可以用了,
// 否则下面函数的this不同,并没有包含style属性,就会报错
//定时器
setTimeout(function(){
//修改背景颜色 this
// console.log(this);
_this.style.background = 'pink';
}, 2000);
});
// 方法2: 使用箭头函数,因为箭头函数是静态的,始终指向创建时的this值
ad.addEventListener("click", function(){
setTimeout(() => {
//修改背景颜色 this
this.style.background = 'pink';
}, 2000);
});
//需求-2 从数组中返回偶数的元素
const arr = [1,6,9,10,100,25];
//方法1:
// const result = arr.filter(function(item){
// if(item % 2 === 0){
// return true;
// }else{
// return false;
// }
// });
// 方法2: 使用箭头函数
const result = arr.filter(item => item % 2 === 0);
console.log(result);
// 箭头函数适合与 this 无关的回调. 定时器, 数组的方法回调
// 箭头函数不适合与 this 有关的回调. 事件回调, 对象的方法
</script>
</body>
</html>
2.6.3 函数参数默认值
- 可以给形参赋初始值,一般位置要靠后(潜规则)
function add(a,b,c=12){
return a+b+c;
}
let result = add (1,2);
console.log(result) // 15
- 与解构赋值结合
function A({host='127.0.0.1',username,password,port}){
console.log(host+username+password+port)
}
A({
host:"shangguigu.com",
username:'ran',
password:'123456',
port:3306
})
// 传参了,使用传的值,没传参使用默认值
2.7 rest 参数
ES6 引入 rest 参数,用于获取函数的实参,用来代替 arguments
/**
* 作用与 arguments 类似
*/
function add(...args){
console.log(args);
}
add(1,2,3,4,5); //得到的是一个数组,可以使用数字的一些方法:filter、some、every、map
/**
* rest 参数必须是最后一个形参
*/
function minus(a,b,...args){
console.log(a,b,args);
}
minus(100,1,2,3,4,5,19);
注意:rest 参数非常适合不定个数参数函数的场景
2.8 spread 扩展运算符
扩展运算符(spread)也是三个点(…)。它好比 rest 参数的逆运算,将一个数组转为用逗号分隔的参数序列,对数组进行解包。
特性
const tfboys=['AA','BB','CC']
function chunwan(){
console.log(arguments);
}
chunwan(...tfboys); //0:'AA' 1:'BB' 2:'CC'
rest 参数 和 spread区别:
rest 参数 : function add(…args) 是放在函数传参
spread: fn(…tfboys) 是放在调用函数时
应用
- 数组的合并
const A = ['aa','bb'];
const B = ['cc','dd'];
//方法1:
const C = A.concat(B)
console.log(C) //[aa,bb,cc,dd]
//方法2:(推荐)
const C = [...A,...B];
console.log(C) //[aa,bb,cc,dd]
- 数组的克隆(浅拷贝)
const A = ['a','b','c'];
const B = [...A];
console.log(B) //[a,b,c]
- 将伪数组转换为真正的数组
const A = documents.querySelectorAll('div');
const B = [...A];
console.log(B) // [div,div,div]
2.9 Symbol
2.9.1 Symbol 基本使用
ES6 引入了一种新的原始数据类型 Symbol,表示独一无二的值。它是JavaScript 语言的第七种数据类型,是一种类似于字符串的数据类型。
Symbol 特点:
- Symbol 的值是唯一的,用来解决命名冲突的问题
- Symbol 值不能与其他数据进行运算
- Symbol 定义 的 对象属 性 不能 使 用 for…in 循 环遍 历 ,但 是可 以 使 用
Reflect.ownKeys 来获取对象的所有键名
// 1. 创建
//创建 Symbol
let s1 = Symbol();
console.log(s1, typeof s1); //内部实现唯一性,我们看不到
//添加标识的 Symbol
let s2 = Symbol('尚硅谷');
let s2_2 = Symbol('尚硅谷');
console.log(s2 === s2_2); //false
//使用 Symbol for 定义
let s3 = Symbol.for('尚硅谷');
let s3_2 = Symbol.for('尚硅谷');
console.log(s3 === s3_2); //true
// 2. 不能与其他数据进行运算
let result = s + 100 //error
let result = s > 100 //error
let result = s + s //error
// 数据类型
// USONB you are so niubility
u undefined
s string symbol
o object
n bull number
b boolean
// 3.Symbol内置值
class Person {
static [Symbol.hasInstance](param){
console.log(param);
console.log("我被用来检测了");
return false;
}
}
let o = {};
console.log(o instanceof Person); //我被用来检测了,false
注: 遇到唯一性的场景时要想到 Symbol
2.9.2 应用
- 给对象添加方法方式一:
let game = {
name : 'ran'
}
let methods = {
up:Symbol()
down:Symbol()
}
game[methods.up]=function(){
console.log('aaa');
}
game[methods.down]=function(){
console.log('bbb');
}
console.log(game) // name: 'ran',Symbol(),Symbol()
- 给对象添加方法方式二
let youxi = {
name: '狼人杀',
[Symbol('say')]:function(){
console.log('阿萨德')
}
}
console.log(youxi) // name:'狼人杀',Symbol(say)
2.9.3 Symbol 内置值
除了定义自己使用的 Symbol 值以外,ES6 还提供了 11 个内置的 Symbol 值,指向语言内部使用的方法。可以称这些方法为魔术方法,因为它们会在特定的场景下自动执行。
2.10 迭代器
迭代器(Iterator)就是一种机制。它是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署 Iterator 接口,就可以完成遍历操作。
-
ES6 创造了一种新的遍历命令 for…of 循环,Iterator 接口主要供 for…of 消费
-
原生具备 iterator 接口的数据(可用 for of 遍历)
a) Array
b) Arguments
c) Set
d) Map
e) String
f) TypedArray
g) NodeList
- 工作原理
a) 创建一个指针对象,指向当前数据结构的起始位置
b) 第一次调用对象的 next 方法,指针自动指向数据结构的第一个成员
c) 接下来不断调用 next 方法,指针一直往后移动,直到指向最后一个成员
d) 每调用 next 方法返回一个包含 value 和 done 属性的对象
注: 需要自定义遍历数据的时候,要想到迭代器
const xiyou=['AA','BB','CC','DD'];
//for in保存的是键名,for of保存的是键值
// for(let v of xiyou){
// console.log(v) // 'AA','BB','CC','DD'
// }
let iterator = xiyou[Symbol.iterator]();
console.log(iterator.next()); //{{value:'唐僧',done:false}}
console.log(iterator.next()); //{{value:'孙悟空',done:false}}
const banji = {
name : "终极一班",
stus: [
'aa',
'bb',
'cc',
'dd'
],
[Symbol.iterator](){
let index = 0;
let _this = this;
return {
next: () => {
if(index < this.stus.length){
const result = {value: _this.stus[index],done: false};
//下标自增
index++;
//返回结果
return result;
}else {
return {value: underfined,done:true};
}
}
}
}
}
for(let v of banji){
console.log(v); // aa bb cc dd
}
2.11 生成器
生成器函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同
// 生成器其实就是一个特殊的函数
//异步编程 纯回调函数 node 方式 ajax mongodb
function * gen (){ //函数名和function中间有一个 *
yield '耳朵'; //yield是函数代码的分隔符
yield '尾巴';
yield '真奇怪';
}
let iterator = gen();
console.log(iteretor.next());
//{value:'耳朵',done:false} next()执行第一段,并且返回yield后面的值
console.log(iteretor.next()); //{value:'尾巴',done:false}
console.log(iteretor.next()); //{value:'真奇怪',done:false}
代码说明:
- *的位置没有限制
- 生成器函数返回的结果是迭代器对象,调用迭代器对象的 next 方法可以得到
yield 语句后的值 - yield 相当于函数的暂停标记,也可以认为是函数的分隔符,每调用一次 next
方法,执行一段代码 - next 方法可以传递实参,作为 yield 语句的返回值
2.11.1 应用
- 生成器函数的参数传递
function * gen(args){
console.log(args);
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());
console.log(iterator.next('BBB')); //next中传入的BBB将作为yield 111的返回结果
console.log(iterator.next('CCC')); //next中传入的CCC将作为yield 222的返回结果
console.log(iterator.next('DDD')); //next中传入的DDD将作为yield 333的返回结果
- 实例1:用生成器函数的方式解决回调地狱问题
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();
- 实例2:模拟异步获取数据
function one(){
setTimeout(()=>{
let data='用户数据';
iterator.next(data)
},1000)
}
function two(){
setTimeout(()=>{
let data='订单数据';
iterator.next(data)
},2000)
}
function three(){
setTimeout(()=>{
let data='商品数据';
iterator.next(data)
},3000)
}
function * gen(){
let users=yield one();
console.log(users)
let orders=yield two();
console.log(orders)
let goods=yield three();
console.log(goods)
}
let iterator = gen();
iterator.next();
2.12 Promise
Promise 主要解决回调地狱的问题,是 ES6 引入的异步编程的新解决方案。语法上 Promise 是一个构造函数,用来封装异步操作并可以获取其成功或失败的结果。
Promise的三种状态:初始化,成功,失败
- Promise 构造函数(基本用法)
<script>
const p =new Promise((resolve, reject)=>{
setTimeout(()=>{
let data='数据库数据'
// resolve(data); //调用成功
reject(data); //调用失败
},1000)
})
p.then(function (value){ //成功则执行第一个回调函数,失败则执行第二个
console.log(value)
},function (reason){
console.error(reason)
})
</script>
- promise读取文件
//1. 引入 fs 模块
const fs = require('fs');
//2. 调用方法读取文件 (方法1)(问题:会存在回调地狱的问题)
// fs.readFile('./resources/为学.md', (err, data)=>{
// //如果失败, 则抛出错误
// if(err) throw err;
// //如果没有出错, 则输出内容
// console.log(data.toString());
// });
//3. 使用 Promise 封装 (方法2)
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("读取失败!!");
});
- 发送 AJAX 请求
<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>
- Promise.prototype.then 方法
<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 对象
// 内部返回的promise对象的状态决定then返回的promise状态
return new Promise((resolve, reject) => {
// resolve('ok');
reject('error');
});
//3. 抛出错误,状态为 rejected,值为throw抛出的值
// throw new Error('出错啦!');
throw '出错啦!';
}, reason => {
console.warn(reason);
});
//链式调用,可以杜绝回调地狱的问题
p.then(value => {
}).then(value => {
});
</script>
- Promise.prototype.catch 方法
//catch()函数只有一个回调函数,意味着如果Promise对象状态为失败就会调用catch()方法并且调用回调函数
<script>
const p = new Promise((resolve, reject)=>{
setTimeout(()=>{
//设置 p 对象的状态为失败, 并设置失败的值
reject("出错啦!");
}, 1000)
});
// 方法1:
// p.then(function(value){}, function(reason){
// console.error(reason);
// });
// 方法2:(语法糖)
p.catch(function(reason){
console.warn(reason);
});
</script>
- 应用:读取多个文件
//引入 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 实现
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'));
});
2.13 Set
ES6 提供了新的数据结构 Set(集合)。它类似于数组,但成员的值都是唯一的,集合实现了 iterator 接口,所以可以使用『扩展运算符…』和『for…of…』进行遍历,集合的属性和方法:
- size 返回集合的元素个数
- add 增加一个新元素,返回当前集合
- delete 删除元素,返回 boolean 值
- has 检测集合中是否包含某个元素,返回 boolean 值
- clear 清空集合,返回 undefined
<script>
//创建一个空集合
let s = new Set();
//创建一个非空集合
let s2 = new Set(['A','B','C','D'])
//元素个数
console.log(s2.size);
//添加新的元素
s2.add('E');
//删除元素
s2.delete('A')
//检测是否存在某个值,有true,没有false
console.log(s2.has('C'));
//清空集合
s2.clear()
console.log(s2);
for(let v of s2){
console.log(v);
}
</script>
//应用
<script>
let 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 result2 = [...new Set(arr)].filter(item => new Set(arr2).has(item))
console.log(result2);
//3.并集
let result3=[...new Set([...arr,...arr2])]
console.log(result3);
//4.差集 是交集的取反
let result4= [...new Set(arr)].filter(item => !(new Set(arr2).has(item)))
console.log(result4);
</script>
2.14 Map
ES6 提供了 Map 数据结构。它类似于对象,也是键值对的集合。但是“键”
的范围不限于字符串,各种类型的值(包括对象)都可以当作键。Map 也实现了
iterator 接口,所以可以使用『扩展运算符…』和『for…of…』进行遍历。Map 的属
性和方法:
- size 返回 Map 的元素个数
- set 增加一个新元素,返回当前 Map
- get 返回键名对象的键值
- has 检测 Map 中是否包含某个元素,返回 boolean 值
- clear 清空集合,返回 undefined
<script>
//创建一个空 map
let m = new Map();
//添加元素 第一个参数是键,第二个参数是值
m.set('name','ran');
m.set('change',()=>{
console.log('改变!')
})
let key={
school:'atguigu'
}
m.set(key,['北京','西安']);
//size 长度
console.log(m.size);
//删除
m.delete('name');
//获取
console.log(m.get('change'));
//检测是否有该映射
console.log(m2.has('age'));
// 清空
// m.clear()
//遍历
for(let v of m){
console.log(v);
}
</script>
2.15 class 类
ES6 提供了更接近传统语言的写法,引入了 Class(类)这个概念,作为对象的模板。通过 class 关键字,可以定义类。基本上,ES6 的 class 可以看作只是一个语法糖,它的绝大部分功能,ES5 都可以做到,新的 class 写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。
知识点:
- class 声明类
- constructor 定义构造函数初始化
- extends 继承父类
- super 调用父级构造方法
- static 定义静态方法和属性
- 父类方法可以重写
//父类
class Phone {
//构造方法
// constructor 这个名字不能修改,在进行new Phone时,自动执行
constructor(brand, color, price) {
this.brand = brand;
this.color = color;
this.price = price;
}
//对象方法,只能使用 方法名(){} 的写法,不能使用 方法名:function(){}
call() {
console.log('我可以打电话!!!')
}
}
//子类
class SmartPhone extends Phone {
constructor(brand, color, price, screen, pixel) {
super(brand, color, price);
this.screen = screen;
this.pixel = pixel;
}
//子类方法
photo(){
console.log('我可以拍照!!');
}
playGame(){
console.log('我可以玩游戏!!');
}
//方法重写
call(){
console.log('我可以进行视频通话!!');
}
//静态方法
static run(){
console.log('我可以运行程序')
}
static connect(){
console.log('我可以建立连接')
}
}
//实例化对象
const Nokia = new Phone('诺基亚', '灰色', 230);
const iPhone6s = new SmartPhone('苹果', '白色', 6088,
'4.7inch','500w');
//调用子类方法
iPhone6s.playGame();
//调用重写方法
iPhone6s.call();
//调用静态方法
SmartPhone.run();
2.15.1 特性
<script>
//=================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);
//=================ES6========================
class shouji {
// constructor 这个名字不能修改,在进行new Phone时,自动执行
constructor(brand,price) {
this.brand=brand;
this.price=price
}
//对象方法,只能使用 方法名(){} 的写法,不能使用 方法名:function(){}
call(){
console.log('我可以打电话')
}
}
let A = new shouji('1+',1999);
console.log(A)
</script>
2.15.2 静态成员
<script>
//=================ES5========================
// function Phone(){
// }
// Phone.name = '手机';
// Phone.change = function(){
// console.log("我可以改变世界");
// }
// Phone.prototype.size = '5.5inch';
// let nokia = new Phone();
// console.log(nokia.name);
// // nokia.change(); //访问不到change方法,原因:只能访问到原型链上的方法
// console.log(nokia.size);
//=================ES6========================
class Phone{
//静态属性
static name = '手机';
static change(){
console.log("我可以改变世界");
}
}
let nokia = new Phone();
console.log(nokia.name); // 都可以访问到
console.log(Phone.name);
</script>
2.15.3 继承
ES5构造函数继承
<script>
//=================ES5========================
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('我可以拍照');
}
const chuizi = new SmartPhone('锤子',2499,'黑色','5.5inch')
console.log(chuizi);
</script>
Class的类继承
<script>
//=================ES6========================
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); // 等价于ES5中的Phone.call(this,brand,price);
this.color=color;
this.size=size;
}
photo(){
console.log('拍照');
}
playGame(){
console.log('打游戏');
}
}
const xiaomi=new SmartPhone('小米',1999,'黑色','4.7inch')
xiaomi.call();
xiaomi.photo();
xiaomi.playGame();
</script>
2.15.4 子类对父类方法的重写
<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);
this.color=color;
this.size=size;
}
photo(){
console.log('拍照');
}
playGame(){
console.log('打游戏');
}
//重写!
call(){
console.log('我可以进行视频通话')
}
}
const xiaomi=new SmartPhone('小米',1999,'黑色','4.7inch')
xiaomi.call();
xiaomi.photo();
xiaomi.playGame();
</script>
2.15.5 get和set设置
<script>
class Phone{
get price(){
console.log("价格被读取了")
return 'I LOVE YOU'
}
// 注意:set需要传参,否则会报错
set price(val){
console.log('价格被修改了')
return val;
}
}
//实例化对象
let s = new Phone();
s.price=12
// console.log(s.price) //其实是调用price方法
</script>
2.16 数值扩展
<script>
// 1.Number.EPSILON
// Number.EPSILON 是 JavaScript的最小精度,属性的值接近于 2.22044...E-16
// 判断两个值如果小于 Number.EPSILON 则认为 这两个值相等
// 主要用于浮点数
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)) //false
console.log(equal(0.1+0.2,0.3)) //true
//2. 二进制和八进制
let b = 0b1010; //2进制
let o = 0o777; //8进制
let d = 100; //10进制
let x = 0xff; //16进制
console.log(x) //255
//3. Number.isFinite 检测一个数是否为有限数
console.log(Number.isFinite(100)); //true
console.log(Number.isFinite(100/0)); //false
console.log(Number.isFinite(Infinity)); //false
//4. 检测一个数值是否为NaN
console.log(Number.isNaN(123)) //false
//5. 字符串转整数
console.log(Number.parseInt('5213123love')); //5213123
console.log(Number.parseFloat('5.123123神器')); //5.123123
//6. 判断是否为整数
console.log(Number.isInteger(5)); //true
console.log(Number.isInteger(2.5)); //false
//7. 将小数部分抹除
console.log(Math.trunc(3.45345345345)) //3
//8. 检测一个数到底是正数、负数、还是0
console.log(Math.sign(100)) //1
console.log(Math.sign(0)) //0
console.log(Math.sign(-123)) //-1
</script>
2.16.1 二进制和八进制
ES6 提供了二进制和八进制数值的新的写法,分别用前缀 0b 和 0o 表示。
2.16.2 Number.isFinite() 与 Number.isNaN()
Number.isFinite() 用来检查一个数值是否为有限的
Number.isNaN() 用来检查一个值是否为 NaN
2.16.3 Number.parseInt() 与 Number.parseFloat()
ES6 将全局方法 parseInt 和 parseFloat,移植到 Number 对象上面,使用不变。
2.16.4 Math.trunc
用于去除一个数的小数部分,返回整数部分。
2.16.5 Number.isInteger
Number.isInteger() 用来判断一个数值是否为整数
2.17 对象扩展
ES6 新增了一些 Object 对象的方法
- Object.is 比较两个值是否严格相等,与『===』行为基本一致(+0 与 NaN)
- Object.assign 对象的合并,将源对象的所有可枚举属性,复制到目标对象
- proto、setPrototypeOf、 setPrototypeOf 可以直接设置对象的原型
<script>
//1.Object.is 判断两个值是否完全相等
// 跟全等号=== 类似,区别在于:全等号NaN === NaN 是false
console.log(Object.is(120,120)) //true
console.log(Object.is(NaN,NaN)) //true
//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'
}
//将b合并到a
// 如果a,b里面都有的元素,b会覆盖a中的元素
// 如果a里面有,b里面没有的,保留;其他有的元素覆盖a的
// 如果b里面有,a里面没有的,保留;其他有的元素覆盖a的
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)) //获取原型 {xiaoqu: Array(2)}
console.log(school) //{name: "尚硅谷"}
</script>
2.18 模块化
模块化是指将一个大的程序文件,拆分成许多小的文件,然后将小文件组合起来。
2.18.1 模块化的好处
模块化的优势有以下几点:
- 防止命名冲突
- 代码复用
- 高维护性
2.18.2 模块化规范产品
ES6 之前的模块化规范有:
- CommonJS => NodeJS、Browserify
- AMD => requireJS
- CMD => seaJS
2.18.3 ES6 模块化语法
模块功能主要由两个命令构成:export 和 import。
- export 命令用于规定模块的对外接口
- import 命令用于输入其他模块提供的功能
导出语法汇总
- 分别暴露
// m1.js
export let school = '尚硅谷'
export function teach(){
console.log('教技能')
}
// index.html
<script type="module">
import * as m1 from "./src/js/m1.js";
console.log(m1);
</script>
- 统一暴露
// m2.js
//统一暴露
let school = '尚硅谷';
function findjob(){
console.log('找工作吧');
}
export {school,findjob}
// index.html
<script type="module">
import * as m2 from "./src/js/m2.js";
console.log(m2);
</script>
- 默认暴露
//m3.js
//默认暴露
export default {
school:'ATGUIGU',
change:function(){
console.log('我们可以改变你')
}
}
// index.html
<script type="module">
import * as m3 from "./src/js/m3.js";
console.log(m3);
</script>
引入语法汇总
- 通用导入方式
import * as m1 from "./src/js/m1.js"
import * as m2 from "./src/js/m2.js"
import * as m3 from "./src/js/m3.js"
- 解构赋值方式
import {school,teach} from "./src/js/m1.js"
import {school as guigu,findJob} from "./src/js/m2.js"
import {default as m3 } from "./src/js/m3.js" // 必须给default起个别名
-
简便形式(只针对默认暴露)
只能针对默认暴露
import m3 from "./src/js/m3.js"
2.18.6 模块化方式2
// app.js
import * as m1 from "./src/js/m1.js"
import * as m2 from "./src/js/m2.js"
import * as m3 from "./src/js/m3.js"
//index.html
//不推荐 原因:浏览器的兼容问题
<script src="./src/js/app.js" type=modeule></script>
// 推荐 把es6转化为es5的语法
<!--
1. 安装工具 npm i babel-cli babel-preset-env browserify(webpack)(二选一) -D
2. 编译 npx babel src/js -d dist/js(要保存的文件夹) --presets=babel-preset-env
3. 打包 npx browserify dist/js/app.js(输入的文件) -o dist/bundle.js(输出的位置)
-->
<script src="dist/bundle.js"></script>
3 ES7 新特性
3.1 Array.prototype.includes
Includes 方法用来检测数组中是否包含某个元素,返回布尔类型值
<script>
//include 比 indexOf方便,indexOf如果是没有值返回的是-1
const mingzhu = ['西游记','红楼梦','水浒传','三国演义']
console.log(mingzhu.includes('西游记')) //true
console.log(mingzhu.includes('金瓶梅')) //false
</script>
3.2 指数操作符
在 ES7 中引入指数运算符「**」,用来实现幂运算
,功能与 Math.pow 结果相同
<script>
//** 幂运算
console.log(2**10) // 1024
console.log(Math.pow(2,10)) //1024
</script>
4 ES8 新特性
4.1 async 和 await
async 和 await 两种语法结合可以让异步代码像同步代码一样
4.1.1 async 函数
- async 函数的返回值为 promise 对象,
- promise 对象的结果由 async 函数执行的返回值决定
async function fn(){
//1.如果返回的是一个非Promise的对象,则fn()返回的结果就是成功状态的Promise对象,值为返回值
return "尚硅谷";
return ;
//2.如果返回的是一个Promise对象,则fn()返回的结果与内部Promise对象的结果一致
throw new Error("出错了")
//3.如果返回的是抛出错误,则fn()返回的就是失败状态的Promise对象
return new Promise((resolve,reject)=>{
resolve('成功的数据');
// reject("失败的错误")
});
}
const result = fn();
result.then(value=>{
console.log(value) //成功的数据
},reason=>{
console.log(reason)
})
4.1.2 await 表达式
- await 必须写在 async 函数中,async里面可以没有await
- await 右侧的表达式一般为 promise 对象
- await 返回的是 promise 成功的值
- await 的 promise 失败了, 就会抛出异常, 需要通过 try…catch 捕获处理
<script>
//创建Promise对象
const p = new Promise((resolve, reject) => {
// resolve("成功的值")
reject("失败了")
})
//await 必须放在async函数中
async function main() {
try {
let res = await p;
console.log(res);
} catch (e) {
console.log(e);
}
}
//调用函数
main() //失败了
</script>
async 和await 结合读取文件
//1. 引入 fs 模块
const fs = require("fs");
//读取『为学』
function readWeiXue() {
return new Promise((resolve, reject) => {
fs.readFile("./resources/为学.md", (err, data) => {
//如果失败
if (err) reject(err);
//如果成功
resolve(data);
})
})
}
function readChaYangShi() {
return new Promise((resolve, reject) => {
fs.readFile("./resources/插秧诗.md", (err, data) => {
//如果失败
if (err) reject(err);
//如果成功
resolve(data);
})
})
}
function readGuanShu() {
return new Promise((resolve, reject) => {
fs.readFile("./resources/观书有感.md", (err, data) => {
//如果失败
if (err) reject(err);
//如果成功
resolve(data);
})
})
}
//声明一个 async 函数
async function main(){
//获取为学内容
let weixue = await readWeiXue();
//获取插秧诗内容
let chayang = await readChaYangShi();
// 获取观书有感
let guanshu = await readGuanShu();
console.log(weixue.toString());
console.log(chayang.toString());
console.log(guanshu.toString());
}
main();
发送AJAX请求
<script>
// 发送 AJAX 请求, 返回的结果是 Promise 对象
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 < 300) {
//成功啦
resolve(x.response);
}else{
//如果失败
reject(x.status);
}
}
}
})
}
//promise then 方法测试
// sendAJAX("https://api.apiopen.top/getJoke").then(value=>{
// console.log(value);
// }, reason=>{})
// async 与 await 测试 axios
async function main(){
//发送 AJAX 请求
let result = await sendAJAX("https://api.apiopen.top/getJoke");
//再次测试
let tianqi = await sendAJAX('https://www.tianqiapi.com/api/?version=v1&city=%E5%8C%97%E4%BA%AC&appid=23941491&appsecret=TXoD5e8P')
console.log(tianqi);
}
main();
</script>
4.2 Object.values 和 Object.entries
- Object.values()方法返回一个给定对象的所有可枚举属性值的数组
- Object.entries()方法返回一个给定对象自身可遍历属性 [key,value] 的数组
4.3 Object.getOwnPropertyDescriptors
该方法返回指定对象所有自身属性的描述对象
<script>
const school = {
name:'尚硅谷',
cities:['北京','上海','深圳'],
xueke:['前端','Java','大数据','运维']
};
//获取对象所有的键
console.log(Object.keys(school));
//获取对象所有的值
console.log(Object.values(school));
//entries,用来创建map
console.log(Object.entries(school));
console.log(new Map(Object.entries(school)))
//对象属性的描述对象,即获取name的值
//主要用于拷贝时,拷贝一份与原来对象相同属性的对象
console.log(Object.getOwnPropertyDescriptor(school))
const obj = Object.create(null,{
name:{
value:'尚硅谷',
//属性特性
writable:true, // 是否可写
configurable:true, //是否可配置
enumerable:true, //是否可枚举
}
})
</script>
5 ES9 新特性
5.1 Rest/Spread 属性
Rest 参数与 spread 扩展运算符在 ES6 中已经引入,不过 ES6 中只针对于数组,
在 ES9 中为对象提供了像数组一样的 rest 参数和扩展运算符
<script>
function connect({host,port,...user}){
console.log(host);
console.log(port);
console.log(user)
}
connect({
host:'127.0.0.1',
port:3306,
username:'root',
password:'root',
type:'master'
}) //127.0.0.1 3306 {username: "root", password: "root", type: "master"}
</script>
<script>
const AA={
username:'ran'
}
const BB={
password:'lyyrhf'
}
const CC={
job:'Java'
}
const D={...AA,...BB,...CC};
console.log(D) //{username: "ran", password: "lyyrhf", job: "Java"}
</script>
5.2 正则表达式命名捕获组
ES9 允许命名捕获组使用符号『?』,这样获取捕获结果可读性更强
let str = '<a href="http://www.atguigu.com">尚硅谷</a>';
const reg = /<a href="(?<url>.*)">(?<text>.*)<\/a>/;
const result = reg.exec(str);
console.log(result.groups.url);
console.log(result.groups.text);
5.3 正则表达式反向断言
ES9 支持反向断言,通过对匹配结果前面的内容进行判断,对匹配进行筛选。
//声明字符串
let str = 'JS5211314 你知道么 555 啦啦啦';
//正向断言
const reg = /\d+(?=啦)/;
const result = reg.exec(str);
//反向断言
const reg = /(?<=么)\d+/;
const result = reg.exec(str);
console.log(result);
5.4 正则表达式 dotAll 模式
正则表达式中点.匹配除回车外的任何单字符,标记『s』改变这种行为,允许行
终止符出现
let str = `
<ul>
<li>
<a>肖生克的救赎</a>
<p>上映日期: 1994-09-10</p>
</li>
<li>
<a>阿甘正传</a>
<p>上映日期: 1994-07-06</p>
</li>
</ul>`;
//声明正则
const reg = /<li>.*?<a>(.*?)<\/a>.*?<p>(.*?)<\/p>/gs;
//执行匹配
const result = reg.exec(str);
let result;
let data = [];
while(result = reg.exec(str)){
data.push({title: result[1], time: result[2]});
}
//输出结果
console.log(data);
6 ES10 新特性
6.1 对象扩展方法 Object.fromEntries
用来创建一个对象,参数是一个数组或者是map对象。
将二维数组转为对象,而ES8 中 Object.entries 方法是把对象转化为数组
<script>
//二维数组
const res = Object.fromEntries([
['name','尚硅谷'],
['cities','成都','武汉']
])
console.log(res) //{name: "尚硅谷", cities: "成都"}
//Map
const m = new Map();
m.set('name','ranhaifeng')
const result = Object.fromEntries(m)
console.log(result); //{name: "ranhaifeng"}
</script>
6.2 字符串扩展方法 trimStart 和 trimEnd
**trimStart :**清除字符串左侧的字符
**trimEnd:**清除字符串右侧的字符
<script>
//trim
let str= ' asd '
console.log(str) //asd
console.log(str.trimStart()) //asd 清空头空格
console.log(str.trimEnd()) // asd 清空尾空格
</script>
6.3 flat与flatMap
**flat:**将多维数组转化为低维数组
**flatMap:**将map对象进行降维
<script>
const arr = [1,2,3,[4,5,6,[7,8,9]]]
//参数为深度,是一个数字,2表示2层
console.log(arr.flat(2)) //[1,2,3,4,5,6,7,8,9]
const arr2=[1,2,3,4]
const result = arr2.flatmap(item => [item * 10]); //如果map的结果是一个多维数组可以进行flat 是两个操作的结合
</script>
6.4 Symbol.prototype.description
用来获取Symbol的字符串描述
let s = Symbol('尚硅谷');
console.log(s.description) //尚硅谷
7 ES11 新特性
7.1 私有属性
<script>
class Person {
//公有属性
name;
//私有属性
#age;
#weight;
//构造方法
constructor(name, age, weight) {
this.name = name;
this.#age = age;
this.#weight = weight;
}
intro(){
console.log(this.name);
console.log(this.#age);
console.log(this.#weight);
}
}
//实例化
const girl = new Person('陈', 18, '45kg');
console.log(girl.#age) //error 原因:类的外部没法得到私有属性的值,只能在类里面访问
console.log(girl); //Person{name: "陈", #age: 18, #weight: "45kg"}
girl.intro(); // 陈 18 45kg
</script>
7.2 Promise
allSettled 和all 方法,主要用于批量处理异步任务。
<script>
//声明两个promise对象
const p1 = new Promise((resolve, reject) => {
setTimeout(()=>{
resolve('商品数据-1')
},1000)
})
const p2 = new Promise((resolve, reject) => {
setTimeout(()=>{
reject('出错了!')
},1000)
})
//调用allsettled方法:返回的结果始终是一个成功的,并且异步任务的结果和状态都存在
const res = Promise.allSettled([p1,p2]);
console.log(res)
// Promise {<pending>}
// __proto__: Promise
// [[PromiseState]]: "resolve"
// [[PromiseResult]]: Array(2)
// 0: {status: 'fulfilled', value: '商品数据-1'}
// 1: {status: 'rejected', reason: '出错了!'}
//=========================================================
//调用all方法:返回的结果是按照p1、p2的状态来的,
//如果都成功,则成功,
//如果一个失败,则失败,失败的结果是失败的Promise的结果
const result = Promise.all([p1,p2])
console.log(result)
</script>
7.3 String.prototype.matchAll
let str = `<ul>
<li>
<a>肖生克的救赎</a>
<p>上映日期: 1994-09-10</p>
</li>
<li>
<a>阿甘正传</a>
<p>上映日期: 1994-07-06</p>
</li>
</ul>`;
//声明正则
const reg = /<li>.*?<a>(.*?)<\/a>.*?<p>(.*?)<\/p>/sg
//调用方法
const result = str.matchAll(reg); //返回的是一个可迭代对象
//展开可迭代对象 方法1
// for(let v of result){
// console.log(v);
// }
//展开可迭代对象 方法2
const arr = [...result];
console.log(arr);
7.4 可选链操作符 ?.
免去层层判断的麻烦
//相当于一个判断符,如果前面的有,就进入下一层级
function main(config){
const dbHost = config?.db?.host //等价于 config && config.db && config.db.host
console.log(dbHost) //192.168.1.100
}
main({
db:{
host:'192.168.1.100',
username:'root'
},
cache:{
host:'192.168.1.200',
username:'admin'
}
})
7.5 动态import
// hello.js
export function hello(){
alert('Hello');
}
// app.js
// import * as m1 from "./hello.js"; //静态传入
//获取
const btn = document.getElementById('btn');
btn.onclick = function(){
//使用之前并未引入,动态引入,返回的其实是一个Promise对象
// 使用的时候再进行传入,import函数,参数是路径
import('./hello.js').then(module => {
module.hello();
});
}
// index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>动态 import </title>
</head>
<body>
<button id="btn">点击</button>
<script src="./js/app.js" type="module"></script>
</body>
</html>
7.6 BigInt类型
//大整型
let n = 521n;
console.log(n,typeof(n)) // 521n n
//函数 将整型转为大整型
let n = 123;
console.log(BigInt(n)) // 123n //不要使用浮点型,只能用int
//大数值运算
let max = Number.MAX_SAFE_INTEGER; // 9007199254740991
console.log(max +1) // 9007199254740992
console.log(max +2) // 9007199254740992 出问题了
console.log(BigInt(max)+BigInt(1)) 9007199254740992n
console.log(BigInt(max)+BigInt(2)) 9007199254740993n
7.7 绝对全局对象globalThis
始终指向全局对象
console.log(globalThis) //window //适用于复杂环境下直接操作window