二阶段3

133 阅读25分钟

JavaScript第23天

回顾

  1. 封装ajax
  • 传递type,url,data,async,dataType,success
  • 先对URL进行校验
  • 将传递的数据交给默认值对象
  • 对象默认值里面的每一个数据都进数据校验
  • data也要进行判断,string,object
  • 封装ajax了
  • 对dataType进行判断如果json,那么就转对象
  1. 异常
  • 系统异常
  • 自定义异常 throw new Error("异常说明")
  • 处理异常
  • try
  • catch
  • finally
  1. http
  2. 三次握手和四次浑手
  3. 输入URL做了哪些事情?
  4. 路由 http://localhost:8080/api/user/query
  5. SQL语句

比如

# 按需插入
insert into 表名 (编号,字段1,字段2) values(null,值1,值2)
# 增
编号 姓名 年龄 性别 
insert into 表名 value(null,值1,值2,值3)
​
# 删
delete from 表名 where id = ?
​
# 改
update 表名 set 字段1 = 值1 , 字段2 = 值2 where id = ?
​
# 查
select * from 表名 
select * from 表名 where 条件

知识点

  1. nodejs连接mysql
  • 下载mysql包 npm i mysql
  • express连接的mysql

比如

const mysql = require("mysql")
mysql.createPool({
    host:'',
    port:"",
    user:""
    password:"",
    database:"",
    connectionLimit:20,
})
  1. 中间件 中间件也叫做拦截器
  • 全局中间件

比如

app.use((req,res,next)=>{
    //放行
    next();
    //跳转到错误中间件
    next(内容)
})
  • 路由中间件

比如

router.use((req,res,next)=>{
    next() //放行
    next(内容) //跳转到错误中间件
})
  • 请求中间件

比如

router.get("/login",(req,res,next)=>{
    next() => 放行
    next(内容) =>跳转到错误中间件
},login)
  • 错误中间件

比如

app.use((err,req,res,next)=>{
    if(err){
        res.send({code:xxx,msg:yyy})
    }
})

JavaScript第24天

回顾

  1. express连接数据库
  • 下载包 npm i mysql
  • 导入包 const mysql = require("mysql")
  • 使用mysql

比如

const pool = mysql.createPool({
    host:"",
    port:"",
    user:"",
    password:"",
    database:"",
    connectionLimit:
})
pool.query("SQL语句",[参数],回调函数)
  1. express里面中间件
  • 全局中间件

比如

app.use((req,res,next)=>{
    next() 放行
    next(内容) 跳转到错误中间件
})
  • 路由中间件

比如

router.use((req,res,next)=>{
​
})
  • 请求中间件

比如

router.get(三级路由,请求中间件,三级路由对应的函数)
  • 错误中间件

比如

app.use((err,req,res,next)=>{
​
})
  1. echarts的基本使用
  2. bootrap的基本使用

知识点

1. promise

promise一般用于解决的回调地狱的(异步代码一层套一层),对代码的维护的友好,可以将异步代码当中同步代码进行展示 给一个私人的解释: 一般请求下,有异步代码,那么就会使用promise来包裹异步代码

  1. promise有三种状态
  • 成功的 fulfilled
  • 等待中 pendding
  • 失败的 rejected
  1. promise有两种转换
  • 等待中转换成成功的状态
  • 等待中转换成失败的状态
  1. 创建promise

比如

//resolve => 返回promise是一个成功的状态
//reject => 返回promise是一个失败的状态
const p = new Promise((resolve,reject)=>{
    setTimeout(() => {
        try {
            throw new Error("人为报一个错误")
​
            resolve("我是一个成功的promise")
        } catch (error) {
            reject("我是一个失败的promise")
        }
    }, 1000);
})
  1. promise的状态

比如

/* 
    resolve => 返回一个成功的Pro貌似额
    reject => 返回一个失败的promise
​
    promise的三种状态
        成功的 fulfilled/resolved
        失败的 rejected
        等待中 pendding
    promise有两种转换
        持续的状态转换成一个成功的状态
        持续的状态转换出一个失败的状态
    Promise的内有一个 constructor 构造器
*/
const p = new Promise((resolve, reject) => {
    setTimeout(() => {
        try {
            // throw new Error("人为报一个错误")
            //成功使用resolve给包裹起来
            resolve("我是一个成功的promise")
        } catch (error) {
            //失败使用reject包裹起来
            reject("我是一个失败的promise")
        }
    }, 1000);
})
console.log(p);
  1. 获取promise的返回结果

比如

/* 
    resolve => 返回一个成功的Pro貌似额
    reject => 返回一个失败的promise
​
    promise的三种状态
        成功的 fulfilled/resolved
        失败的 rejected
        等待中 pendding
    promise有两种转换
        持续的状态转换成一个成功的状态
        持续的状态转换出一个失败的状态
    Promise的内有一个 constructor 构造器
*/
const p = new Promise((resolve, reject) => {
    setTimeout(() => {
        try {
            // throw new Error("人为报一个错误")
            //成功使用resolve给包裹起来
            resolve("我是一个成功的promise")
        } catch (error) {
            //失败使用reject包裹起来
            reject("我是一个失败的promise")
        }
    }, 1000);
})
p.then(res=>{
    //获取一个成功的promise的返回结果
})
p.catch(err=>{
    //获取一个失败的promise返回的结果
})
  1. 使用promise解决异步的回调地狱

比如

const p1 = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve("早上吃")
    }, 1000)
})
//获取成功的promise
p1.then(res => {
    console.log(res);
    //中午吃
    const p2 = new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve("中午吃")
        }, 1000)
    })
    p2.then(res => {
        console.log(res);
​
        //下午吃
        const p3 = new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve("下午吃")
            }, 1000)
        })
​
        p3.then(res => {
            console.log(res);
        })
    })
})
  1. 获取promise的返回结果 async,await => 解决promise里面一种返回状态

