目录
一、深克隆
野路子方案
- 克隆不了对象之中的函数,除此之外对象之中的所有数据都可以实现深克隆
console.log( JSON.parse( JSON.stringify( 数组名/对象名 ) ))
递归方案
- 解决了野路子方案存在的问题
function deepClone( obj ){
let clone = obj instanceof Array ? [] : {};
for( let attr in obj ){
if( typeof obj[attr] === "Object" ){
clone[attr] = deepClone( obj[attr] );
}else{
clone[attr] = obj[attr];
}
}
return clone;
}
let obj5 = { a:{},b:[],c: function(){} };
let clone3 = deepClone( obj5 );
console.log( "clone3:",clone3 );
二、闭包
形成闭包的规则
同时满足了下面的规则的话,活动对象就不会被删除:
-
外部函数包裹内部函数;
-
外部函数返回内部函数;( 暴露 )
-
外部函数声明的变量在内部函数之中被引用;
这种情况我们称之为闭包;
代码
// 外部函数
function outerFn( b ){
// 声明变量
let a = 10;
// 内部函数
function innerFn(){
// 注意: 外部函数的参数( 形参 )也遵闭包机制进行改变;
console.log( a,b );
}
// 我们需要返回内部函数
return innerFn;
}
三、函数科里化
科里化函数封装思路
-
科里化函数传入目标函数作为参数
-
科里化函数封装返回常规函数的科里化函数
-
我们判定当前调用科里化函数的时候传入了多少个参数
-
如果传入参数和目标参数相同,则调用目标函数,完成计算结果
-
如果传入参数没有到达既定的参数数量,我们就继续返回函数
-
代码
// 常规函数
function foo( a,b,c ){
return a + b + c;
}
// 科里化函数
function curry(fn) {
// 在外部记录当前的参数传入了多少
// 记录当前的目标函数的参数数量
let args = [];
let { length } = fn;
// 在内部使用闭包:
function curry_fn(...arg) {
args.push(...arg);
// 如果args数量没有达到目标参数的数量, 那么我们返回当前的函数;
if (args.length < length) {
return "参数不够";
} else {
// 如果参数数量足够了那么我们就调用目标函数执行功能;
return fn(...args);
}
}
return curry_fn;
}
四、xhr的二次封装
4.1、普通封装
思路
-
提取需要改变的数据作为参数来进行封装
-
请求方式需要改变!【method】
-
请求路径需要改变!【url】
-
请求数据需要改变!【data】
-
请求头需要改变! 【headers】
-
响应数据处理需要改变!(重要)回调函数!【callback】
响应数据为什么需要改变,因为我们不知道我们拿到的数据类型是txt还是JSON,
如果是JSON需要格式化,而txt纯文本则不需要
代码
- 封装
// 对于多参数封装我们要把参数放在对象之中
// -. 封装xhr工具
function xhr(options) {
options = {
// 前面写默认参数
// -. 请求方式
method: "GET",
// -. 请求路径
utl: "",
// -. 请求携带数据
data: {},
// -. 请求头
headers: {},
// - 响应数据的处理方式 :
// - text / json
dataType: "json",
// -. 响应处理函数
callback: function () { },
// 后面携带的是用户参数
...options
};
// 注意: 我们只需要formattedDate加工data数据,并不需要返回值,所以不需要写return语句,当然写也没什么。
formattedDate(options);
// -. 查看格式化后的data数据
// console.log( options.data );
// 1. xhr发起请求
// -. 创建xhr实例对象( 这里没有任何需要改变的地方 )
let xhr = new XMLHttpRequest();
// -. 配置xhr对象
// 注意: 我们请求携带数据,如果请求方式是GET,那么数据需要放到url路径上;(将数据和url路径拼接在一起)
if (options.method.toUpperCase() === "GET" && options.data) {
options.url += "?" + options.data;
xhr.open(options.method, options.url);
}
xhr.open(options.method, options.url);
// -. 请求头
for (let attr in options.header) {
console.log(1);
console.log(attr)
// 调用一次setRequestHeader设置一条请求头信息
xhr.setRequestHeader(attr, options.header[attr]);
}
// -. 请求体
// 判断当前的请求方式是不是POST,如果是POST同时携带数据我们把数据放在send参数之中;
if (options.method.toUpperCase() === "POST" && options.data) {
xhr.send(options.data);
} else {
xhr.send();
}
// 2. xhr响应处理
xhr.onload = function () {
let data = xhr.responseText;
// 把响应数据处理格式进行逻辑判断
switch (options.dataType) {
case "json":
data = JSON.parse(data);
break;
}
options.callback(data);
}
}
// 格式化数据
function formattedDate( options ){
let data = "";
for( let attr in options.data ){
data += `&${attr}=${options.data[attr]}`
}
options.data = data.slice( 1 )
}
- 使用
function sendRequest() {
// 传递请求的配置参数
let options = {
method: "POST",
url: "http://localhost:8888/test/fourth",
data: {
name: "jack",
age: 16
},
header: {
"Content-Type": "applicationx-www-form-urlencoded",
},
callback(data) {
console.log("这是响应数据:", data)
}
}
xhr(options);
}
let btn = document.getElementById("btn");
btn.addEventListener("click", sendRequest);
4.2、promise封装
Promise封装核心
-
让xhr函数的返回值是一个Promise对象
-
让响应数据获取结束之后改变Promise对象的状态
-
响应数据作为Promise对象的数据进行放入!
注意: 要把异步程序放入到Promise对象之中;(Promise对象的状态改变都是在异步异步程序完成的);
代码
- 封装
// xhr工具封装
function xhr(options) {
options = {
// -. 请求方式
method: "GET",
// -. 请求路径
url: "",
// -. 数据
data: {},
// -. 请求头
headers: {},
// -. 响应数据类型
dataType: "json",
// -. 回调函数( 响应处理 )
callback: function () { },
...options
}
// 数据格式化
formattedDate(options);
// console.log( options.data )
// 1. 发送请求
// -. 创建xhr实例对象
let xhr = new XMLHttpRequest();
// -. 配置xhr对象
if (options.method.toUpperCase() === "GET" && options.data) {
options.url += "?" + options.data;
xhr.open(options.method, options.url);
} else {
xhr.open(options.method, options.url);
}
// -. 设置请求头
for (let attr in options.headers) {
xhr.setRequestHeader(attr, options.headers[attr]);
}
// -. 设置请求体( 发送数据 )
if (options.method.toUpperCase() === "POST" && options.data) {
xhr.send(options.data);
} else {
xhr.send();
}
// 响应数据处理:
// -. 因为响应数据处理都是异步的,所以我们把异步程序放入到Promise对象之中
// -. 在获取到响应数据之后,改变Promise对象的状态
// 2. 响应处理
return new Promise(resolver => {
xhr.onload = function () {
let data = xhr.responseText;
switch (options.dataType) {
case "json":
data = JSON.parse(data);
break;
}
options.callback(data);
// 改变Promise对象状态:
// -. callback可以保留, 因为这个callback并不影响我们程序执行
resolver(data);
}
})
}
// 加工数据
function formattedDate(options) {
let data = "";
for (let attr in options.data) {
data += `&${attr}=${options.data[attr]}`;
}
options.data = data.slice(1);
}
- 使用(async await 处理Promise响应数据!(推荐))
let btnNode = document.getElementById( "btn" );
// async await 处理Promise响应数据!(推荐)
async function sendRequest(){
let options = {
method: "POST",
url: "http://localhost:8888/test/fourth",
data:{
name: 'jack',
age: 18
},
headers:{
"Content-Type": "application/x-www-form-urlencoded"
},
// callback( data ){
// console.log( "这是响应数据:",data )
// }
}
let data = await xhr( options );
console.log( data )
}
btnNode.addEventListener( "click",sendRequest );
- 使用( then使用Promise对象)
let btnNode = document.getElementById( "btn" );
// then使用Promise对象
function sendRequest(){
let options = {
method: "POST",
url: "http://localhost:8888/test/fourth",
data:{
name: 'jack',
age: 18
},
headers:{
"Content-Type": "application/x-www-form-urlencoded"
},
// callback( data ){
// console.log( "这是响应数据:",data )
// }
}
// 注意: xhr函数的返回值是一个Promise对象
xhr( options )
.then( data=>{console.log( data )} )
}
btnNode.addEventListener( "click",sendRequest );
五、axios的二次封装
封装思路
-
配置基础路径和超时时间
-
请求拦截(显示进度条)
-
响应拦截(关闭进度条)
-
导出二次封装
注意:二次封装的axios里面的配置项都是固定配置选项,不是随意取名的
代码
- 进度条需要借助node安装
// 引入axios
import Axios from 'axios';
import base from './base.js';
// = 进度条
import NProgress from 'nprogress';
// = 使用 nprogress的css样式
import "nprogress/nprogress.css";
// 1. 配置基础路径和超时时间
const instance = Axios.create({
// = 基础路径( baseURL )
// baseURL: "http://localhost:3000",
baseURL: base.hostURL,
// = 超时时间( timeout 单位ms )
timeout: 5000
})
// 2. 请求拦截
// = 开启进度条
instance.interceptors.request.use(
(config)=>{
NProgress.start();
return config;
},
(err)=>{
return Promise.reject(err);// '错误' false
}
);
// 3. 响应拦截
// = 关闭进度条
instance.interceptors.response.use(
(res)=>{
NProgress.done();
return res;
},
(err)=>{
// - Promise.reject() 方法返回一个带有拒绝原因的 Promise 对象。
// = err就是:Promise对象失败状态传递参数为err
// = err就是状态改变传递的实参
// = then监听工具会有形参接收的
return Promise.reject(err)
}
);
// 4. 导出二次封装
export default instance;