拷贝
浅拷贝和深拷贝只针对引用类型(对象)
浅拷贝
- 拷贝对象之后,对象里面的属性值是简单数据类型直接拷贝值
- 如果对象里面的属性值是引用数据类型则拷贝的是地址
简单理解: 如果是单层对象,浅拷贝没问题,如果有多层就有问题
深拷贝
递归
JavaScript 中可以使用
obj[属性]
或obj.属性
两种方式来访问对象的属性值在 for in 中只能使用
[]
语法,而不能用.
语法
通过递归实现简单深拷贝,示例代码如下:
const oldObj = {
uname: '校花',
age: 18,
hobby: ['乒乓球', '足球'] // 对象
}
const newObj = {}
// 拷贝函数
function deepCopy(newObj, oldObj) {
// 遍历对象中的元素,k 为属性名,oldObj[k] 为值
for (let k in oldObj) {
// 处理数组的问题
if (oldObj[k] instanceof Array) {
newObj[k] = [] // 给 newObj 添加属性为 k 的空数组
deepCopy(newObj[k], oldObj[k])
} else {
newObj[k] = oldObj[k]
}
}
}
deepCopy(newObj, oldObj)
oldObj.hobby[0] = '篮球' // 修改对象
console.log(newObj)
console.log(oldObj)
lodash
js 库 lodash 里面的 _cloneDeep
方法实现了深拷贝,示例代码如下:
<script src="./lodash.min.js"></script>
<script>
const oldObj = {
uname: '校花',
age: 18,
hobby: ['乒乓球', '足球']
}
const newObj = _.cloneDeep(oldObj)
newObj.hobby[0] = '铅球'
console.log(newObj)
console.log(oldObj)
</script>
JSON
使用 JSON 字符串进行转换,示例代码如下:
const oldObj = {
uname: '校花',
age: 18,
hobby: ['乒乓球', '足球'] // 对象
}
// JSON.stringify(oldObj):把对象转为 json 字符串
const newObj = JSON.parse(JSON.stringify(oldObj))
newObj.hobby[0] = '羽毛球'
console.log(newObj)
console.log(oldObj)
- js 中字符串是基本数据类型
- java 中 String 是不可变的对象
异常
throw
function fn(x, y) {
if (!x || !y) {
throw new Error('没有参数')
}
return x + y
}
fn()
try/catch
function fn() {
try {
const p = document.querySelector('p')
p.style.color = 'red'
} catch (err) {
console.log(err.message)
} finally {
console.log('最终都要执行的')
}
}
fn()
debugger
使用 debugger
关键字写在代码中打断点
改变 this
call
使用 call
方法调用函数,同时指定被调用函数中 this
的值,语法如下:
fun.call(thisArg, arg1, arg2, ...)
- thisArg:在调用
fun
函数时指定的this
对象 - arg1,arg2:传递的其他参数
- 返回值是
fun
的返回值
示例代码如下:
const xh = {
uname: '校花'
}
function fn(a) {
console.log(a)
console.log(this)
}
fn.call(xh, '程序员校花')
apply
使用 apply
方法调用函数,同时指定被调用函数中 this
的值,语法如下:
fun.apply(thisArg, [argsArray])
-
thisArg:在调用
fun
函数时指定的this
对象 -
argsArray:传递的值,必须包含在数组里面
-
返回值是
fun
的返回值
示例代码如下:
const xh = {
age: 18
}
function fn(x, y) {
console.log(this) // xh
console.log(x + y) // 3
}
fn.apply(xh,[1, 2])
// 使用场景:求数组最大值
const max1 = Math.max(1, 2, 3, 4)
console.log(max1) // 4
const max2 = Math.max.apply(Math, [1, 2, 3])
console.log(max2) // 3
bind
bind
方法不会调用函数,但是能指定被调用函数中 this
的值,语法如下:
fun.bind(thisArg, arg1, arg2, ...)
- thisArg:在调用
fun
函数时指定的this
对象 - arg1,arg2:传递的其他参数
- 返回值:一个由指定的
this
值和传递的其他参数构成的新函数(不需要再传递实参,因为在绑定函数时已经预设了参数)
示例代码如下:
const xh = {
age: 18
}
function fn() {
console.log(this) // xh
}
const fun = fn.bind(xh)
fun()
// 需求,有一个按钮,点击禁用,1 秒之后开启
const btn = document.querySelector('button')
btn.addEventListener('click', function () {
// 禁用按钮
this.disabled = true
window.setTimeout(function () {
this.disabled = false
}.bind(this), 1000) // 这个 this 即 btn
})
性能优化
防抖
-
防抖:单位时间内,频繁触发事件,只执行最后一次
-
使用场景:
- 搜索框搜索输入,只需要用户最后一次输入完,再发送请求
- 手机号、邮箱验证输入检测
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/cd5ec9d24a38988b4c6b8844d6b6b06a.png)
lodash 实现
使用 lodash 库实现防抖效果,要求: 鼠标在盒子上移动,鼠标停止之后(即最后一次事件结束后),500 ms 后里面的数字就会变化 + 1,示例代码如下:
<div class="box"></div>
<script src="lodash.min.js"></script>
<script>
const box = document.querySelector('.box')
let i = 1
function mouseMove () {
box.innerHTML = i++
// 如果里面存在大量消耗性能的代码,比如 dom 操作、数据处理,可能会造成卡顿
}
// box.addEventListener('mousemove', mouseMove)
box.addEventListener('mousemove', _.debounce(mouseMove, 500))
</script>
节流
- 节流:单位时间内,频繁触发事件,只执行一次
- 使用场景:高频事件:
- 鼠标移动
mousemove
- 页面尺寸缩放
resize
- 滚动条滚动
scroll
- 鼠标移动
lodash 实现
使用 lodash 库实现节流效果,要求: 鼠标在盒子上移动频繁触发事件,但是使用节流操作使 2 秒内只触发一次事件,示例代码如下:
<div class="box"></div>
<script src="lodash.min.js"></script>
<script>
const box = document.querySelector('.box')
let i = 1
function mouseMove () {
box.innerHTML = i++
// 如果里面存在大量消耗性能的代码,比如 dom 操作、数据处理,可能会造成卡顿
}
// box.addEventListener('mousemove', mouseMove)
box.addEventListener('mousemove', _.throttle(mouseMove, 2000))
</script>