比如

function fn(){
    const p = new Promise((resolve,reject)=>{
        setTimeout(()=>{
            try {   
                // throw new Error("错误")
                resolve("我是贵阳的")
            } catch (error) {
                reject("我是长沙的")
            }
        },1000)
    })
    //调用fn这个函数,将promise的返回结果集返回出去
    return p;
}
//可以使用async和await获取promise的返回结果
//给函数添加async,给调用这添加await
//这种用法最多
async function fun(){
    const res = await fn();
    console.log(res);
}
fun();
  1. async所修饰的函数 async所修饰的函数一定是一个promise的返回结果,返回了什么需要看return的内容
  • 如果返回的了一个非promise的内容

    • 没有异常 -> 在return函数里面没有异常出现,那么return内容就是promise的结果
    • 有异常 -> 在return函数里面有异常,那么promise的结果就是那个异常
  • 如果返回的是一个成功的promise

    • 如果是一个成功的promise,那么结果就是那个成功的promise里面的内容
    • 如果是一个失败的promise,那么结果机试那个失败的promise里面的内容

比如

//async所修饰的函数的返回结果一定是一个promise的结果集,promise的返回内容需要看return后面的东西
async function fn(){
    // return 123; //如果返回的是一个非promise的值,那么return的内容就是这个promise的结果
    // throw new Error("自定义异常")
    // return 123; //如果返回的是一个非promise的值,里面存在的异常,那么return的内容就是这个异常
​
​
    //Promise.resolve("abc") => 直接创建一个成功的Promise,promise的内容就是abc
    // return Promise.resolve("abc") //如果是一个成功的promise,promise的内容就是return的后面内容
​
    //Promise.reject("edf") => 直接创建一个失败的promise
    return Promise.reject("def")//如果是一个失败的promise,promise的内容就是return的后面内容
}
const res = fn();
console.log(res);
  1. promise的方法
  • 直接创建一个成功的promise Promise.resolve("内容")
  • 直接创建一个失败的promise Promise.reject("内容")

比如

//promise的方法
//直接创建一个成功的promise
console.log(Promise.resolve("成功"));
​
//直接创建一个失败的promise
console.log(Promise.reject("失败"))
  • allSettled和all和race

比如

const p1 = new Promise((resolve,reject)=>{
    setTimeout(()=>{
        try {
            throw new Error("3报错了")
            resolve("你好11111")
        } catch (error) {
            reject("我好111111")
        }
    },500)
})
const p2 = new Promise((resolve,reject)=>{
    setTimeout(()=>{
        try {
            throw new Error("2报错了")
            resolve("你好2222")
        } catch (error) {
            reject("我好2222")
        }
    },999)
})
const p3 = new Promise((resolve,reject)=>{
    setTimeout(()=>{
        try {
            throw new Error("3报错了")
            resolve("你好3333")
        } catch (error) {
            reject("我好33333")
        }
    },400)
})
​
//批量处理promise的结果 => all 
    // => 如果都没有报错,那么得到的结果状态是一个成功的promise,结果就是多个promise的内容组成的数组
    // => 如果有报错,那么得到的结果状态是一个失败的promise,结果就是最快的失败的promise的结果
const res1 = Promise.all([p1,p2,p3])
​
//批量处理premise的结果 => race
    // => 看哪一个promise的跑的快,谁跑的快,那么promise的结果就是跑的快的那个promise的结果,否管成功或者失败
const res2 = Promise.race([p1,p2,p3])
​
//批量处理promise的结果 => allSettled
    // => 返回的一定一个成功的promise返回装
        // = > 内容是有多个promise结果集对象组成的数组
const res3 = Promise.allSettled([p1,p2,p3])
​
console.log(res1,res2,res3);

2. axios

专门用于发送请求,是对ajax的封装,使用promise对ajax,axios的返回值是 promise的结果,axios获取到的数据,在data里面

get请求

// 在 node.js 用GET请求获取远程图片
axios({
  method: 'get',//请求类型
  url: 'http://localhost;8080/login?username=admin&password=123456',//请求地址
})
.then(res=>{//表示是响应的数据
    console.log(res) //服务器的数据
});

post请求

axios({
  method: 'post',//请求类型
  url: '/user/12345',//请求地址
  data: { //post请求的参数
    firstName: 'Fred',
    lastName: 'Flintstone'
  }
}).then(res=>{
    console.log(res)
})

3. 跨域的解决方案

  1. 没有跨域问题的标签_客户端 常见没有跨域问题的HTML标签有 img,src,link...

比如

<script src="https://cdn.bootcdn.net/ajax/libs/axios/1.3.4/axios.min.js"></script>
<img src="https://img2.baidu.com/it/u=1906732828,3160455141&fm=253&app=138&size=w931&n=0&f=JPEG&fmt=auto?sec=1677862800&t=2fcfdb0971059538242448a049cc4d37" alt="">
  1. JSONP_客户端 使用script的src的方式来解决的跨域的问题,那么就叫做JSONP

比如

<button>点我发送请求</button>
<script>
    /* 
        callbackFunction => 是一个回调函数
    */
    function callbackFunction(msg){
        console.log(msg);
    }
    //JSONP => 使用script的src标签的方式来解决跨域,叫做JSONP
    const btn = document.querySelector("button")
​
    let newScript
    btn.onclick = function(){
        if(newScript) return;
        /* 
            1. 创建script
            2. script的原生属性src是 https://www.runoob.com/try/ajax/jsonp.php?jsoncallback=callbackFunction
            3. 将script的标签挂载 body上面
        */
        newScript = document.createElement("script")
        newScript.src = "https://www.runoob.com/try/ajax/jsonp.php?jsoncallback=callbackFunction"
        document.body.appendChild(newScript)
    }
