1.Promise**
1.概念
Promise 是异步编程的一种解决方案,比传统的回调函数和事件更合理、更强大。Promise是一个构造函数, 用来生成Promise实例, Promise实例是异步操作管理者。Promise代表了未来某个将要发生的事件(通常是一个异步操作) ,可以将异步操作以同步的流程表达出来, 避免了层层嵌套的回调函数(回调地狱)
Promise本身还是在使用回调函数(只不过比回调函数多了一种状态管理)
2.使用
创建promise对象,实例化Promise 参数是回调函数,内置两个参数,resolve和reject
1.promise三个状态
初始化状态 pending
成功状态 fullfilled
失败状态 rejected
2.调用
then : 触发resolve方法执行then
let promise = new Promise((resolve,reject)=>{
// 初始化状态
let num = 10;
// 判定
if (num > 10){
resolve('成功');
}else{
reject('失败');
}
}),
// 使用promise对象中的then方法进行触发promise对象
// then方法内置一个或者两个参数 如果是一个参数
// 第一个参数 是resolve函数 是一个回调函数
// 第二个参数 可选 是reject函数 是一个回调函数
// 返回值是一个新的promise
let a = promise.then(data=>{
console.log(data);
},err=>{
console.log(err);
})
console.log(a);
catch : 触发reject方法执行catch
let promise = new Promise((resolve,reject)=>{
let num = 10;
if (num > 100){
resolve('成功');
}else{
console.log(alsdjla);
reject('失败');
}
})
promise.then(data=>{
console.log(data);
}).catch(error=>{
console.log(error);
})
3.捕获异常
在使用then的时候是无法捕获异常的 但是在catch中可以捕获异常
try : 可能出现异常的代码
catch : 如果try出现错误,代码执行catch
finally : 不管会不会发生异常,都会执行finally中的代码
try{
console.log(num);
}catch{
let num = 500;
console.log(num);
}finally{
console.log('gameover');
}
4.链式操作
then方法的第一个参数,成功时的回调函数,分两种情况
返回了一个普通的数据(非promise),这个值会作为参数传递给下一个then的成功回调
返回了一个promise,下一个then的执行,取决于这个promise状态的改变
let promise = new Promise((resolve,reject)=>{
let num = 10;
if (num > 5){
resolve('获取京东首页');
}else{
reject('404页面走丢了');
}
})
// 触发Promise
promise.then(data=>{
console.log(data);
return data + '中的一级栏目';
}).then(data=>{
console.log(data);
return data + '中的二级栏目';
}).then(data=>{
console.log(data);
return data + '中的浪琴';
}).then(data=>{
console.log(data);
})
all方法
all方法是Promise中的静态方法 不需要实例化Promise 就可以直接使用
它主要的作用是执行所有的Promise 也就是说 一次性可以执行多个Promise
let p1 = new Promise((resolve,reject)=>{
setTimeout(() => {
resolve('这是p1');
}, 2000);
})
let p2 = new Promise((resolve,reject)=>{
setTimeout(() => {
resolve('这是p2');
}, 3000);
})
let p3 = new Promise((resolve,reject)=>{
setTimeout(() => {
resolve('这是p3');
}, 1000);
})
// 使用Promise构造中的all方法 内置一个参数 参数是一个数组 数组中每一个元素都是一个Promise
let p = Promise.all([p1,p2,p3]);
p.then(d=>{
console.log(d);
})
race方法
race方法是Promise中的静态方法 不需要实例化Promise 就可以直接使用
执行速度最快的那个Promise 其他的都不执行
let p1 = new Promise((resolve,reject)=>{
setTimeout(() => {
resolve('这是p1');
}, 2000);
})
let p2 = new Promise((resolve,reject)=>{
setTimeout(() => {
resolve('这是p2');
}, 3000);
})
let p3 = new Promise((resolve,reject)=>{
setTimeout(() => {
resolve('这是p3');
}, 1000);
})
// race方法 执行最快的Promise 内置一个参数 参数是一个数组 数组中的每一个元素都是Promise
let p = Promise.race([p1,p2,p3]);
p.then(d=>console.log(d));
2.async…await函数**
1.目的
真正意义上去解决异步回调的问题,同步流程表达异步操作
本质上async 是 Generator和Promise的语法糖
2.特点
不需要像Generator去调用next方法,遇到await等待,当前的异步操作完成就往下执行
被async修饰的函数,是一个异步函数 返回的总是Promise对象,可以用then方法进行下一步操作
async取代Generator函数的星号*,await取代Generator的yield
语意上更为明确,使用简单,经临床验证,暂时没有任何副作用
async…await特点*
1.async修饰的函数可以使用await 其他函数不可以使用 即使使用 也没有效果
2.async函数 无论函数内容是什么 返回值都是一个promise
3.await会自动获取我们async函数中的promise对象中的resolve状态 并且经过异常处理
4.他会将我们异步代码变成同步代码进行执行
3.案例
function fn1(){
return new Promise((resolve,reject)=>{
setTimeout(() => {
// console.log('fn1');
resolve('这是fn1 执行事件为2s');
}, 2000);
})
}
function fn2(){
return new Promise((resolve,reject)=>{
setTimeout(() => {
// console.log('fn2');
resolve('这是fn2 执行事件为2s');
}, 3000);
})
}
function fn3(){
return new Promise((resolve,reject)=>{
setTimeout(() => {
// console.log('fn3');
resolve('这是fn3 执行事件为1s');
}, 1000);
})
}
async function fn(){
let v1 = await fn1();
console.log(v1);
let v2 = await fn2();
console.log(v2);
let v3 = await fn3();
console.log(v3);
}
fn();
3.面向对象
什么是面向过程 : 需要什么写什么 需要什么封装什么
什么是面向对象 : 就是 我们将一系列的程序 逻辑 代码 进行封装 需要的时候 直接调用
面向对象的优势
减少代码冗余
便于后期维护
保证数据安全
1.类和对象的关系
类是对象的抽象 对象是类的具体
类是对象的模板 对象是类的铸件
2.类的成员
成员属性 : 类似于变量 但是不同于变量 成员属性在类中是全局的 属性是一个事务的特征 特性
成员方法 : 类似于函数 但是不同于函数 成员方法在类中是全局的 方法指的是一个事物的行为
定义一个类 使用关键字 class 后面是类名 类名后面直接跟上大括号 没有形参列表
类名的命名一般使用帕斯卡命名法
3.实例化一个类
实例化一个对象 使用关键字 new
// 定义一个类
class Car{
// 定义成员属性
name = 'Audi';
color = "black";
// 定义成员方法
start(){
console.log(this.name + '车启动了');
}
}
// 实例化一个对象
let c = new Car();
console.log(c.name);
console.log(c.color);
c.start();
4.构造器
构造器是每一个类中都存在的方法 即使你不定义 他也存在
构造方法是魔术方法 不需要调用 在满足条件的情况下会被自动调用
构造方法 只要实例化了一个对象 就会被自动调用
主要的作用是用来初始化对象使用
构造器关键字 : constructor
class Person{
constructor(name,age,sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
say(){
console.log(`我的名字叫做${this.name},我是一个${this.age}岁的${this.sex}孩`);
console.log(this.food);
}
eat(food){
this.food = food;
}
}
let obj = new Person('Eric',18,'男');
obj.say();
let newObj = new Person('Mary',13,'女');
newObj.eat('套餐');
newObj.say();
class Person{
constructor(name,age,sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
say(){
console.log(`我的名字叫做${this.name},我是一个${this.age}岁的${this.sex}孩`);
}
}
let obj = new Person('Eric',18,'男');
obj.say();
let newObj = new Person('Mary',13,'女');
newObj.say();
5.继承
继承就是一个类中有另一个类的方法和属性 这就是继承
可以减少代码的冗余
继承 使用关键字 extends
// 定义一个父类 也就基类
class Worker{
constructor(name){
this.name = name;
}
zb(){
console.log(this.name + '的周报');
}
jx(){
console.log(this.name + '的绩效');
}
}
// 子类 或者叫做派生类 继承父类
class Boss extends Worker{
// 定义子类的方法
szb(){
console.log(this.name + '审核周报');
}
sjx(){
console.log(this.name + '审核绩效');
}
}
let w = new Worker('Eric');
w.zb();
w.jx();
let b = new Boss('Mary');
b.jx();
b.zb();
b.sjx();
b.szb()
6.方法的重写
当我们父类中的方法 不能满足子类的需求的时候 我们可以对父类的方法进行重写 或者覆盖
// 定义一个父类 也就基类
class Worker{
constructor(name){
this.name = name;
}
zb(){
console.log(this.name + '的周报');
}
jx(){
console.log(this.name + '的绩效');
}
}
// 子类 或者叫做派生类 继承父类
class Boss extends Worker{
// 定义子类的方法
szb(){
console.log(this.name + '审核周报');
}
sjx(){
console.log(this.name + '审核绩效');
}
// 直接定义重名方法 覆盖父类的方法
jx(){
console.log(this.name + '说 我是按照季度发放奖金的');
}
}
let w = new Worker('Eric');
w.jx();
let b = new Boss('Mary');
b.jx();
7.继承构造器
如果说构造器不能满足我们子类的需求 那么我们怎么班
构造器不能直接重写 不能覆盖 不能自己重新定义
我们重写构造器的时候 需要先继承父类的构造器 并且继承父类构造器中所有的参数
继承构造器 我们需要使用super关键字
class Worker{
constructor(name){
this.name = name;
}
jx(){
console.log(this.name + '的绩效');
}
}
class Boss extends Worker{
constructor(name,money){
super(name);
this.money = money;
}
sjx(){
console.log(this.name + '审核绩效');
}
jx(){
console.log(this.name + "说 我的工资至少一个月" + this.money);
console.log(this.name + '说 我是按照季度发放奖金的');
}
}
let b = new Boss('三哥',80000);
b.jx();
8.静态方法
静态方法其实就像Promise中的all方法或者是race方法一样 不需要实例化 直接能够调用的方法
静态方法需要使用static进行修饰 它不存储在我们传统对象的堆栈空间中 他存储在数据段 对每一个空间都进行开放
不需要实例化 没有引用 所以说 我们静态方法执行的效率比较快 大约比普通方法快55%
调用静态方法 类名.方法()
class Person{
constructor(name,age) {
this.name = name;
this.age = age;
}
say(){
console.log(this.name + "不说实话 说他只有" + this.age + "岁");
console.log(this);
}
// 定义静态方法
static eat(){
// console.log('今天中午吃点饭');
console.log(this.name + '今天中午吃点饭');
}
}
let p = new Person('Eric',18);
// console.log(p);
// p.say()
// Person.say();
// 调用静态方法
// Person.eat();
Person.eat();
// p.eat();
注意 静态方法中 不能有非静态成员
4.ES6模块
1.概念
什么是模块 模块其实就是我们JS文件或者是一个JSON
模块打包一共分为两个部分
第一部分 : 引入 在ES6中 引入使用import … from
第二部分 : 暴露 在ES6中 暴露使用export
2.暴露
暴露 : 其实就是模块中向外部展示的数据
如果说模块中的数据没有暴露 那么是不能被其他程序进行引入的
3.引入
引入 : 引入某个模块的程序 如果不引入 那么不能使用
注意事项
第一 : 引入的时候 script标签中 一定要加上一个属性 type=“module”
第二 : 程序必须在服务器上运行 使用IP或者域名进行访问
let name = 'Eric';
let age = 18;
let sex = '男';
let username = 'admin';
let password = "123";
let arr = [11,22,33];
let fun = ()=>{
console.log('这是一个函数');
}
let obj = {name,age,sex}
export {
username,
password,
arr,
fun,
obj,
name,
age,
sex
}
<!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>
</body>
</html>
<script type="module">
import {username,password,obj,name,age,sex} from "./8.js";
console.log(username);
console.log(password);
console.log(obj);
console.log(name);
</script>
5.字符串扩展
includes : 是否包含字符串
startsWith : 是否以某个字符开头
endsWith : 是否以某个字符结尾
repeat : 重复字符串指定的次数
// includes : 是否包含字符串 检测自付出中是否包含某个字符或者字符串
let str1 = 'hello';
console.log(str1.includes('h'));
console.log(str1.includes('l'));
console.log(str1.includes('el'));
console.log(str1.includes('lll'));
// repeat : 重复字符串指定的次数 参数是重复的次数
let str = '*';
console.log(str.repeat(60));
// console.log(str.repeat(6));
// startsWith : 是否以某个字符开头
let str2 = "http://www.ujiuye.com";
console.log(str2.startsWith('http://'));
console.log(str2.startsWith('https://'));
console.log(str.repeat(60));
// endsWith : 是否以某个字符结尾
let str3 = "http://www.ujiuye.com/index.html";
console.log(str3.endsWith('.html'));
console.log(str3.endsWith('.htm'));
console.log(str3.endsWith('.php'));
console.log(str3.endsWith('.jpg'));
6.数值扩展
Number.isFinite : 判断是否是有限大
Number.MAX_VALUE : 数字最大值
Number.isInteger : 判断是否是整数
Number.parseInt : 将字符串转换为整型
Math.trunc : 向下取整
// Number.isFinite : 判断是否是有限大
// 判断数字是否有限大 在JS中 我们数字是有上限的 也就是说 我们数字中有最大值
// 超过这个最大值 JS就不再支持
console.log(Number.isFinite(1.7976931348623157e+308));
console.log(Number.isFinite(1.7976931348623157e+309));
console.log(Number.isFinite(Infinity));
console.log(9999**99);
console.log(Number.isFinite(9999**99));
console.log('*'.repeat(60));
// Number.MAX_VALUE : 取出JS中数字最大值
console.log(Number.MAX_VALUE);
console.log(1.7976931348623157e+308);
console.log(1.7976931348623157e+309); // Infinity
console.log('*'.repeat(60));
// Number.isInteger : 判断是否是整数
console.log(Number.isInteger(3));
console.log(Number.isInteger(3.));
console.log(Number.isInteger(3.0));
console.log(Number.isInteger('3'));
console.log(Number.isInteger(3.0000000000000001));
console.log(3.0000000000000005);
console.log('*'.repeat(60));
// Number.parseInt : 将字符串转换为整型
console.log(Number.parseInt('12a3'));
console.log(Number.parseInt('1.2a3'));
console.log(Number.parseInt('a1.2a3'));
console.log(Number.parseInt('1.23'));
console.log('*'.repeat(60));
// Math.trunc : 向下取整
console.log(Math.trunc(2.2));
console.log(Math.trunc(2.1));
console.log(Math.trunc(2.4));
console.log(Math.trunc(2.5));
console.log(Math.trunc(2.9));
console.log(Math.trunc(2.9999999999999999));
7.对象扩展
Object.is : 判断v1,v2数据是否完全相等
Object.assign : 将源对象source的属性复制到新的目标target对象上
Object.keys : 取出对象的键 返回一个数组
Object.values : 取出对象的值 返回一个数组
// Object.is 判断两个对象是否相等
let obj1 = {name:'Eric',age:18};
let obj2 = {name:'Eric',age:18};
// console.log(obj1 == obj2);
// 使用is方法进行判定 内置两个参数 参数是两个对象 进行比较
console.log(Object.is(obj1,obj2));
let str1 = 'qwe';
let str2 = 'qwe';
console.log(Object.is(str1,str2));
// assign方法 将一个对象中的属性 分配给另一个对象
let obj3 = {name:'Eric',age:18,sex:'男'};
let obj4 = {username :'admin',password : '123'};
let newObj = {};
// 使用assign方法 内置参数若干
// 第一个参数是接受属性的对象 后面的参数都是赋予属性的对象
// Object.assign(newObj,obj3);
// console.log(newObj);
Object.assign(newObj,obj3,obj4);
console.log(newObj);
// Object.keys : 取出对象中所有的键 返回一个数组
// Object.values : 取出对象中所有的值 返回一个数组
let obj = {name:'Eric',age:18,sex:'男'};
console.log(Object.keys(obj));
console.log(Object.values(obj));
Object.create : 以一个对象为原型创建另一个对象
let obj = {name:'Eric',age:18,sex:'男'};
/*
create : 以一个对象为原型 创建另一个对象
实质上他只是实现了一个对象的继承
内置两个参数 第一个参数是原型对象
第二个参数是一个描述 描述就是一个对象
对象中的键就是我们新建对象的属性
对象中的值还是一个对象
这个对象中有4个属性 这四个属性就是对属性的修饰
value : 属性的值
writable : 修饰属性是否可写 是不是可以修改 默认是false
configurable : 修饰属性是否可删除 默认为false
enumerable : 修饰属性是否课遍历 默认为false
返回值是创建的对象
*/
let newObj = Object.create(obj,{
school : {
value : '吉林大学',
writable : false,
configurable : false,
enumerable : false
},
address : {
value : '吉林长春',
writable : true,
configurable : true,
enumerable : true
}
})
console.log(newObj);
// console.log(newObj.name);
// 修改属性
newObj.address = "河北廊坊";
newObj.school = "慕尼黑大学";
console.log(newObj);
// 删除属性
// delete newObj.address;
// delete newObj.school;
// console.log(newObj);
// 遍历对象
for (let key in newObj){
console.log(newObj[key]);
}
Object.defineProperties : 给对象添加属性
// 创建一个原型对象
let obj = {firstName : "良辰",lastName : "叶"}
// 使用defineProperty方法添加一个对象属性
// 内置三个参数 第一个参数是原型对象 第二个参数是对象的键
// 第三个参数是描述 描述是一个对象 对象的键是value 对象的值是添加的属性值
// Object.defineProperty(obj,'fillName',{
// value : '叶良辰'
// })
// console.log(obj);
/*
使用defineProperties方法添加对象属性 这次可以添加多个
内置两个参数 第一个参数是原型对象
第二个参数是一个描述 描述是一个对象
对象中的键 使我们要添加的属性的名字
对象中的值是一个描述 这个描述中的属性包括create方法中的属性
对象中可以内置两个方法
get方法 : 获取新增属性的时候会被自动调用
set方法 : 修改新增属性的时候 会被自动调用
*/
Object.defineProperties(obj,{
fillName : {
// value : '叶良辰',
get(){
return this.lastName + this.firstName;
},
set(rename){
// console.log('你呀改我干啥 还把我改成' + rename);
this.lastName = rename.slice(0,1);
this.firstName = rename.slice(1);
}
}
})
console.log(obj.fillName);
obj.fillName = '赵日天';
console.log(obj.fillName);
console.log(obj);
obj.fillName = "上官海棠";
console.log(obj);
let object = {
username : '张飞',
get username(){
// console.log('我改名了 我叫关羽');
return '我改名了 我叫关羽'
},
set username(x){
console.log('修改了username 修改的是' + x);
}
}
console.log(object.username);
// object.username = 123;
console.log(object);
8.数组扩展
Array.from : 将伪数组对象或者可遍历的对象 转换成真数组
Array.of : 将一系列的值转换为数组
find : 找出第一个满足条件的元素
findIndex : 找出第一个满足条件元素的索引
<!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>
<button>按钮1</button>
<button>按钮2</button>
<button>按钮3</button>
<button>按钮4</button>
<button>按钮5</button>
<button>按钮6</button>
<button>按钮7</button>
<button>按钮8</button>
</body>
</html>
<script>
// 数组的扩展
// Array.from : 将伪数组对象或者可遍历的对象 转换成真数组
let oBtns = document.getElementsByTagName('button');
console.log(oBtns);
console.log(Object.prototype.toString.call(oBtns));
let arr = Array.from(oBtns);
console.log(Object.prototype.toString.call(arr));
arr.forEach(element => {
console.log(element);
});
// Array.of : 将一系列的值转换为数组
// 其实就是一个创建数组的方式 内置参数若干 会将每一个参数 都转换成数组元素
let data = Array.of(1,7,3,0,1,0,7,9,2,0,1);
console.log(data);
console.log(Object.prototype.toString.call(data));
// find : 找出第一个满足条件的元素
// 和filter类似 filter是返回数组中所有符合条件的元素 返回值是一个数组 即使没有满足条件的元素 那么也会返回一个空数组
// 但是find只是查找第一个满足条件的元素 返回值是一个数组元素 如果说没有满足条件的元素 那么返回undefined
// 传参方式和filter保持一致
// let res = data.filter(element=>element%2==0);
// let res = data.filter(element=>element%2==13);
// console.log(res);
// let result = data.find(element=>element%3==0);
let result = data.find(element=>element%3==13);
console.log(result);
// findIndex : 找出第一个满足条件元素的索引
// 传参方式和find保持一致
// 如果说找不到满足条件的下标 返回值是-1
// let index = data.findIndex(element=>element%3==0);
let index = data.findIndex(element=>element%13==26);
console.log(index);
</script>
9.深度克隆
深度克隆其实就是我们所说的深拷贝
1.浅拷贝
拷贝对象其实就是复制对象 而浅拷贝指的是 拷贝之后 当一个对象发生改变的时候 另一个对象 也会跟着改变
浅拷贝只是拷贝了对象的栈空间的地址 没有拷贝堆空间的内存
// 直接拷贝
// let arr = [66,88,99];
// let newArr = arr;
// console.log(arr);
// console.log(newArr);
// arr.push(33)
// newArr.push(44);
// console.log(arr);
// console.log(newArr);
// 使用...进行浅拷贝
// let arr = [66,88,99,[11,22,33]];
// let newArr = [...arr];
// console.log(arr);
// console.log(newArr);
// arr[3].push(999);
// console.log(arr);
// console.log(newArr);
// 使用assign也是浅拷贝
// let obj = {
// name : 'Eric',
// age : 18,
// arr : [11,22]
// };
// let newObj = {}
// Object.assign(newObj,obj);
// console.log(obj);
// console.log(newObj);
// obj.arr[2] = 12356464;
// console.log(obj);
// console.log(newObj);
// 使用JSON.parse都是浅拷贝
let obj = {
name : 'Eric',
age : 18,
say : ()=>{
console.log(123);
},
arr : [11,22]
};
let newObj = JSON.parse(JSON.stringify(obj));
console.log(obj);
console.log(newObj);
2.深拷贝
深拷贝指的是 拷贝之后 一个对象发生改变 不会影响另一个对象
深拷贝不仅仅拷贝了栈空间的地址 也拷贝了堆空间的内存
// let obj = {name : 'Eric',age : 18,sex : '男'};
let obj = {name : 'Eric',age : 18,sex : '男',gk:[146,157,286]};
// let arr = [11,33,55,77,99];
let arr = [11,33,55,77,99,[22,44,66,88]];
// 定义一个函数 完成深度克隆
function deepCopy(object){
let result = null;
if (Object.prototype.toString.call(object) == '[object Array]'){
result = [];
}else if (Object.prototype.toString.call(object) == '[object Object]'){
result = {};
}else{
return object;
}
// 遍历对象或者是数组 进行处理 使用for...in
for (let key in object){
if (typeof object[key] == 'object'){
result[key] = deepCopy(object[key])
}else{
result[key] = object[key];
}
}
return result
}
let newArr = deepCopy(arr); // [object Array]
let newObj = deepCopy(obj); // [object Object]
// console.log(newArr);
// console.log(newObj);
// 测试对象 和对象中的数组
newObj.gk.push(35);
console.log(obj);
console.log(newObj);
// 测试数组 数组中的数组
newArr[5].push(1234567890);
console.log(arr);
console.log(newArr);