一.浅深拷贝
浅拷贝:只能拷贝一层,如果是简单类型,拷贝的是值,如果是引用类型拷贝的是地址.
const obj1 = {
uname: '张三',
age: 18,
gender: '男',
gfs: ['凤姐', '芙蓉姐姐', '黄蓉'],
wife: {
w1: '蔡徐坤',
w2: 'ikun'
}
}
// 浅拷贝:只拷贝对象的第一层 如果第一层有引用类型 拷贝的是内存引用地址,如果是简单地址,拷贝的是值
// 使用展开运算符,可以是浅拷贝
// const obj2 = { ...obj1 }
// obj2.uname = '王五'
// obj2.gfs[0] ='小王'
// console.log(obj2)
// 使用Object.assign 将一个对象拷贝到另一个对象
Object.assign(obj2, obj1)
obj2.uname = '王五'
obj2.gfs[0] ='小王'
深拷贝:可以拷贝多层,不管是引用类型还是简单类型,拷贝的都是值.
const obj1 = {
uname: '张三',
age: 18,
gender: '男',
gfs: ['凤姐', '芙蓉姐姐', '黄蓉'],
wife: {
w1: '蔡徐坤',
w2: 'ikun'
}
}
// 创建一个空对象
const obj2 = {}
// 封装函数
function deepCopy(newObject, oldObject) {
// 遍历旧对象
// debuggerm 断点调试
for (let k in oldObject) {
// 获取旧对象的值赋给item变量
const item = oldObject[k]
// 判断item是不是数组
if (item instanceof Array) {
// 对数组
// 给newObject添加属性 但属性的值添加一个空的数组
newObject[k] = []
deepCopy(newObject[k], item)
} else if (item instanceof Object) {
// 对对象
// 给newObject添加属性 但属性的值添加一个空的对象
newObject[k] = {}
deepCopy(newObject[k], item)
} else {
// 将old对象属性值 赋值给新对像
newObject[k] = item
}
}
}
deepCopy(obj2, obj1)
obj2['gfs'][0]='嘿嘿嘿'
实现深拷贝的方法: 1.使用递归 2.利用JSON字符串 3.引用lodashi的JS文件
const obj1 = {
uname: '张三',
age: 18,
gender: '男',
gfs: ['凤姐', '芙蓉姐姐', '黄蓉'],
wife: {
w1: '蔡徐坤',
w2: 'ikun'
}
}
// 先将 对象转成json字符串
const str = JSON.stringify(obj1)
// 将json字符串转换成js对象
const obj2 = JSON.parse(str)
obj2['gfs'][0] = '王五'
二.异常处理
- throw抛异常
抛出异常使用throw关键字,会中止程序. Error对象配合throw使用
function fn(x, y) {
if (!x || !y) {
throw new Error('没有传参')
}
return x + y
}
const res = fn()
- try/catch捕获异常
捕获异常使用 try catch try关键字 利用catch的参数调用信息
<button class="id">按钮</button>
<script>
try {
const but = document.querySelector('id')
but.innerHTML = '老刘'
} catch (error) {
throw new Error('err.message')
}
finally {
console.log('hello')
}
</script>
- debugger(断点调试)
三.处理this
普通函数this指向:
- 谁调用,this指向谁
- 构造函数内this指向实例化对象
- 普通函数内this指向window
箭头函数this指向:
- 箭头函数内没有this
- 会沿用当前函数的上一级函数的this
改变函数this指向:
call Bind Apply 区别:
- 相同点:他们都是改变函数的this指向.
- 不同点:Call第一个参数是改变函数this指向,第二个参数可以是参数列表
- Apply:第一个参数是改变函数this指向,第二个参数是数组
- Bind:函数不会调用,会返回一个新的函数,第二个参数可以是多个
function fn(x, y) {
console.log(this, x, y)
}
const obj = {
uname: '张三'
}
//相同点:call()和apply() 都可以调用函数,都可以改变函数的this指向
//不同点:传递的参数个数不一样,call()可以传递多个参数,而apply()只能传递两个参数 第一个参数是需要改变函数里面的对象 第二个参数必须是数组
fn.apply(obj, [10, 20])
const arr = [10, 20, 30, 40, 50]
// 利用apply()来 求数组的最大值
// apply(可以调用函数)
// apply()多用于数组有关系的
const res = Math.max.apply(Math, arr)
console.log(res)
/* bind call apply 三者区别:
相同点:都可以改变函数的this指向
不同点:1.bind不能调用函数,会返回一个新的函数 call和apply可以调用函数
2.call 第一个形参用于改变函数的this指向,其他的形参 可以是 参数列表
3.bind第一个形参是用于改变函数的this指向,其他的参数可以是参数列表
4.apply的形参只有两个 第一个是用与改变函数的this指向,第二个形参是一个数组
*/
function f(x, y) {
console.log(this, x, y)
}
const obj = {
uname: 'zs',
age: 18
}
const res = f.bind(obj, 10, 20)
res()
四.递归
递归:在函数里调用自己
作用:实现浅拷贝,深拷贝,遍历Dom树
<script>
function f(n) {
console.log(n)
n = n - 2
if (n > 0) {
f(n)
}
console.log(n)
}
f(10)
</script>
//悲波拉锲数列
// 已知第一项和第二项数字是1
// 第一项 第二项 第三项 第四项 第五项 第六项
// 1 1 2 3 5 8
// 我们想过知道数组的第六项和的值
// 第四项和第五项的和
// 第四项的=第二项+第三项
function f(n) {
if (n === 1 || n === 2) {
return 1
} else {
// return 前一项 +前两项
return f(n - 1) + f(n - 2)
}
}
const res = f(10)
console.log(res)