​
​
    /* const btn = document.querySelector("button")
    btn.onclick = function(){
        const xhr = new XMLHttpRequest()
        xhr.open("get","https://www.runoob.com/try/ajax/jsonp.php?jsoncallback=callbackFunction")
        xhr.send()
        xhr.onload = function(msg){
            console.log(msg);
        }
    } */
</script>
  1. 使用cors解决跨域问题_服务端
  • 下包 => npm i cors
  • 导入 => const cors = require("cors")
  • 使用 => app.use(cors())
  1. 代理 是前端最常用的一种跨域的解决方案

JavaScript第25天

回顾

  1. promise
  • 是异步代码的一种解决方案,常用解决回调地狱,事件相关

  • promise有三种状态

    • fulfilled
    • rejected
    • pending
  • promise有两种转换

    • 持续化状态进入到成功的状态
    • 持续化状态进入到失败的状态
  • 获取promise的结果

    • .then,.catch
    • async,await
  • async所修饰的函数

  • promise的方法

    • allSettled
    • all
    • race
    • Promise.resolve()
    • Promise.reject()
  1. axios 可以在浏览器当中使用和node.js axios({ method:"GET", url:"" }).then(res=>res.data)

axios({ method:"POST", url:"", data:{} }).then(res=>res.data)

  1. 跨域
  • 常见的可以支持跨域的标签有link,img,iframe,,,,,

  • JSONP

  • cors

  • proxy

    • nginx => 正向代理(前端跨域,vpn)和反向代理(负载均衡)

知识点

token

  1. 下载包 => npm i jsonwebtoken
  2. 导入包 => const jwt = require("jsonwebtoken")
  3. 生成token => jwt.sign({个人信息},'秘钥',{expiresIn:毫秒过期时间})
  4. 校验token => jwt.verify(token,'秘钥',(err,data)=>{if(err) next(105) next()})

比如

const jwt = require("jsonwebtoken")
const {tokenKey} = require('./config')
//生成一个token
const token = jwt.sign({username:"wenyuan"},tokenKey,{expiresIn:过期时间默认单位是秒})
​
// eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6Indlbnl1YW4iLCJpYXQiOjE2Nzc4MTE3NTMsImV4cCI6MTY3NzkzMTc1M30.mQ6gOhapEjR0ZzftPFupETv41tQ42AD-eQQSvoAwacc
//解密
// jwt.verify(token,'秘钥',(err,data)=>{if(err) next(105) next()})
jwt.verify("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6Indlbnl1YW4iLCJpYXQiOjE2Nzc4MTE3NTMsImV4cCI6MTY3NzkzMTc1M30.mQ6gOhapEjR0ZzftPFupETv41tQ42AD-eQQSvoAwacc",tokenKey,(err,data)=>{
    if(err){
        console.log("token解密失败");
    }else{
        console.log("token解密成功");
    }
})
console.log(token);

cookie的storage的区别

  1. cookie可以前后端都进行操作,storage只能前端进行操作
  2. cookie可以人为的禁用
  3. cookie存储的量比较,大概4K,storage存储量比较大,可以存储大概5M
  4. 生命周期=>cookie可以设置过期时间,如果没有设置,那么关闭浏览器的时候自动消失 localStorage:除非被手动清除,否则将会永久保存 sessionStorage:仅在当前网页会话下有效,关闭页面或浏览器后就会被清除

多表联合查询

select * from 表1,表2 where 表1.公共字段 = 表2.公共字段 and 条件

比如

# select * from 表1,表2 where 表1.公共字段 = 表2.公共字段 and 条件
select * from student,clazz where student.clazzid = clazz.cid #查询所有的学生信息
select * from student,clazz where student.clazzid = clazz.cid and clazz.cid = 1;# 查询一班的学生

JavaScript第26天

回顾

  1. token
  • token的基本作用

语法

//下载
npm i jsonwebtoken
//导包
const jwt = require("jsonwebtoken")
// 加密
const token = jwt.sing({个人信息},'秘钥',过期时间)
// 解密
jwt.verify(token,'秘钥',(err,data)=>{if(err){加密失败}else{next()}})
  • token失效或者是过期我们应该怎么处理?
  1. cookie和storage的区别
  2. 多表联合查询 select * from 表1,表2 where 表1.公共字段 = 表2.公共字段 and 条件
  3. 常用的请求方式有 get 和 post
  4. 一般resultfull方式
  • 获取 get
  • 添加 post
  • 删除 delete
  • 修改 update

知识点

  1. sql排序

比如

## SQL不区分大小写
## 排序 => order by 字段 esc/desc , 默认按照升序进行排序
## 一般排序都是写在sql语法的最后面的
# order by 字段 asc => 排序按照升序
# order by 字段 desc => 排序按照降序进行排序
select * from student order by sid desc
select * from student order by sscore desc
  1. 模糊查询

比如

## 模糊查询
## select * from 表名 where 字段 like '%文%'
select * from student where sname like '%文%'
select * from student where sphone like '%4%'
select * from student where sname like '%九%'

MongoDB数据库

  1. 是一个非关系型数据库
  2. MongoDB的安装
  3. 启动方式一
  • 新建一个文件夹 => data => 路径随意
  • 找MongoDB安装路径 => C:\Program Files\MongoDB\Server\4.0\bin
  • 在URL栏里面输入一个cmd,就会出现改路径对应的黑窗口
  • 在黑窗口里面输入一句话 => mongod --dbpath="写刚刚data文件夹的路径",按回车
  1. 启动方式二
  • 新建一个文件夹 => data => 路径随意

  • 找MongoDB安装路径 => C:\Program Files\MongoDB\Server\4.0\bin , 复制这个路径

  • 在环境变量里面手动配置环境=>目的就是在任何地方都可以启动MongoDB

    • 找到我的电脑,右键属性
    • 点击高级系统设置
    • 点击环境变量
    • 找到用户变量
    • 点击path => 会弹出一个框
    • 点击新建 => 将C:\Program Files\MongoDB\Server\4.0\bin粘贴进去
    • 连续点击三个确定
  • 在桌面里面新建一个文件(注意:后缀名一定要显示出来,按window+E,找到并点击查看,点击显示,再点击文件扩展名)

  • 把文件的名字修改成 无所谓.bat

  • 点击文件右键->编辑->将里面的乱码全部(ctrl+A)删除

  • 添加 mongod --dbpath="写刚刚data文件夹的路径"

  • 以后每一次都启动MongoDB的时候,那么直接双击无所谓.bat文件即可

  1. MongoDB的使用
  • 下载包 npm i mongoose
  • 导入包 const mongoose = require('mongoose');
  • 连接数据库 mongoose.connect('mongodb://localhost:27017/数据库名'); connect => 连接 mongodb => 请求协议 localhost => 本机IP地址 27017 => 默认端口号
  • 创建表结构

