1、sort复杂数据排序
// attr:根据该属性排序;rev:升序1或降序-1,不填则默认为1
function sortBy(attr, rev) {
if (rev == undefined)
rev = 1
else (rev) ? 1 : -1
return function (a, b) {
a = Number(a[attr].split('A')[1])
b = Number(b[attr].split('A')[1])
if (a < b)
return rev * -1
if (a > b)
return rev * 1
return 0
}
}
let aa = [{a:'CRA004'},{a:'CRA001'},{a:'CRA003'},{a:'CRA002'},{a:'CRA005'}]
let b = aa.sort(sortBy('a',1))
2、Object.create()、new Object()和{}的区别
字面量和new关键字创建的对象是Object的实例,原型指向Object.prototype,继承内置对象Object
Object.create(arg, pro)创建的对象的原型取决于arg,arg为null,新对象是空对象,没有原型,不继承任何对象;arg为指定对象,新对象的原型指向指定对象,继承指定对象
3、AbortController-中止浏览器请求
使用方法简述:
const controller = new AbortController();
const signal = controller.signal;
setTimeout(()=>controller.abort(),5000); // 5秒后取消接口调用
fetch(url,{signal}).then(res=>{
return response.text();
}).then(text=>{AbortController详解
console.log(text);
})
4、一些常用js方法
- join():
- join() 将数组中元素 组成字符串 ,需要传个参数作为连接符,不传的话默认就是逗号。
- push()
- 在数组 尾部逐个添加 元素,返回结果数组的长度,能接收任意数量参数,push() 修改了原数组。
- pop()
- pop() 移除数组最后一项,返回的是被移除项。修改原数组
- shift()
- shift() 删除数组的第一项元素,返回被删除的元素, 修改原数组
- unshift()
- 向数组的头部添加元素,返回的是结果数组的长度,修改原数组
- sort()
- 将数组按照从小到大的顺序排列, 修改原数组 。
- sort中没有参数时,会按照数组元素对应的ASCII码进行比较和排序
- sort()无法对由两位数以上的数组元素构成的数组进行合理排序
- 出现原因和解决方法
因为sort()方法会首先会调用每个数组数据项的toString()方法,
转换成字符串以后再进行比较,在字符串中"25"<“3”,
解决方法是需要用到sort的参数,此时这个参数叫做比较函数
- 出现原因和解决方法
- sort()的参数——比较函数
示例:使用比较函数将数字数组进行正确排序-
比较函数会接受两个参数,并对两者进行比较
若第一个参数应位于第二个参数之前,则返回一个负数
若第一个参数等于第二个参数,则返回0
若第一个参数应位于第二个参数之后,则返回一个正数
通过以上逻辑的比较函数,会使数组最后变为升序排列,
若要变为降序,只需返回一个负数变为返回一个正数即可(正数变负数,负数变正数)
-
-
比较函数不能对混搭(字符+数字)数组进行排序
-
不能将比较函数用于比较一个不能转化成数字的字符串和数组的排序,
这是因为比较函数会先将字符串转化成数字再比较,当字符串不能转换成数字时,就不能比较大小(不用比较函数,也就是sort不加参数时,比较的是ASCII值,此时可以比较) -
总结:
1. 数组中既有字符串又有数字时,先看看其中的字符串是字母型字符串还是数字型字符串,2. 若是字母型字符串,sort不用带参数,直接比较ASCII值
若是数字型字符串,sort带参数,让比较函数将字符串转换成数字再比较3.对于由对象构成的数组,如何排序?
需求
数组项是对象,现在需要根据对象的某个属性,对数组进行排序
- 将数组按照从小到大的顺序排列, 修改原数组 。
- reverse()
- 数组反转。
- concat()
- 在不影响原数组的情况下,复制了一个数组,将参数添加到副本的尾部,因此若没有传参,就相当于复制了原数组。
- slice()
- slice() 不影响原数组 ,返回原数组指定开始位置 - 结束位置的新数组。 这个位置是数组的下标,当然是从0开始计算,如果只有一个参数,那就是默认第二个参数到尾部。
- 如果不传第二个参数,默认返回到最后,也 不包含 最后一个的哦。 参数是 负数,相当于反着来,这时候就是包含了结束位置, 不包含 开始位置的元素。
- slice() 不影响原数组 ,返回原数组指定开始位置 - 结束位置的新数组。 这个位置是数组的下标,当然是从0开始计算,如果只有一个参数,那就是默认第二个参数到尾部。
- splice()
- 删除任意项元素,需要两个参数:要删除的位置 和 要删除的数量
- 插入任意项元素,需要三个参数:要删除的位置,一个不删 和 要插入的元素。
- 事实证明,是在要插入位置 之前 插入的。
- 替换,其实就是在指定位置删除任意项元素,再插入任意项元素。
- indexOf() 和 lastIndexOf()
- 查找参数元素在数组中的 位置 ,找不到就返回 -1 。那必传参数一定是目标元素咯,还有个可选参数就是要开始查找的起点位置。 indexOf() 从头到尾找,lastIndexOf() 从尾到头找。
5、彩礼问题,第一天1分钱,第二天2分钱,第三天4分钱,第四天8分钱...,一个月后,累计给了多少彩礼?
function aa(n){ // n表示天数
let u = 0.01;
let s=0;
let tip='';
for(let i=0;i<n;i++){
let c = u*(Math.pow(2,i))
s+=c;
if(s>1){
s = Math.floor(s)
}
if(i===n-1){
tip = '第'+(i+1)+'天:'+ c
}
}
return [s,tip];
}
结果:[10737407, '第30天:5368709.12'] ,1073万,吓死人...
6、预览链接也可以实现下载功能
h5 的a标签有个download属性,可以指定下载的文件名
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<!-- 可换成其他的文件类型 -->
<a href="https://itsharer.oss-cn-beijing.aliyuncs.com/tmp/%E5%8C%85%E5%A4%84%E7%90%86%E6%B5%81%E7%A8%8B.pdf">点我预览</a>
<p id="download"></p>
</body>
<script>
const download = document.getElementById("download");
const loadFileToBlob = function(url, callback) {
if (!url || !callback) return false;
var xhr = new XMLHttpRequest();
xhr.open('get', url, true);
xhr.responseType = 'blob';
xhr.onload = function() {
callback(this.status == 200 ? this.response : false);
}
xhr.send();
return true;
}
const load = () => {
loadFileToBlob("https://itsharer.oss-cn-beijing.aliyuncs.com/tmp/%E5%8C%85%E5%A4%84%E7%90%86%E6%B5%81%E7%A8%8B.pdf", function(blobFile) {
if (!blobFile) return false;
download.innerHTML = '<a download="aaa.pdf" href="' + window.URL.createObjectURL(blobFile) + '" target="_blank">文件下载</a>';
})
}
load()
</script>
</html>
当遇到跨域问题的时候,本地启动node服务器:
serve.js
import http from 'http';
import path from 'path'
import fs from 'fs';
import url from 'url';
import c from 'child_process';
// 代理配置
let conifg = {
'/api': { // 需要拦截的本地请求路径
target: 'http://t.weather.itboy.net', // 真实代理地址 CRP服务
// target: 'http://10.31.27.199', // 真实代理地址 target: 'http://10.31.27.199:8087/', 林凤颜
// port: 8087, // 端口,默认80
},
};
// 创建http服务
let app = http.createServer(function (request, response) {
let urls = request.url === '/' ? 'index.html' : request.url;
// 存在代理地址,走代理请求
if (hasProxy(urls, request, response)) {
return;
}
var pathname = url.parse(request.url).pathname;
var extname = path.extname(pathname);
// 普通请求和资源加载
fs.readFile(pathname.substr(1), function (err, data) {
let type = memu(extname);
if (err) {
console.log('请求失败', err);
response.writeHead(404, {'Content-Type': type});
}else{
response.writeHead(200, {
'Content-Length': data.length,
'Content-Type': type
});
// 响应文件内容
response.write(data);
}
// 发送响应数据
response.end();
});
});
function memu (exname) {
switch(exname){
case ".html":
return "text/html";
break;
case ".css":
return "text/css";
break;
case ".jpg":
return "image/jpg";
break;
case ".png":
return "image/png";
break;
case ".js":
return "text/javascript";
break;
case ".json":
return "text/json";
break;
case ".jpeg":
return "image/jpeg";
break;
case ".gif":
return "image/gif";
break;
case ".svg":
return "image/svg+xml";
break;
case ".rtf":
return "application/rtf";
break;
case ".woff":case ".woff2":
return "application/x-font-woff";
break;
case ".webm":
return "video/webm";
break;
default:
return "text/plain";
}
}
// 判断是否存在代理地址
function hasProxy (url, request, response) {
for (const key in conifg) {
if (url.indexOf(key) < 0) {
continue;
}
const { target, port } = conifg[key];
let info = target.split('//');
let opts = { // 请求参数
protocol: info[0],
host: info[1],
port: port || 80,
method: request.method,
path: url,
json: true,
headers: {
...request.headers,
host: info[1],
referer: target + url
}
}
proxy(opts, request, response);
return true;
}
return false;
}
// 代理转发
function proxy(opts, request, response) {
// 请求真实代理接口
var proxyRequest = http.request(opts, function (proxyResponse) {
// 代理接口返回数据,写入本地response
proxyResponse.on('data', function (chunk) {
response.write(chunk, 'binary');
});
// 代理接口结束,通知本地response结束
proxyResponse.on('end', function () {
response.end();
});
response.writeHead(proxyResponse.statusCode, proxyResponse.headers);
});
// 本地接口数据传输,通知代理接口请求
request.on('data', function (chunk) {
proxyRequest.write(chunk, 'binary');
});
// 本地请求结束,通知代理接口请求结束
request.on('end', function () {
proxyRequest.end();
});
}
app.listen(9001);
c.exec('start http://localhost:9001/index.html'); // 启动服务器
console.log('server is listen on 9001....');
下载文件页面:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<!-- 可换成其他的文件类型 -->
<a href="/api/weather/city/101010100 ">点我预览</a>
<p id="download"></p>
</body>
<script>
const download = document.getElementById("download");
const loadFileToBlob = function(url, callback) {
if (!url || !callback) return false;
var xhr = new XMLHttpRequest();
xhr.open('get', url, true);
xhr.responseType = 'blob';
xhr.onload = function() {
callback(this.status == 200 ? this.response : false);
}
xhr.send();
return true;
}
const load = () => {
loadFileToBlob("/api/weather/city/101010100 ", function(blobFile) {
if (!blobFile) return false;
download.innerHTML = '<a download="bbb.json" href="' + window.URL.createObjectURL(blobFile) + '" target="_blank">文件下载</a>';
})
}
load()
</script>
</html>
7、tabindex 的作用
<div class="container" ref="container">
<p tab-index="-1">Inside the trap</p>
<p tab-index="-1">Can't break out</p>
<p tab-index="-1">Stuck here forever</p>
</div>
它接受一个整数作为值,具有不同的结果,具体取决于整数的值:
- tabindex=负值 (通常是 tabindex=“-1”),表示元素是可聚焦的,但是不能通过键盘导航来访问到该元素,用 JS 做页面小组件内部键盘导航的时候非常有用。
tabindex="0"
,表示元素是可聚焦的,并且可以通过键盘导航来聚焦到该元素,它的相对顺序是当前处于的 DOM 结构来决定的。- tabindex=正值,表示元素是可聚焦的,并且可以通过键盘导航来访问到该元素;它的相对顺序按照tabindex 的数值递增而滞后获焦。如果多个元素拥有相同的 tabindex,它们的相对顺序按照他们在当前 DOM 中的先后顺序决定。
根据键盘序列导航的顺序,值为 0
、非法值、或者没有 tabindex 值的元素应该放置在 tabindex 值为正值的元素后面。
8、vue3 文件内容对比v-code-diff
默认支持以下内容对比
- plaintext
- xml/html
- javascript
- json
- yaml
- python
- java
- bash
- sql
安装:
yarn add v-code-diff
引入:import CodeDiff from 'v-code-diff';
app.use(i18)
.use(createPinia())
.use(router)
.use(CodeDiff)
.mount('#app')
使用:
<script setup lang="ts">
const data = ref({
oldStr: [
{
date: '2016-05-02',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄',
},
{
date: '2016-05-04',
name: '王小虎',
address: '上海市普陀区金沙江路 1517 弄',
},
{
date: '2016-05-01',
name: '虎',
address: '上海市普路 1519 弄',
},
{
date: '2016-05-03',
name: '王',
address: '上海市普陀区金沙江路 1516 弄',
},
],
newStr: [
{
date: '2016-05-02',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄',
},
{
date: '2016-05-04',
name: '王小虎',
address: '上海市普陀区金沙江路 1517 弄',
},
{
date: '2016-05-01',
name: '王小虎',
address: '上海市普陀区金沙江路 1519 弄',
},
{
date: '2016-05-03',
name: '王小虎',
address: '上海市普陀区金沙江路 1516 弄',
},
],
});
const oldStrToCompare = computed(() =>{
return JSON.stringify(data.value.oldStr, null, 2) //重点! 格式化添加空格
})
const newStrToCompare = computed(()=> {
return JSON.stringify(data.value.newStr, null, 2)//重点! 格式化添加空格
})
const diffEvent = (val:object) => { // 事件 返回对比结果
console.log(1,val)
}
</script>
<template>
<div class="compare">
<code-diff
language="json" // 不传 默认text对比
:old-string="oldStrToCompare"
:new-string="newStrToCompare"
file-name="test.txt"
@diff="diffEvent"
output-format="side-by-side"/>
</div>
</template>
<style lang="scss" scoped>
.center {
max-height: 600px;
overflow-y: auto;
}
</style>
9、函数的柯里化
柯里化就是将多个入参的函数拆分成多个函数,每个函数只接受一个参数;
10、Glob 相关
如在项目.gitignore文件中的使用:
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
.DS_Store
dist
dist-ssr
coverage
*.local
/cypress/videos/
/cypress/screenshots/
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
*.tsbuildinfo
11、数组reduce方法计数
const DATA = [
{ id: "todo-0", name: "Eat", completed: true },
{ id: "todo-1", name: "Sleep", completed: false },
{ id: "todo-2", name: "Repeat", completed: false },
]
const doneCount = DATA.reduce((pre, done) => pre + (done.completed?1:0 ), 0);
// 第1个参数 上1个计数 是否满足条件 起始计数
console.log(doneCount)