1、截取url地址栏指定参数
获取地址栏参数,可能会有多个参数,取第一个不一定对,所以需要截取指定参数的值
// 获取地址栏参数
function GetRequest() {
var url = location.search; //获取url中"?"符后的字串 http://y.qq.com?projectId=29&userType=3
var theRequest = new Object();
if (url.indexOf("?") != -1) {
var str = url.substr(1);
strs = str.split("?");
console.log(strs)//["projectId=29"]
for (var i = 0; i < strs.length; i++) {
theRequest[strs[i].split("=")[0]] = decodeURIComponent(strs[i].split("=")[1]);
}
}
return theRequest;
}
//调用
var a=GetRequest();
var projectId = a['projectId'];
console.log(projectId,'projectId')//29
function transformParams() {
var params = location.search.substring(1);
return params.split('&').map(item => {
var index = item.indexOf('=')
if (index == -1) {
return {
[item]: null
}
}
var key = item.slice(0, index);
val = item.slice(index + 1)
return {
[key]: val
}
})
}
function getQueryString(name) {
let reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i");
let r = window.location.search.substr(1).match(reg);
if (r != null) {
return unescape(r[2]);
};
return null;
}
getQueryString('token') // token串
transformParams()
// http://localhost:3000/nx-temp13-k8s/app?code=8b7bf92b-4911-4b69-9ca4-ba9929a72876#/InvAcctgJournalCheckExceptionView/list
[
{
"code": "8b7bf92b-4911-4b69-9ca4-ba9929a72876"
}
]
2、处理字符串,截取某个字符前后值
function getCaption(str) {
let index = str.lastIndexOf('\,');
let strFront = str.substring(index + 1, str.length);
let strAfter = str.substring(0, index);
this.after = strAfter;//hello
this.front = strFront;//word
}
let str = 'hello,word';
getCaption(str)
3、使用moment 第三方插件格式化日期
安装:npm install moment --save
引用:import moment from 'moment';
使用:
getTimeFn() {
const end = new Date();
const start = new Date();
start.setTime(start.getTime() - 3600 * 1000 * 24 * 89);//默认返现3个月日期
this.ruleForm.startDate = moment(start).format('YYYY-MM-DD');
this.ruleForm.endDate = moment(end).format('YYYY-MM-DD');
}
4、千分符
function qffformat(num) {
var reg = /\d{1,3}(?=(\d{3})+$)/g;
return (num + "").replace(reg, "$&,");
}
qffformat('123456789')//"123,456,789"
5、vue全局注册,全局按需引入
- 初始化插件对象需要通过Vue.use(),插件对象中必须有install方法
- 每一个vue组件都是Vue的实例,所以组件内this可以拿到Vue.prototype上添加的属性和方法。
// 下拉树 tree
import Treeselect from '@riophae/vue-treeselect';
import '@riophae/vue-treeselect/dist/vue-treeselect.css';
// 全局注册树
Vue.component('treeselect', Treeselect);
// 按需引入 Element
import './libs/js/elementUi';
import 'element-ui/lib/theme-chalk/index.css';
//挂在全局使用
Vue.prototype.$axios = axios;
Vue.prototype.$loading = loading;
Vue.prototype.$api = api;
this.$axios.post(this.$api.info)
this.$loading.open();
6、自动补全2位小数,一位补0
function returnSmallNumber(valueParam) {
let value = Math.round(parseFloat(valueParam) * 100) / 100;
let xsd = value.toString().split('.');
if (xsd.length == 1) {
value = value.toString() + '.00';
return value;
}
if (xsd.length > 1) {
if (xsd[1].length < 2) {
value = value.toString() + '0';
}
return value;
}
}
returnSmallNumber(1.2)//1.20 (1 -> 1.00)
7、el-input 输入框限制最大值、保留小数点2位
<el-input
v-model="ruleForm.gdsylzcStart"
type="number"
></el-input>
watch: {
'ruleForm.gdsylzcStart': function (newVal, oldVal) {
// 解决数字键盘可以输入输入多个小数点问题
if (newVal === '' && oldVal.toString().indexOf('.') > 0) {
this.ruleForm.gdsylzcStart = oldVal;
return;
}
// 保留两位小数
if (newVal) {
newVal = newVal.toString();
let pointIndex = newVal.indexOf('.');
if (pointIndex > 0 && newVal.length - pointIndex > 3) {
this.ruleForm.gdsylzcStart = oldVal;
return;
}
}
// 最大值
if (newVal > 100) {
this.ruleForm.gdsylzcStart = oldVal;
return;
}
}
}
8、el-input 输入框根据参数(n)保留小数点n位
/**
* @author m
* @description 自动补全n位小数
* @param (value) 值 (num) 位数
*/
function formatNumber(value, num) {
if (value && !isNaN(value)) {
let a, b, c, i;
a = value.toString();
b = a.indexOf('.');
c = a.length;
if (num == 0) {
if (b != -1) {
a = a.substring(0, b);
}
} else {
//如果没有小数点
if (b == -1) {
a = a + '.';
for (i = 1; i <= num; i++) {
a = a + '0';
}
} else {
//有小数点,超出位数自动截取,否则补0
a = a.substring(0, b + num + 1);
for (i = c; i <= b + num; i++) {
a = a + '0';
}
}
}
return a;
} else {
return '';
}
}
formatNumber(3.256, 4) // 3.2560
9、el-input 行内校验
<!-- 只允许输入数字和一位小数点和小数点后两位 并且首位不能为小数点 -->
<el-input type="text" onkeyup="value= value.match(/\d+(\.\d{0,2})?/) ? this.value.match(/\d+(\.\d{0,2})?/)[0] : ''" >
<!-- 只能输入英文 -->
<el-input type="text" onkeyup="value=value.replace(/[^a-zA-Z]/g,'')">
<!-- 只能输入字母和数字 -->
<el-input oninput="value=value.replace(/[^\w\.\/]/ig,'')">
<!--只能输入数字-->
<el-input type='text' onkeyup="this.value=this.value.replace(/[^0-9-]+/,'');" />
<!--只能输入数字和小数点-->
<el-input type="text" onkeyup="this.value=this.value.replace(/[^0-9.]/g,'')" />
<!--只能输入正数,小数点后保留两位-->
<el-input type="text" onkeyup="this.value= this.value.match(/\d+(\.\d{0,2})?/) ? this.value.match(/\d+(\.\d{0,2})?/)[0] : ''" />
<!--只能输入字母和汉字 禁止特殊字符-->
<el-input type="text" onkeyup="value=value.replace(/[^\a-zA-Z\u4E00-\u9FA5]/g,'')" onbeforepaste="clipboardData.setData('text',clipboardData.getData('text').replace(/[^\a-zA-Z\u4E00-\u9FA5]/g,''))"/>
<!--有时候输入框是对象的方式渲染的,想要控制各个对象的输入校验(不能小于?, 不能大于?),可以通过@input.native根据event处理-->
<el-input
v-model="scope.row.ratio"
type="Number"
:min="0"
:max="100"
@input.native="validateInput($event, scope.row)"
/>
// 校验方法
validateInput(e, row) {
// 验证是否是纯数字
// let isNumber = /^\d*$/.test(e.target.value);
// 过滤非数字
e.target.value = e.target.value.replace(/\D/g, "");
if (e.target.value <= 0) {
e.target.value = 1;
}
if ( e.target.value > row.orderNum) {
e.target.value = row.orderNum;
}
},
10、首字母大小、下划线转驼峰、是否是数字
// 首字母大小
function titleCase(str) {
return str.replace(/( |^)[a-z]/g, L => L.toUpperCase())
}
titleCase(str="abcd") //"Abcd"
// 下划转驼峰
function camelCase(str) {
return str.replace(/-[a-z]/g, str1 => str1.substr(-1).toUpperCase())
}
camelCase(str="my-test") //"myTest"
function isNumberStr(num){
return /^[+-]?(0|([1-9]\d*))(\.\d+)?$/g.test(num)
}
isNumberStr(num="2")//true num="a" false
11、截取今天前30天按月
function createBeginDate(month = 1) {
let date = new Date();
date.setMonth(date.getMonth() - month);
date.toLocaleDateString();
let y = date.getFullYear();
let m = date.getMonth() + 1;
m = m < 10 ? '0' + m : m;
let d = date.getDate();
d = d < 10 ? '0' + d : d;
const time = y + '-' + m + '-' + d;
return time;
}
createBeginDate(1)//2021-03-26 传0是今天,传n是n月
12、截取今天前30天按日
function createBeginDateDay(agoDay,nowDay) {
let date1 = new Date();
let date2 = new Date(date1);
let getDate1 = date1.getDate() < 10 ? `0${date1.getDate()}` : date1.getDate();
let getDate2 = date2.getDate() < 10 ? `0${date2.getDate()}` : date2.getDate();
//-30为30天前,+30可以获得30天后的日期
date2.setDate(date1.getDate() - agoDay);
//30天前(月份判断是否小于10,小于10的前面+0)
agoDay = `${date2.getFullYear()}-${
date2.getMonth() + 1 < 10
? `0${date2.getMonth() + 1}`
: date2.getMonth() + 1
}-${getDate2}`;
//当前日期
nowDay = `${date1.getFullYear()}-${
date1.getMonth() + 1 < 10
? `0${date1.getMonth() + 1}`
: date1.getMonth() + 1
}-${getDate1}`;
return [agoDay, nowDay];
}
// 第一个参数是n天前的日期,第二个参数是当天的日期(今天的日期不用传,只取时候用)
createBeginDateDay(30) //2021-03-27至2021-04-26
13、截取今天之前 n天的日期
默认1个月 30天,半年180天,一年365天
/**
* @param manyDayBeforeNowDay(agoDay = n天,nowDay不用传) 第一个参数[0]获取当前n天的日期,
* 第二个参数[1]不用传(默认获取今天的日期)
*/
function manyDayBeforeNowDay(agoDay, nowDay) {
if (agoDay * 1) {
return [
timeStampToFormdate(new Date().getTime() - agoDay * 60 * 60 * 24 * 1000),
(nowDay = toDay()),
];
} else {
return [];
}
}
function toDay() {
let date = new Date();
let year = date.getFullYear();
let month = date.getMonth() + 1;
month = month < 10 ? '0' + month : month;
let day = date.getDate() < 10 ? '0' + date.getDate() : date.getDate();
return `${year}-${month}-${day}`;
}
function timeStampToFormdate(timestamp) {
if (!timestamp) {
return '';
}
var date =
timestamp.toString().length == '13'
? new Date(timestamp)
: new Date(timestamp * 1000); //时间戳为10位需*1000,时间戳为13位的话不需乘1000
var Y = date.getFullYear() + '-';
var M =
(date.getMonth() + 1 < 10
? '0' + (date.getMonth() + 1)
: date.getMonth() + 1) + '-';
var D = date.getDate() < 10 ? '0' + date.getDate() : date.getDate();
var h =
date.getHours() < 10 ? '0' + date.getHours() + ':' : date.getHours() + ':';
var m =
date.getMinutes() < 10
? '0' + date.getMinutes() + ':'
: date.getMinutes() + ':';
var s = date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds();
return Y + M + D;
// return Y + M + D + ' ' + h + m + s;
}
manyDayBeforeNowDay(30) //["2021-05-25", "2021-06-24"]
14、获取当前时间,自动轮询计算下一秒时间
function timeRun(time) {
let timeJoin = time.split(':');
let hour = timeJoin[0];
let minute = timeJoin[1];
let second = timeJoin[2];
let ymd;
this.timeRunSetInterval = setInterval(() => {
if (second == 59) {
second = '00';
if (minute == 59) {
minute = '00';
if (hour == 23) {
hour = '00';
} else {
hour++;
if (hour <= 9) {
hour = '0' + hour;
}
}
} else {
minute++;
if (minute <= 9) {
minute = '0' + minute;
}
}
} else {
second++;
if (second <= 9) {
second = '0' + second;
}
}
ymd = hour + ':' + minute + ':' + second;
console.log(ymd)//17:20:15 17:20:16 17:20:17 ...
}, 1000);
}
timeRun('17:20:14')
15、获取今天的日期
直接调用方法获取今天日期 toDay() "2021-06-04"
// let dddd = 'Fri Dec 10 2021 00:00:00 GMT+0800 (中国标准时间)'
// let date = new Date(dddd); //处理自定义的日期编码
function toDay() {
let date = new Date();
let year = date.getFullYear();
let month = date.getMonth() + 1;
month = month < 10 ? '0' + month : month;
let day = date.getDate() < 10 ? '0' + date.getDate() : date.getDate();
return `${year}-${month}-${day}`
}
toDay() // "2021-06-04"
16、table 表格分页计算
/**
* @description 添加序号索引
* @param pageNum 页数
*/
function createIndex(pageNum, i, size) {
i = parseInt(i);
size = parseInt(size);
return (pageNum - 1) * size + i + 1;
}
data.rows.map((item, i) => {
//id: table表格序号
let id = createIndex(this.searchForm['pageNum'],i,this.searchForm['pageSize']);
}
17、取数组的最大值|最小值
function getMin(arr) {
let ary = [];
if (arr.length >= 1) {
for (let i = 0; i < arr.length; i++) {
if (arr[i] !== '' && arr[i] !== null && arr[i] !== undefined) {
ary.push(arr[i]);
}
}
return Math.min(...ary);
} else {
return 0;
}
}
function getMax(arr) {
let ary = [];
if (arr.length >= 1) {
for (let i = 0; i < arr.length; i++) {
if (arr[i] != '' && arr[i] !== null && arr[i] !== undefined) {
ary.push(arr[i]);
}
}
return Math.max(...ary);
} else {
return 0;
}
}
getMin([0.254,1.25,5,4,0.9885,3.5,5.5,9.8])//0.254
getMax([0.254,1.25,5,4,0.9885,3.5,5.5,9.8])//9.8
18、数字转化大写金额
调用 changeNum(1000)方法 参数传金额
function changeNum(money) {
var cnNums = new Array("零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"); //汉字的数字
var cnIntRadice = new Array("", "拾", "佰", "仟"); //基本单位
var cnIntUnits = new Array("", "万", "亿", "兆"); //对应整数部分扩展单位
var cnDecUnits = new Array("角", "分", "毫", "厘"); //对应小数部分单位
var cnInteger = "整"; //整数金额时后面跟的字符
var cnIntLast = "元"; //整型完以后的单位
var maxNum = 999999999999999.9999; //最大处理的数字
var IntegerNum; //金额整数部分
var DecimalNum; //金额小数部分
var ChineseStr = ""; //输出的中文金额字符串
var parts; //分离金额后用的数组,预定义
var Symbol = ""; //正负值标记
if (money == "") {
return "";
}
money = parseFloat(money);
if (money >= maxNum) {
alert('超出最大处理数字');
return "";
}
if (money == 0) {
ChineseStr = cnNums[0] + cnIntLast + cnInteger;
return ChineseStr;
}
if (money < 0) {
money = -money;
Symbol = "负 ";
}
money = money.toString(); //转换为字符串
if (money.indexOf(".") == -1) {
IntegerNum = money;
DecimalNum = '';
} else {
parts = money.split(".");
IntegerNum = parts[0];
DecimalNum = parts[1].substr(0, 4);
}
if (parseInt(IntegerNum, 10) > 0) { //获取整型部分转换
var zeroCount = 0;
var IntLen = IntegerNum.length;
for (var i = 0; i < IntLen; i++) {
var n = IntegerNum.substr(i, 1);
var p = IntLen - i - 1;
var q = p / 4;
var m = p % 4;
if (n == "0") {
zeroCount++;
} else {
if (zeroCount > 0) {
ChineseStr += cnNums[0];
}
zeroCount = 0; //归零
ChineseStr += cnNums[parseInt(n)] + cnIntRadice[m];
}
if (m == 0 && zeroCount < 4) {
ChineseStr += cnIntUnits[q];
}
}
ChineseStr += cnIntLast;
//整型部分处理完毕
}
if (DecimalNum != '') { //小数部分
var decLen = DecimalNum.length;
for (var i = 0; i < decLen; i++) {
var n = DecimalNum.substr(i, 1);
if (n != '0') {
ChineseStr += cnNums[Number(n)] + cnDecUnits[i];
}
}
}
if (ChineseStr == '') {
ChineseStr += cnNums[0] + cnIntLast + cnInteger;
} else if (DecimalNum == '') {
ChineseStr += cnInteger;
}
ChineseStr = Symbol + ChineseStr;
return ChineseStr;
}
//changeNum(12345) "壹万贰仟叁佰肆拾伍元整"
19、递归处理树结构
const data = [{
id: 1,
title: "课程 1",
children: [
{
id: 4,
title: "课程 1-1"
},
{
id: 5,
title: "课程 1-2",
children: [{
id: 6,
title: "课程 1-2-1"
},
{
id: 7,
title: "课程 1-2-2"
},
],
},
],
},
{
id: 2,
title: "课程 2"
},
{
id: 3,
title: "课程 3"
},
];
const formatData = (data) => {
const newArr = [];
const callFn = (root, newArr) => {
let currentArr;
if (Array.isArray(root)) {
currentArr = root;
} else {
newArr.push(root);
currentArr = root.children;
}
if (!currentArr || !currentArr.length) return;
for (let i = 0; i < currentArr.length; ++i) {
callFn(currentArr[i], newArr);
}
};
callFn(data, newArr);
newArr.forEach(item => {
if (item.children) delete item.children
})
return newArr;
};
console.log(formatData(data))
// 创建一个辅助函数用于递归构建带有折叠功能的DOM节点
<div id="courses-tree"></div>
function createTreeNodes(course, level = 0) {
const li = document.createElement('li');
li.dataset.id = course.id;
const titleSpan = document.createElement('span');
titleSpan.textContent = `${' '.repeat(level)}${course.title}`;
li.appendChild(titleSpan);
// 折叠按钮
const toggleBtn = document.createElement('button');
toggleBtn.textContent = '[-]';
toggleBtn.addEventListener('click', () => {
const childrenUL = li.querySelector('ul');
if (childrenUL) {
childrenUL.style.display = childrenUL.style.display === 'none' ? 'block' : 'none';
}
toggleBtn.textContent = toggleBtn.textContent === '[+]' ? '[-]' : '[+]';
});
li.appendChild(toggleBtn);
if (course.children && course.children.length > 0) {
const childrenUL = document.createElement('ul');
course.children.forEach(child => {
childrenUL && childrenUL.appendChild(createTreeNodes(child, level + 1));
});
li.appendChild(childrenUL);
if (childrenUL) {
childrenUL.style.display = 'none'; // 初始时子项隐藏
}
}
return li;
}
// 将课程列表转换为DOM元素并插入到页面中某个容器内
const treeContainer = document.getElementById('courses-tree');
options.forEach(course => {
treeContainer.appendChild(createTreeNodes(course));
});
treeContainer
20、日期编码格式转为标准日期,日期大小比较
let bigDate = 'Fri Dec 12 2021 00:00:00 GMT+0800 (中国标准时间)';
let bigDate2 = "Fri Dec 12 2021 00:00:00 GMT+0800 (中国标准时间)";
function toDay(dates) {
// let date = new Date(dates);
let dddd = 'Fri Dec 10 2021 00:00:00 GMT+0800 (中国标准时间)'
let date = new Date(dddd);//自定义的格式
let year = date.getFullYear();
let month = date.getMonth() + 1;
month = month < 10 ? '0' + month : month;
let day = date.getDate() < 10 ? '0' + date.getDate() : date.getDate();
return `${year}-${month}-${day} 00:00:00`
}
let t1 = toDay(bigDate)
let t2 = toDay(bigDate2)
function tab(date1,date2){
var oDate1 = new Date(date1);
var oDate2 = new Date(date2);
if(oDate1.getTime() == oDate2.getTime()){
console.log('相等')
}else if(oDate1.getTime() !== oDate2.getTime()) {
console.log('不想等')
}
if(oDate1.getTime() > oDate2.getTime()){
console.log('第一个大');
} else if(oDate1.getTime() < oDate2.getTime()){
console.log('第二个大');
}else {}
}
tab(t1,t2);
21、巧用数组方法判断日期是否相等
let viewItemsReturnDate = ['Thu Dec 16 2021 00:00:00 GMT+0800 (中国标准时间)',
'Thu Dec 17 2021 00:00:00 GMT+0800 (中国标准时间)','Thu Dec 18 2021 00:00:00 GMT+0800 (中国标准时间)'];
let t1 = 'Thu Dec 16 2021 00:00:00 GMT+0800 (中国标准时间)';
let t2 = 'Thu Dec 18 2021 00:00:00 GMT+0800 (中国标准时间)';
let allEqual = false;
//调用toDay 方法转位日期,去比对大小
if (viewItemsReturnDate.length > 0) {
viewItemsReturnDate.map(item => {
let t1 = this.toDay(viewItemsReturnDate[0]);
let t2 = this.toDay(item);
allEqual = t1 == t2 ? true : false;
})
}
if(!allEqual){
// 不相等
}else {
//相等
}
22、判断数组中的每一项是否相等
function isAllEqual(array) {
if (array.length > 0) {
return !array.some(function(value, index) {
return value !== array[0];
});
} else {
return true;
}
}
isAllEqual([1,1,2]) // false
23、数组对象里 item 里有重复的,那么保留ary初始化的,去掉 item 里新增的
let ary = [
{
name:"ha",
key: 'StockTransfer',
},
{
name:"he",
key: 'MiscIssue',
},
];
let item = [];
item.push(
{
name:"hi",
key: 'MiscReceipt',
},
{
name:"ha",
key: 'StockTransfer',
}
)
let hash = {};
const newAry = item.reduce((cur, next) => {
hash[next.key] ? "" : hash[next.key] = true && cur.push(next);
return cur;
}, [])
24、数组中的值是否相等
let ary = [
"2022-04-20T16:00:00.000Z",
"2022-04-20T16:00:00.000Z",
"2022-04-20T16:00:00.000Z"
]
// 判断是否相等
function isAllEqual(array) {
if (array.length > 0) {
return !array.some((value, index) => {
return value !== array[0];
});
} else {
return true;
}
}
isAllEqual(ary) // true
let allEqualtakeT;
if (ary.length > 0) {
takeT = ary.join(",") + ",";
}
for(let i = 0;i < ary.length; i++){
allEqual = takeT.replace(ary[i] + ",", "").indexOf(ary[i] + ",") > -1
}
console.log(allEqual)// true
25、把obj对象里的值覆盖到newobj里面
有两个对象,需要用某个对象覆盖另一个对象的,根据属性来覆盖
let obj = {
a:"1",
b:"2"
}
let newobj = {
a:"10",
b:"20"
}
function deepCopy(newobj, obj) {
if (typeof obj != 'object') {
return obj
}
for (var attr in obj) {
var a = {}
if (newobj[attr]) {
a = newobj[attr]
}
newobj[attr] = deepCopy(a, obj[attr])
}
return newobj
}
deepCopy(newobj,obj)
// {a: '1', b: '2'}
26、不足位数前面补0 & 后缀补0
不足位数前面补0&后缀补0,length是值的总位数
function PrefixInteger(num, length) {
return (Array(length).join('0') + num).slice(-length)
}
function SuffixInteger(num, length) {
return (num + Array(length).join('0')).slice(-length)
}
PrefixInteger(4,9) // '000000004'
SuffixInteger(4,9) //'400000000'
27、防抖与节流
防抖 (Debouncing) 的含义是指在一定时间内,多次触发同一个事件,只执行最后一次操作。例如,当我们在搜索框中输入关键词时,输入框会不断触发 oninput 事件,如果每次输入都去请求服务器获取数据,会造成不必要的请求浪费。此时就可以使用防抖技术,将一定时间内的多次触发合并为一次操作,只请求一次服务器数据,减少了请求次数和服务器负载。
节流 (Throttling) 的含义是指在一定时间内,多次触发同一个事件,只执行第一次操作。例如,当我们拖动网页上的滚动条时,会不断触发 onscroll 事件,如果每次触发都去计算滚动距离,会造成浏览器性能下降。此时就可以使用节流技术,将一定时间内的多次触发限制为一次操作,只计算一次滚动距离,提高了浏览器性能和用户体验。
/* 防抖函数 */
export const debounce = (fn, wait) => {
let timer = null;
return function () {
let context = this,
args = arguments;
if (timer) {
clearTimeout(timer);
timer = null;
}
timer = setTimeout(() => {
fn.apply(context, args);
}, wait);
};
};
/* 节流函数 */
export const throttle = (fn, delay) => {
let curTime = Date.now();
return function () {
let context = this,
args = arguments,
nowTime = Date.now();
if (nowTime - curTime >= delay) {
curTime = Date.now();
return fn.apply(context, args);
}
};
};
28、深拷贝与浅拷贝
对象属于引用类型的值,会在浏览器的栈内存中存一个十六进制的地址,指向对象的堆内存。
浅拷贝就是创建一个新对象,这个对象有着原始属性值的一份精准拷贝。
如果属性是基本类型,拷贝的就是基本类型的值;如果是引用类型,拷贝的就是内存地址。
修改同一份内存地址中的值,就会影响到另一个对象的原有值。
let schemaObj = {
code: 1,
templateId: "12345678",
rangeWork: "view",
function: () => {}
}
// 浅拷贝
let schemaObj1 = schemaObj;
schemaObj1.rangeWork = "add";
console.log(schemaObj.rangeWork) // add
console.log(schemaObj1.rangeWork)// add
// 深拷贝
let schemaObj2 = {...schemaObj}; // 等同于 Object.assign({}, schemaObj);
schemaObj2.rangeWork = "add";
console.log(schemaObj.rangeWork) // view
console.log(schemaObj2.rangeWork)// add
// 这种方法虽然可以实现数组或对象深拷贝,但不能处理函数和正则,因为这两者基于JSON.stringify和JSON.parse处理后,得到的正则就不再是正则(变为空对象),得到的函数就不再是函数(变为null)了。
let schemaObj3 = JSON.parse(JSON.stringify(schemaObj));
schemaObj3.rangeWork = "add";
console.log(schemaObj.rangeWork) // view
console.log(schemaObj3.rangeWork)// add
// 调用封装的 deepClone
let schemaObj4 = deepClone(schemaObj);
schemaObj4.rangeWork = "add";
console.log(schemaObj.rangeWork) // view
console.log(schemaObj4.rangeWork)// add
// 封装递归方法
function deepClone(obj, hash = new WeakMap()) {
if (obj === null) return obj; // 如果是null或者undefined我就不进行拷贝操作
if (obj instanceof Date) return new Date(obj);
if (obj instanceof RegExp) return new RegExp(obj);
// 可能是对象或者普通的值 如果是函数的话是不需要深拷贝
if (typeof obj !== "object") return obj;
// 是对象的话就要进行深拷贝
if (hash.get(obj)) return hash.get(obj);
let cloneObj = new obj.constructor();
// 找到的是所属类原型上的constructor,而原型上的 constructor指向的是当前类本身
hash.set(obj, cloneObj);
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
// 实现一个递归拷贝
cloneObj[key] = deepClone(obj[key], hash);
}
}
return cloneObj;
}
/**
* 【对象】
* 扩展 jQuery.extend()方法 -> $.extend(true, {}, schemaObj)//第一个参数为true,就是深拷贝
* 函数库lodash的_.cloneDeep方法 -> _.cloneDeep(schemaObj)
*
/
29、根据url地址转换为file文件
音频地址(audio.mp3),转换为file文件
// url地址转file文件,设置文件名称
function handerUrlToFile(fileUrl) {
if (!fileUrl) return;
fetch(fileUrl)
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.blob();
})
.then(blob => {
const speakerName = fileUrl.split('/').pop();
const urlSuffix = fileName.split('.').pop();
const audioOrgFile = new File([blob], `${fileName}`, {
type: `audio/${urlSuffix}`,
});
console.log(audioOrgFile, 'audioOrgFile');
console.log(speakerName, 'speakerName');
this.audioOrgFile = audioOrgFile;
this.speakerName = speakerName;
})
.catch(error => {
console.error('There has been a problem with your fetch operation:', error);
});
}
let formdata = new FormData();
formdata.append('file', this.audioOrgFile);
formdata.append('speakerName', this.speakerName);
30、使用 Promise 实现防止重复请求
const preventReqMore = (fn, p = null) => {
return (...argv) => {
p = p ? p : fn(...argv).finally(() => {
p = null
})
return p
}
}
// 可以简写成一行
// const preventReqMore = (fn, p = null) => (...argv) => p ? p : (p = fn(...argv).finally(() => (p = null)))
let fetchReq = () => {
return new Promise((resolve) => {
setTimeout(() => {
console.log('Request completed');
resolve();
}, 1000);
});
};
let fetchReqPrevented = preventReqMore(fetchReq);
fetchReqPrevented();
fetchReqPrevented(); // 会被阻止,不会发起请求
31、生成 uuid 的方法
const uuid = (a) => a ? (a ^ ((Math.random() * 16) >> (a / 4))).toString(16) : ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, uuid);
console.log(uuid()) // bf6fb22e-4162-48ca-9d93-1c2566e63152
32、检查是否是空对象的方法
方法一:
function isEmptyObject(obj){
//排除null或undefined
if(obj == null) return false;
if(typeof obj !== "object") return false;
//是一个对象,纯对象或特殊对象都可以
var keys = Object.keys(obj);
//如果兼容再去拼接
if(Object.prototype.hasOwnProperty.call(Object,"getOwnPropertySymbols")){
keys.concat(Object.getOwnPropertySymbols(obj));
}
return keys.length === 0;
}
isEmptyObject({}) // true
方法二:
const isEmptyObject = obj => Reflect.ownKeys(obj).length === 0 && obj.constructor === Object;
isEmptyObject({}) // true
isEmptyObj({a:"not empty"}) //false
33、video播放器切换tab键去掉默认被选中
/* 移除 video 元素本身的焦点边框 */
video:focus {
outline: none;
}
video::-moz-focus-inner {
border: none;
}
// /* 移除 video 内部控件(播放按钮、进度条等)的焦点边框 */
video::-webkit-media-controls-enclosure:focus,
video::-webkit-media-controls-panel:focus,
video::-webkit-media-controls-current-time-display:focus,
video::-webkit-media-controls-time-remaining-display:focus,
video::-webkit-media-controls-timeline:focus,
video::-webkit-media-controls-mute-button:focus,
video::-webkit-media-controls-volume-slider:focus,
video::-webkit-media-controls-fullscreen-button:focus,
video::-webkit-media-controls-play-button:focus,
video::-webkit-media-controls-overflow-button:focus {
outline: none;
box-shadow: none;
}