比如

const personSchema = mongoose.Schema({
  username:String,
  password:String,
  gender:String,
  age:Number,
});
  • 编译表模型

比如

const person = mongoose.model('person', personSchema);
  1. 操作数据库
  • 存储数据 save

比如

person({
    username:"wenyuan",
    password:"123456",
    gender:"男",
    age:18,
})
.save()
.then(res=>{console.log(res)})
  • 删除 deleteOne(单个删除,如果有多个满足条件,那么会删除第一个),deleteMany(批量删除)

比如

// wenyuan.deleteOne({条件}) => 如果有多个满足条件,那么删除就是前面的
wenyuan.deleteOne({gender:'妖'}).then(res=>console.log(res))
wenyuan.deleteMany({gender:"男"}).then(res=>console.log(res))
wenyuan.deleteOne({_id:'6409782427511d7390ad0d89'}).then(res=>console.log(res))
  • 修改 update

比如

wenyuan.updateOne({gender:'男'},{age:22}).then(res=>console.log(res))
wenyuan.updateMany({gender:'男'},{age:22}).then(res=>console.log(res))
wenyuan.updateOne({_id:'640972ff39ea5e0a866b6bad'},{username:"网无"}).then(res=>console.log(res))
  • 查询

比如

wenyuan.find({_id:'640972ff39ea5e0a866b6bad'}).then(res=>console.log(res))
wenyuan.find().then(res=>console.log(res))
wenyuan.find({gender:"男"}).then(res=>console.log(res))
wenyuan.findById("640972ff39ea5e0a866b6bad").then(res=>console.log(res))

JavaScript第30天

  1. jsonserver 是临时服务器 他是用json数据来模拟数据库 这个服务器是已经帮我们解决的跨域的问题
  2. 使用步骤
  • 搭建一个json文件 => 最好放在网站里面进行解析一遍
  • 下载包 => npm i -g json-server
  • 启动json文件 => json-server --watch JSON文件名 --port 端口号 默认的端口是3000
  • 操作json临时服务器
  1. 我们可以使用resultFul风格来操作JSON服务器
  • post => 添加

比如

/**
 * @Description:  # TODO 添加的resultful风格
 * @Author: 文渊
 * @Date: 2023-03-10 14:47:58
 */
axios({
    url:"http://localhost:3000/student",
    method:"post",
    data:{
        username:"zhangsan",
        password:123456,
        nickname:"张三",
        age:18,
        gender:"男",
        phone:123745678,
    }
})
.then(res=>console.log(res.data))
  • get => 获取

比如

/**
 * @Description:  # TODO 查询
 * @Author: 文渊
 * @Date: 2023-03-10 14:57:18
 */
//没有带参数,那么就是查询所有
axios({
    url:"http://localhost:3000/student"
})
.then(res=>console.log(res.data))
​
//根据ID进行查询
axios({
    url:"http://localhost:3000/student/3"
})
.then(res=>console.log(res.data))
  • put => 修改

比如

/**
 * @Description:  # TODO 修改
 * @Author: 文渊
 * @Date: 2023-03-10 14:53:58
 *    是根据ID进行修改数据
 *        比如:修改id等1的那个信息,将id=1的那个信息修改wenyuan
 *      url后面跟的是id
 *      data后面根据的你要修改的数据
 */
axios({
    url:"http://localhost:3000/student/1",
    method:"put",
    data:{
        username:"wenyuan",
        password:654321,
        nickname:"👲🏼👲🏼",
        gender:'男',
        phone:1111111111,
        age:17
    }
})
.then(res=>console.log(res.data))
  • delete => 删除

比如

/**
 * @Description:  # TODO 删除操作
 * @Author: 文渊
 * @Date: 2023-03-10 14:51:01
 *  要根据什么来进行删除 => 根据ID来进行删除
 *      url => http://localhost:3000/student/id
 *      比如: 删除 id = 2 的数据 => http://localhost:3000/student/2
 */
axios({
    url:"http://localhost:3000/student/2",
    method:'delete'
})
.then(res=>console.log(res))

JavaScript第31天

对象的拷贝

// let a=1;
        // let b=a;
        // a=100;
        // console.log(a,b);
​
        let obj1 = {
            a: 1,
            b: 2
        }
        // 方法
        // let obj2=obj1;
        // obj2.a=2323;
        // console.log(obj1,obj2)
​
        let obj2 = {}
​
        //方法1
        // for(let key in obj1){
        //  // console.log(obj1[key])
        //  obj2[key]=obj1[key]   属性是变量的时候,要用[]
        // }
​
​
        //方法2
        // obj2={...obj1}
​
        //方法3
        Object.assign(obj2, obj1)
        console.log(obj2)
let obj1 = {
            a: 1,
            b: 2
        }
        let obj2 = Object.create(obj1);
        //Object.create  用于创建一个新对象  使用现有的对象来作为新创建的对象的原型
        obj2.a = 2323;//在实例上可以拿到原型对象上的数据 而且实例数据更改了,原型不变
        console.log(obj2, obj2.a, obj2.b)
        console.log('a' in obj2); //in  判断属性(包括原型对象上的属性)是不是在对象上----存在返回true  反之  返回false
        console.log('b' in obj2);
