文章目录
深拷贝浅拷贝有什么区别?怎么实现深拷贝?
["1","2","3"].map(parselInt)的返回值是什么?
怎么预防按钮的重复点击?
深拷贝浅拷贝有什么区别?怎么实现深拷贝?
浅拷贝
浅拷贝,指的是创建新的数据,这个数据有着原始数据属性值的一份精确拷贝
如果属性是基本类型,拷贝的就是基本类型的值。如果属性是引用类型,拷贝的就是内存地址
即浅拷贝是拷贝一层,深层次的引用类型则共享内存地址
下面简单实现一个浅拷贝
function shallowClone(obj) {
const newObj = {};
for(let prop in obj) {
if(obj.hasOwnProperty(prop)){
newObj[prop] = obj[prop];
}
}
return newObj;
}
1
2
3
4
5
6
7
8
9
在JavaScript中,存在浅拷贝的现象有:
Object.assign
Array.prototype.slice(), Array.prototype.concat()
使用拓展运算符实现的复制
深拷贝
深拷贝开辟一个新的栈,两个对象属完成相同,但是对应两个不同的地址,修改一个对象的属性,不会改变另一个对象的属性
常见的深拷贝方式有:
_.cloneDeep()
jQuery.extend()
JSON.stringify()
手写循环递归
_.cloneDeep()
const _ = require('lodash');
const obj1 = {
a: 1,
b: { f: { g: 1 } },
c: [1, 2, 3]
};
const obj2 = _.cloneDeep(obj1);
console.log(obj1.b.f === obj2.b.f);// false
1
2
3
4
5
6
7
8
jQuery.extend()
const $ = require('jquery');
const obj1 = {
a: 1,
b: { f: { g: 1 } },
c: [1, 2, 3]
};
const obj2 = $.extend(true, {}, obj1);
console.log(obj1.b.f === obj2.b.f); // false
1
2
3
4
5
6
7
8
JSON.stringify()
const obj2=JSON.parse(JSON.stringify(obj1));
1
2
循环递归
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;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
区别
从上图发现,浅拷贝和深拷贝都创建出一个新的对象,但在复制对象属性的时候,行为就不一样
浅拷贝只复制属性指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存,修改对象属性会影响原对象
[“1”,“2”,“3”].map(parselInt)的返回值是什么?
首先整个题目考校的是两个函数,和一个字符串转数字的概念
1.数组的map函数,接受三个参数,当前值,当前索引,当前数组。
2. parselnt接受两个参数,需要转换的字符串,基数(基数取值范围2~36)
3. 根据上面的两个函数的解释,我们可以发现实际上,上面的[‘1’,‘2’,‘3’].map(parseInt) 其实就是等价于下面的代码。
['1','2','3'].map((item, index) => {
return parseInt(item, index)
})
// parseInt('1', 0) 1
// parseInt('2', 1) NaN
// parseInt('3', 2) NaN
1
2
3
4
5
6
4.如果我们需要返回1,2,3需要怎么办?
function parseIntFun(item) {
return parseInt(item, 10)
}
['1','2','3'].map(parseIntFun)
// parseInt('1', 10) 1
// parseInt('2', 10) 2
// parseInt('3', 10) 3
1
2
3
4
5
6
7
怎么预防按钮的重复点击?
先看看在那些场景会导致重复请求:
1.手速快,不小心双击操作按钮。
2.很小心的点击了一次按钮,因为请求响应比较慢,页面没有任何提示,怀疑上次点击没生效,再次点击操作按钮。
3.很小心的点击了一次按钮, 因为请求响应比较慢,页面没有任何提示,刷新页面,再次点击操作按钮。
解决方案
1.控制按钮,在短时间内被多次点击,第一次以后的点击无效。
2.控制按钮,在点击按钮触发的请求响应之前,再次点击无效。
3.配置特殊的URL,然后控制这些URL请求的最小时间间隔。如果再次请求跟前一-次请求间隔很小,弹窗二次提示,是否继续操作。
防止无意识复点击按钮
给按钮添加控制,在control 毫秒内,第一次点击事件之后的点击事件不执行。
<template>
<button @click="handleClick"></button>
</templage>
<script>
export default {
methods: {
handleClick(event) {
if (this.disabled) return;
if (this.notAllowed) return;
// 点击完多少秒不能继续点
this.notAllowed = true;
setTimeout(()=>{
this.notAllowed = false;
}, this.control)
this.$emit('click', event, this);
}
}
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
按钮点击立马禁用,等响应回来才能继续点击
触发点击的button实例传入fetch配置,代码如下:
doQuery: function (button) {
this.FesApi.fetch(`generalcard/query`, {
sub_card_type: this.query.sub_card_type,
code_type: this.query.code_type,
title: this.query.title,
card_id: this.query.card_id,
page_info: {
pageSize: this.paginationOption.page_info.pageSize,
currentPage: this.paginationOption.page_info.currentPage
}
}, {
//看这里,加上下面一行代码就行。。so easy
button: button
}).then(rst => {
// 成功处理
});
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
在fetch函数内部,设置button的disabled=true,当响应回来时,设置disabled=false代码如下:
const action = function (url, data, option) {
// 如果传了button
if (option.button) {
option.button.currentDisabled = true;
}
// 记录日志
const log = requsetLog.creatLog(url, data);
return param(url, data, option)
.then(success, fail)
.then((response) => {
requsetLog.changeLogStatus(log, 'success');
if (option && option.button) {
option.button.currentDisabled = false;
}
return response;
})
.catch((error) => {
requsetLog.changeLogStatus(log, 'fail');
if (option && option.button) {
option.button.currentDisabled = false;
}
error.message && window.Toast.error(error.message);
throw error;
});
};