JavaScript第23天
回顾
- 封装ajax
- 传递type,url,data,async,dataType,success
- 先对URL进行校验
- 将传递的数据交给默认值对象
- 对象默认值里面的每一个数据都进数据校验
- data也要进行判断,string,object
- 封装ajax了
- 对dataType进行判断如果json,那么就转对象
- 异常
- 系统异常
- 自定义异常 throw new Error("异常说明")
- 处理异常
- try
- catch
- finally
- http
- 三次握手和四次浑手
- 输入URL做了哪些事情?
- 路由 http://localhost:8080/api/user/query
- 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 条件
知识点
- nodejs连接mysql
- 下载mysql包
npm i mysql - express连接的
mysql
比如
const mysql = require("mysql")
mysql.createPool({
host:'',
port:"",
user:""
password:"",
database:"",
connectionLimit:20,
})
- 中间件 中间件也叫做拦截器
- 全局中间件
比如
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天
回顾
- express连接数据库
- 下载包 npm i mysql
- 导入包 const mysql = require("mysql")
- 使用mysql
比如
const pool = mysql.createPool({
host:"",
port:"",
user:"",
password:"",
database:"",
connectionLimit:
})
pool.query("SQL语句",[参数],回调函数)
- express里面中间件
- 全局中间件
比如
app.use((req,res,next)=>{
next() 放行
next(内容) 跳转到错误中间件
})
- 路由中间件
比如
router.use((req,res,next)=>{
})
- 请求中间件
比如
router.get(三级路由,请求中间件,三级路由对应的函数)
- 错误中间件
比如
app.use((err,req,res,next)=>{
})
- echarts的基本使用
- bootrap的基本使用
知识点
1. promise
promise一般用于解决的回调地狱的(异步代码一层套一层),对代码的维护的友好,可以将异步代码当中同步代码进行展示 给一个私人的解释: 一般请求下,有异步代码,那么就会使用promise来包裹异步代码
- promise有三种状态
- 成功的 fulfilled
- 等待中 pendding
- 失败的 rejected
- promise有两种转换
- 等待中转换成成功的状态
- 等待中转换成失败的状态
- 创建promise
比如
//resolve => 返回promise是一个成功的状态
//reject => 返回promise是一个失败的状态
const p = new Promise((resolve,reject)=>{
setTimeout(() => {
try {
throw new Error("人为报一个错误")
resolve("我是一个成功的promise")
} catch (error) {
reject("我是一个失败的promise")
}
}, 1000);
})
- 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);
- 获取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返回的结果
})
- 使用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);
})
})
})
- 获取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();
- 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);
- 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请求的配置参考地址 www.axios-http.cn/docs/req_co…
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. 跨域的解决方案
- 没有跨域问题的标签_客户端 常见没有跨域问题的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="">
- 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>
- 使用cors解决跨域问题_服务端
- 下包 =>
npm i cors - 导入 =>
const cors = require("cors") - 使用 =>
app.use(cors())
- 代理 是前端最常用的一种跨域的解决方案
JavaScript第25天
回顾
- promise
-
是异步代码的一种解决方案,常用解决回调地狱,事件相关
-
promise有三种状态
- fulfilled
- rejected
- pending
-
promise有两种转换
- 持续化状态进入到成功的状态
- 持续化状态进入到失败的状态
-
获取promise的结果
.then,.catchasync,await
-
async所修饰的函数
-
promise的方法
- allSettled
- all
- race
- Promise.resolve()
- Promise.reject()
- axios 可以在浏览器当中使用和node.js axios({ method:"GET", url:"" }).then(res=>res.data)
axios({ method:"POST", url:"", data:{} }).then(res=>res.data)
- 跨域
-
常见的可以支持跨域的标签有link,img,iframe,,,,,
-
JSONP
-
cors
-
proxy
- nginx => 正向代理(前端跨域,vpn)和反向代理(负载均衡)
知识点
token
- 下载包 => npm i jsonwebtoken
- 导入包 => const jwt = require("jsonwebtoken")
- 生成token => jwt.sign({个人信息},'秘钥',{expiresIn:毫秒过期时间})
- 校验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的区别
- cookie可以前后端都进行操作,storage只能前端进行操作
- cookie可以人为的禁用
- cookie存储的量比较,大概4K,storage存储量比较大,可以存储大概5M
- 生命周期=>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天
回顾
- token
- token的基本作用
语法
//下载
npm i jsonwebtoken
//导包
const jwt = require("jsonwebtoken")
// 加密
const token = jwt.sing({个人信息},'秘钥',过期时间)
// 解密
jwt.verify(token,'秘钥',(err,data)=>{if(err){加密失败}else{next()}})
- token失效或者是过期我们应该怎么处理?
- cookie和storage的区别
- 多表联合查询 select * from 表1,表2 where 表1.公共字段 = 表2.公共字段 and 条件
- 常用的请求方式有 get 和 post
- 一般resultfull方式
- 获取 get
- 添加 post
- 删除 delete
- 修改 update
知识点
- 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
- 模糊查询
比如
## 模糊查询
## select * from 表名 where 字段 like '%文%'
select * from student where sname like '%文%'
select * from student where sphone like '%4%'
select * from student where sname like '%九%'
MongoDB数据库
- 是一个非关系型数据库
- MongoDB的安装
- 启动方式一
- 新建一个文件夹 => data => 路径随意
- 找MongoDB安装路径 =>
C:\Program Files\MongoDB\Server\4.0\bin - 在URL栏里面输入一个
cmd,就会出现改路径对应的黑窗口 - 在黑窗口里面输入一句话 =>
mongod --dbpath="写刚刚data文件夹的路径",按回车
- 启动方式二
-
新建一个文件夹 => 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文件即可
- 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);
- 操作数据库
- 存储数据 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天
- jsonserver 是临时服务器 他是用json数据来模拟数据库 这个服务器是已经帮我们解决的跨域的问题
- 使用步骤
- 搭建一个json文件 => 最好放在网站里面进行解析一遍
- 下载包 =>
npm i -g json-server - 启动json文件 =>
json-server --watch JSON文件名 --port 端口号默认的端口是3000 - 操作json临时服务器
- 我们可以使用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))