​
        //hasOwnProperty  判断对象自身的属性在对象身上有没有存在
        console.log(obj2.hasOwnProperty('a'))
        console.log(obj2.hasOwnProperty('b'))
​
​
函数式编程
  // 函数式编程 => 把计算过程转换为一系列嵌套函数的调用过程
        // 高阶函数 => 函数的参数或返回值是函数
        
        let arr = [1, 2, 3, 4, 5, 6, 7];
        let num1 = arr.filter(item => item > 4).map(item => item * 3)
        console.log(num1)
函数柯里化

柯里化(Currying)是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果的新函数的技术。(柯里化 把需要传多个参数的函数 转换成一个一个参数的传递)

js高级

作用域链

 let a=5;  //作用域  词法作用域
         function fun(){
            var a;
            console.log("a",a)
            
         }
      
         fun()

原型链

闭包

基本数据类型(null undefined string number boolean) 引用数据类型(object symbol)

值传递和引用传递

       let a=1;
        let b=a;  //值传递
        a=100;
        console.log(a,b);

对象的拷贝

  let obj1={
            a:1,
            b:2
        }
       //let obj2=obj1;  //引用传递
       let obj2={}
    //    obj2.a=obj1.a;
    //    obj2.b=obj1.b;
    //    for(var attr in obj1){
    //       obj2[attr]=obj1[attr]  //属性是变量的时候,要用[]括起来 
    //    }
        //  obj2={...obj1};
        Object.assign(obj2,obj1)  // obj2是目标对象 obj1源对象
        obj2.a=100;
        console.log(obj1,obj2)
​

通过原型拷贝对象

  let obj1 = {
            a: 1,
            b: 2
        }
        function create(obj1) {  //创建一个实例,用现有对象当做这个实例的原型对象
            function Fun() {
​
            }
            Fun.prototype = obj1;
            return new Fun();
        }
       let obj2=create(obj1);
       obj2.a=100;
        //在实例上可以拿到原型对象上的数据,而且实例数据更改了,原型不变
        console.log(obj2,obj2.a,obj2.b)

Object.create

   let obj1 = {
            a: 1,
            b: 2
        }
        // function create(obj1) {  //创建一个实例,用现有对象当做这个实例的原型对象
        //     function Fun() {
​
        //     }
        //     Fun.prototype = obj1;
        //     return new Fun();
        // }
    //    let obj2=create(obj1);
    let obj2=Object.create(obj1);  
    //Object.create() 方法用于创建一个新对象,使用现有的对象来作为新创建对象的原型(prototype)
       obj2.a=100;
        //在实例上可以拿到原型对象上的数据,而且实例数据更改了,原型不变
        console.log(obj2,obj2.a,obj2.b)

in和hasOwnProperty区别

 let obj1 = {
            a: 1,
            b: 2
        }
        let obj2 = Object.create(obj1);
        //Object.create() 方法用于创建一个新对象,使用现有的对象来作为新创建对象的原型(prototype)
        obj2.a = 100;
        //在实例上可以拿到原型对象上的数据,而且实例数据更改了,原型不变
        console.log("a" in obj2)   //in 判断属性(包括原型对象上的属性)是不是在对象上
        console.log("b" in obj2)
        console.log(obj2.hasOwnProperty("a")) //true //hasOwnProperty 判断对象自身的属性在对象上有没有。
        console.log(obj2.hasOwnProperty("b"))  //false

字符串中常用的方法

repeat includes indexOf padStart padEnd startsWith endsWith

数组常用方法

fill

filter

find

findIndex

flat

  let arr=[1,2,3,4,5,6,7];
        let tempArr=[];
        for(var i=0;i<arr.length;i++){
            if(arr[i]>3){
                tempArr.push(arr[i])
            }
        }
        console.log(tempArr)
       // console.log(arr.filter((item)=>item>3))  //函数式编程
       //把计算过程转换为一系列嵌套函数的调用过程叫函数式编程
       //高阶函数 函数的参数或返回值是函数

函数式编程之组合

    //  console.log(arr.filter(item=>item>4).map(item=>item*3))  
       function doubleX(x){  //纯函数  输出完全由输入决定的函数 
        return x*2
       }  
       function add100(x){
        return 100+x
       }
​
    //    function compose(fn1,fn2){
    //      return function(value){
    //           return doubleX(add100(value))  //组合使用函数
    //      }
    //    }
     const compose=(fn1,fn2)=>(value)=>fn1(fn2(value))
     let returnFn =  compose(doubleX,add100);
     console.log(returnFn(10))

函数式编程--函数的柯理化

//  function getPrice(price,discount){  //根绝折扣得到价格 price 原价  discount折扣
        //      return price*discount;
        //  }
​
        //  console.log(getPrice(100,0.8))
        //  console.log(getPrice(200,0.8))
        //  console.log(getPrice(300,0.8))
​
        // function getPriceFn(discount){
        //     return function(price){
        //         return price*discount;
        //     }
        // }
        const getPriceFn=(disCount)=>(price)=>price*disCount;
        let getPrice=getPriceFn(0.8);  //参数的复用
        console.log(getPrice(100))
        console.log(getPrice(200))

JavaScript第32天

Array.of

将一组值,转换伪数组

Array.from

将伪数组对象转换为真正的数组

Array.isArray()

判断是否是一个数组

arguments

是一个伪数组

...

剩余参数

闭包

function out() {
            function inner() {  //闭包函数
                console.log('海鸥')
            }
            return inner
        }
        let out1=out();  //即使外部函数执行完,函数的执行空间也不会销毁
        out1()

闭包就是能够读取外层函数内部变量的函数

闭包产生的条件:在函数的作用域外调用函数,就会形成一个闭包,闭包函数和引用的变量都不会销毁

函数可以记住并调用所在的词法作用域,就形成了闭包,即使函数是在作用域外执行

通过共有的方法来访问私有变量,私有变量的访问就变安全了

闭包的特点:

1、外部函数可以访问内部函数的变量

2、因为闭包的存在产生了延迟

3、慎用,因为变量不会被GC自动回收,所以有内存泄漏的风险

4、闭包访问变量因为在函数内部,所以避免全局污染

getter与setter

当访问属性的时候,get就会自动执行,get修饰的函数getter

当修改属性的时候,set就会自动执行, set修饰的函数setter

<body>
    <div><button id="btn1">-</button><span class="span">0</span><button id="btn2">+</button></div>
    <script>
        const btn1 = document.getElementById('btn1')
        const span = document.querySelector('.span')
        const btn2 = document.getElementById('btn2')
​
​
        // function goods(){
        //  let count=0;
        //  return{
        //      add(){
        //          count++
        //      },
        //      sub(){
        //          if(count>1){
        //              count--
        //          }
        //      },
        //      get count(){
        //          return count
        //      },
        //      set count(value){
        //          count=value
        //      }
        //  }
        // }
​
​
        function goods() {
            let count = 1;
            return {
                add(){
                    count++
                },
                get count() {
                    return count
                },
                set count(value){
                    count=value
                },
                sub(){
                    if(count>1){
                        count--
                    }
                }
            }
        }
        let obj = goods();
        span.innerHTML = obj.count;
        btn1.onclick = function () {
            obj.sub();
            span.innerHTML = obj.count;
        }
        btn2.onclick = function () {
            // obj.add();
            obj.count=2323
            span.innerHTML =obj.count
        }
​
​
​
    </script>
</body>

Array.of

Array.of()方法用于将一组值,转换为数组

Array.from

将伪数组对象转换为真正数组

Array.isArray

判断是否是一个数组

tips:

arguments 是一个伪数组

剩余参数

 function getSalary(basic,...args){
        return basic+args.reduce((a,b)=>a+b)
    }
    console.log(getSalary(3000,50));

闭包

函数里的函数(可以访问其他函数内部变量的函数)

  function fun(){
            function inner(){  //闭包函数
                console.log("inner")
            }
            // globalvar=inner;
            return inner;
         }
         let refFun=fun();
        //  globalvar();
        refFun();

闭包产生的典型条件

在函数的作用域外调用函数,就会形成一个闭包,闭包函数以及引用的变量都不会销毁

函数可以记住并调用所在词法作用域,就形成了闭包,即使,函数是在作用域外执行

闭包特点

1.外部可以访问内部函数的变量

2.因为闭包的存在生存期延迟了

3.慎用,因为变量不会被GC自动回收,所以有内存泄露的风险

4、闭包访问变量因为在函数内部,所以避免全局污染

 function fun() {
            var a = 0   //私有变量
            function inner() {  //闭包函数  外界可以访问到的共有方法   
                //通过公有的方法访问私有的变量 私有变量的访问就很安全了
​
                a++;
                console.log("inner", a)
            }
            // globalvar=inner;
            return inner;
        }
        let refFun = fun();  //即使外部的fun函数执行完,函数的执行空间也不会销毁
        //  globalvar();
        refFun();
        refFun();
        refFun();
​
        let refFun2 = fun();  //即使外部的fun函数执行完,函数的执行空间也不会销毁
        //  globalvar();
        refFun2();
        refFun2();
        refFun2();

getter和setter

 function goods(){
          var count=1
          return {  //沙箱模式
                add(){
                    count++;
                },
                get count(){   //getter
                    return count;
                },
                set count(value){  //setter
                    count=value;
                },
                sub(){
                    if(count>1){
                        count--
                    }
                }
          }
       }  
      let  obj=goods();
       oneDiv.innerHTML=obj.count;  // 当你访问obj.count属性时候,get就会自动执行,get修饰的函数 getter
       btn1.onclick=function(){
        //    obj.add();
            obj.count=100    //当你修改obj.count属性的时候,set就会被自动执行 set修饰的函数 setter
           oneDiv.innerHTML=obj.count;
       }
       btn11.onclick=function(){
           obj.sub();
           oneDiv.innerHTML=obj.count;
       }

JavaScript第33天

面试题

function fun(n, o) {
            console.log(o)
            return {
                fun(m) {
                    return fun(m, n)
                }
            }
        }
        // let c=fun(0)  //n==0  o==undefind  0  0
        // c.fun(1)  //m==1  //m==1  o==n==0
        // c.fun(2)   //m==2  //m==2  o==n==0
​
​
        // let c=fun(0)  //n==0  o==undefind
        // c.fun(1).fun(2)  //m==1    o== undefind 0 1
​
        let c = fun(0).fun(1).fun(2)   //o==undefind 0  1 2  2
        c.fun(3)
        c.fun(4)

数据劫持

Object.defineProperty

let obj={
            a:1,
            b:2,
            c:3
        }
        let value=obj.b  //用一个变量存obj.b
        Object.defineProperty(obj,'b',{
            get(){
                // return 'b不可以访问'
                return value  //返回obj.b
            },
            set(v){
                console.log(`修改${v}`)
            }
        })
        obj.b=23  //修改b
        console.log(obj.a,obj.b,obj.c)

Object.defineProperty四个属性

value: 999,  值
writable:false,  是否可以修改
enumerable:false,  是否可以用for in 循环
configurable:false  属性是否可修改
getter 
setter
​
​
let obj = {
            a: 1,
            b: 2,
            c: 3
        }
        let value = obj.b  //用一个变量存obj.b
        Object.defineProperty(obj, 'b', {
            value: 999,
            writable: true,
            enumerable:true,
            // configurable:false
        })
        obj.b = 777
        console.log(obj.b)
        // delete obj.b
        for(let key in obj){
            console.log(key)
        }

Object.defineProperties

let obj = {
            a: 1,
            b: 2,
            c: 3
        }
        for (let t in obj) {
            Object.defineProperties(obj, {
                ['_' + t]: {  //拷贝对象以前的值
                    value: obj[t],
                    writable: true,
                    enumerable: false
                },
                [t]: {  //通过属性访问对象拷贝的值
                    get() {
                        console.log('t读取')
                        return obj['_' + t]
                    },
                    set(v) {
                        console.log('t写入')
                        obj['_' + t] = v
                    }
                }
            })
        }
​
        for (let t in obj) {
            console.log(t, obj[t])
        }
         console.log(obj)

Object.defineProperty与Object.defineProperties的区别

Object.defineProperty:每次只能定义单个属性

Object.defineProperties:每次能定义多个属性

数据劫持

Object.defineProperty

        let obj={
            a:1,
            b:2,
            c:3
        }
        let value=obj.b;
        Object.defineProperty(obj,"b",{
            get(){
                //return "b不可以访问"
                return value
            },
            set(v){
                console.log("试图把b的值改为"+v+"但是失败了")
            }
        })
      obj.b=100
      console.log(obj.a,obj.b,obj.c)

四个属性

value:1000,   值
writable:true,  是否可以修改
enumerable:true,  是否可以用for in循环遍历
configurable:false 属性是否可修改

Object.defineProperties

        let obj={
            a:1,
            b:2,
            c:3
        }
        for(let t in obj){
               Object.defineProperties(obj,{
                  ['_'+t]:{
                     value:obj[t],
                     writable:true,
                     enumrable:false
                  },
                  [t]:{
                     get(){
                        console.log("t 读取")
                        return obj['_'+t];
                     },
                     set(v){
                        console.log("t 写入")
                        obj['_'+t]=v;
                     }
                  }
               })
        }

JavaScript第34天

正向代理

// 正向代理   使用new Proxy
        let obj={
            a:'海鸥',
            b:'hhhh',
            c:'嘻嘻嘻'
        }
​
        let p=new Proxy(obj,{
            get(target,arrter){    //target  目标对象   arrter属性   value  修改的值
                return target[arrter]
            },
            set(target,arrter,value){
                
                target[arrter]=value
                return true
            }
​
        })
        p.a=23
        p.b=34
        p.c=98
        console.log(p.a,p.b,p.c)

防抖

很短时间内,多次触发同一事件,就产生了抖动。

抖动过程中后一次把前一次干掉了,最后执行最后一次事件

<input type="text" id="inpt">
    <script>// 防抖  规定事件内只执行最后一次
        const inpt=document.getElementById('inpt');
​
        let timer=null
        inpt.oninput=function(){
            clearTimeout(timer);
            timer=setTimeout(()=>{
                console.log('海鸥')
            },230)
        }
    </script>

截流

很短时间内,多次触发同一个事件,需要对流量进行控制

第一次执行完才能执行第二次

let timer = null;
        let flag = true;
        function fun() {
            if (!flag) return
            flag = false
            clearTimeout(timer)
            timer = setTimeout(() => {
                console.log('海鸥')
                flag = true
            },10000)
​
        }
        setInterval(() => {
            console.log(8888888)
        },100)

深拷贝

let obj1 = {
            a: 1,
            b: 2,
            c: 3,
            d: {
                dd: 77
            },
            f: [1, 2, 3, 4]
        }
        let obj2 = {}
​
        // 深拷贝
        function deep(target, arrt) {
            for (let k in arrt) {
                if (arrt[k].constructor === Object) {   //判断是不是一个对象  
                    target[k] = {};
                    deep(target[k], arrt[k])  //用递归(一个函数调用自身)进行深拷贝
                } else if (Array.isArray(arrt[k])) {   //判断是不是一个数组
                    target[k] = []
                    deep(target[k],arrt[k])   //用递归进行深拷贝t
                } else {
                    target[k] = arrt[k]
                }
            }
            return target
​
        }
​
        deep(obj2, obj1)
        
        obj2=JSON.parse(JSON.stringify(obj1))  //工作中使用的深拷贝方法
                
        obj1.d.dd = 9999
        obj2.f[3]='海鸥'
        console.log(obj1, obj2)
​

Proxy

 let p= new Proxy(obj,{
            get(target,attr){
                return target[attr]
            },
            set(target,attr,value){   //target  目标对象   arrter属性   value  修改的值
                target[attr]=value;
                return true;
            }
        })
        p.a=11;
        p.b=22;
        p.c=33
        console.log(p.a,p.b,p.c)

防抖

很短事件内,多次触发同一个事件,就产生了抖动。

抖动过程中后一次把前一次干掉了,最后执行的最后一次

  let txt = document.getElementById("txt");
    
        txt.oninput=(function(timer){
           return function(){
             clearTimeout(timer);
             timer=setTimeout(() => {  //防抖 规定事件内只执行最后一次
                    console.log("123")
             }, 500);
        }
    })()  //自执行函数

截流

很短事件内,多次触发同一个事件,需要对流量进行控制

第一次执行完才能执行第二次

let timer=null;
        let flag=true //true 才可以执行下一次,false,不可以执行下一次
        function fun(){
            if(!flag) return;
            flag=false;
            clearTimeout(timer)
            timer=setTimeout(()=>{
                console.log("Fun")
                flag=true;
            },2000)
            
        }
​
        setInterval(() => {
           fun()
        }, 10);

对象深拷贝

 function deepCopy(target,source){
             for(let t in source){
                if(source[t].constructor===Object){
                    target[t]={}
                    deepCopy(target[t],source[t]) //用递归进行深拷贝
                }
                else if(source[t].constructor===Array){
                     target[t]=[]
                     deepCopy(target[t],source[t])
                }
                else{
                    target[t]=source[t] 
                }
               
             }
             return target
          }

判断数据类型

typeof 适合基本数据类型

Object.prototype.toString.call(arr)

constructor

instanceOf

eventloop

  //先执行同步代码,在执行异步代码
        //都是异步任务,同级别的情况下,先执行微任务,后执行宏任务
​
        new Promise((resolve,reject)=>{
            console.log(3)   //同步代码
            resolve()
        }).then(()=>{
            console.log(4)  //异步代码 微任务
            setTimeout(()=>{
                console.log(5)
            },0)
        })
        setTimeout(()=>{  //异步代码 宏任务
            console.log(2)
        },0)
        console.log(1);

继承(extend)

1. 原型继承

  //原型继承: 好处: 属性方法全都能继承
        //缺点: 属性不在子类实例上,而是在原型上
         function Person(name,age){ //属性放在实例上,方法放在原型上
            this.name=name;
            this.age=age;
         }
         Person.prototype.say=function(){
            return this.name+","+this.age;
         }
         Student.prototype=new Person;
         function Student(name,age,school){
            this.name=name;
            this.age=age;
            this.school=school
         }
         Student.prototype.exam=function(){  //子类上进行扩展,不影响父类
            return "exam"
         }
         let s = new Student('zs',18,'qf')
         let s1 = new Student('ww',20,'qf')
         console.log(s,s1,Person.prototype)

2.借用构造函数继承

//只能继承属性,不能继承方法
        function Person(name,age){
            this.name=name;
            this.age=age;
        }
        Person.prototype.hello=function(){
            return this.name+','+this.age;
        }
​
        function Student(school,...args){
            Person.call(this,...args);  //借用构造函数法
            this.school=school;
        }
        let  s= new Student('qf','zs',22);
        console.log(s)

3.组合继承

 function Person(name,age){  //组合继承
            this.name=name;
            this.aga=age;
         }
         Person.prototype.hello=function(){
            return this.name+","+this.age;
         }
         function Student(school,...args){
            Person.call(this,...args);
            this.school=school;
         }
         Student.prototype=new Person;
         Student.prototype.constructor=Student;
         let s = new Student("qf","zs",16)
         console.log(s,s.constructor)

4.寄生式继承

   function Person(name,age){  //组合继承
            this.name=name;
            this.aga=age;
         }
         Person.prototype.hello=function(){
            return this.name+","+this.age;
         }
         function Student(school,...args){
            Person.call(this,...args);
            this.school=school;
         }
         //Student.prototype=new Person;
         // function F(){
​
         // }
         // F.prototype=Person.prototype;
         // Student.prototype=new F;
         Student.prototype=Object.create(Person.prototype);
         Student.prototype.constructor=Student;
         let s = new Student("qf","zs",16)
         console.log(s,s.constructor)    //寄生式继承的好处:创建了一个空函数,用空函数的实例继承了父类的原型对象上的方法

5.拷贝继承

        function Person(name,age){
            this.name=name;
            this.age=age;
        }
        Person.prototype.hello=function(){
            return this.name+','+this.age;
        }
​
        function Student(school,name,age){
            this.school=school;
            this.name=name;
            this.age=age;
            let p = new Person("zs",18);
            for(let t in p){
                Student.prototype[t]=p[t]  //拷贝继承
            }
        }
      let s =  new Student("qf","zs",20);
      console.log(s)

6.假冒继承

类继承

class Person{
            constructor(name,age){
           
                this.name=name;
                this.age=age;
            }
            hello(){
                return this.name+','+this.age
            }
        }
        class Student extends Person{  //extend 继承父类的方法 Student.prototype=Object.create(Person.prototype)
            constructor(school,...args){
                super(...args)   //super必须首先调用,继承父类的属性   Person.call(this,...args)
                this.school=school;
               
            }
        }
       let s = new Student('qf','ls',20);
       console.log(s)

设计模式

创建型模式 单例模式

 const getInstance=(function(){
                let ins=null;
                return function(constrctor){
                    if(!ins){
                        ins=new constrctor(...arguments)
                    }
                    return ins;
                }
            })()

结构型模式 装饰器

行为型模式 发布订阅模式

   //观察者模式(发布订阅模式)
        //自定义事件   onclick=fun
        class Message {
            constructor(){
                this.eventObj={}   
            }
            subscribe(evtname,fn){  //订阅操作  evtname 字符串 自定义事件的名字  fn 函数
                if(!this.eventObj[evtname]){
                    this.eventObj[evtname]=[]
                }
                //this.evetObj[evtname] 是一个数组 ,数组是每一个元素是函数
                this.eventObj[evtname].push(fn);
            }
            publish(evtname,args){  //发布操作
                if(this.eventObj[evtname]){ //调用publish eventObj.msg有值,是一个数组,数组是两个函数
                   this.eventObj[evtname].forEach((fun)=>console.log(fun(args)))
                }
            }   
            remove(evtname,fn){
                if(this.eventObj[evtname] && fn){
                    this.eventObj[evtname] =  this.eventObj[evtname].filter((item)=>item!==fn)
                }
            }
       
        }
​
       let bus = new Message();
       const say=(str)=>"hello"+str;
       bus.subscribe("msg",say)  // evtObj.msg   say
       bus.subscribe("msg",(str)=>{
        return "world"+str
       })
       bus.remove('msg',say)
      bus.publish("msg","zs")  //但订阅的多余一个的时候,有群发的效果

策略模式

 function getDiscountFn(discount){
            return function(price){
                return price*discount
            }
        }
​
        const getPriceFn=(holiday)=>{
           
            let cls={  //策略模式
                '618':getDiscountFn(0.8),
                "1111":getDiscountFn(0.7),
                '101':getDiscountFn(0.85)
            }
            return cls[holiday]
        }
       let getPrice= getPriceFn("618");
       console.log(getPrice(1000))