首先浅拷贝和深拷贝只针对引用类型
浅拷贝:拷贝的是地址
常见方法:
如果是简单数据类型拷贝值,引用数据类型拷贝的是地址 (简单理解: 如果是单层对象,没问题,如果有多层就有问题)
首先浅拷贝和深拷贝只针对引用类型
深拷贝:拷贝的是对象,不是地址
常见方法:
函数递归:
如果一个函数在内部可以调用其本身,那么这个函数就是递归函数
1<body>2 <script>3 const obj = {4 uname: 'pink',5 age: 18,6 hobby: ['乒乓球', '足球'],7 family: {8 baby: '小pink'9 }10 }11 const o = {}12 // 拷贝函数13 function deepCopy(newObj, oldObj) {14 debugger15 for (let k in oldObj) {16 // 处理数组的问题 一定先写数组 在写 对象 不能颠倒17 if (oldObj[k] instanceof Array) {18 newObj[k] = []19 // newObj[k] 接收 [] hobby20 // oldObj[k] ['乒乓球', '足球']21 deepCopy(newObj[k], oldObj[k])22 } else if (oldObj[k] instanceof Object) {23 newObj[k] = {}24 deepCopy(newObj[k], oldObj[k])25 }26 else {27 // k 属性名 uname age oldObj[k] 属性值 1828 // newObj[k] === o.uname 给新对象添加属性29 newObj[k] = oldObj[k]30 }31 }32 }33 deepCopy(o, obj) // 函数调用 两个参数 o 新对象 obj 旧对象34 console.log(o)35 o.age = 2036 o.hobby[0] = '篮球'37 o.family.baby = '老pink'38 console.log(obj)39 console.log([1, 23] instanceof Object)40 // 复习41 // const obj = {42 // uname: 'pink',43 // age: 18,44 // hobby: ['乒乓球', '足球']45 // }46 // function deepCopy({ }, oldObj) {47 // // k 属性名 oldObj[k] 属性值48 // for (let k in oldObj) {49 // // 处理数组的问题 k 变量50 // newObj[k] = oldObj[k]51 // // o.uname = 'pink'52 // // newObj.k = 'pink'53 // }54 // }55 </script>56</body>xxxxxxxxxx181<body>2 <!-- 先引用 -->3 <script src="./lodash.min.js"></script>4 <script>5 const obj = {6 uname: 'pink',7 age: 18,8 hobby: ['乒乓球', '足球'],9 family: {10 baby: '小pink'11 }12 }13 const o = _.cloneDeep(obj)14 console.log(o)15 o.family.baby = '老pink'16 console.log(obj)17 </script>18</body>xxxxxxxxxx181<body>2 <script>3 const obj = {4 uname: 'pink',5 age: 18,6 hobby: ['乒乓球', '足球'],7 family: {8 baby: '小pink'9 }10 }11 // 把对象转换为 JSON 字符串12 // console.log(JSON.stringify(obj))13 const o = JSON.parse(JSON.stringify(obj))14 console.log(o)15 o.family.baby = '123'16 console.log(obj)17 </script>18</body>了解 JavaScript 中程序异常处理的方法,提升代码运行的健壮性。
异常处理是指预估代码执行过程中可能发生的错误,然后最大程度的避免错误的发生导致整个程序无法继续运行
总结:
x1<script>2 function counter(x, y) {34 if(!x || !y) {5 // throw '参数不能为空!';6 throw new Error('参数不能为空!')7 }89 return x + y10 }1112 counter()13</script>总结:
throw 抛出异常信息,程序也会终止执行throw 后面跟的是错误提示信息Error 对象配合 throw 使用,能够设置更详细的错误信息xxxxxxxxxx211<script>2 function foo() {3 try {4 // 查找 DOM 节点5 const p = document.querySelector('.p')6 p.style.color = 'red'7 } catch (error) {8 // try 代码段中执行有错误时,会执行 catch 代码段9 // 查看错误信息10 console.log(error.message)11 // 终止代码继续执行12 return1314 }15 finally {16 alert('执行')17 }18 console.log('如果出现错误,我的语句不会执行')19 }20 foo()21</script>总结:
try...catch 用于捕获错误信息try 代码段中try 代码段中出现错误后,会执行 catch 代码段,并截获到错误信息相当于断点调试
了解函数中 this 在不同场景下的默认值,知道动态指定函数 this 值的方法。
this 是 JavaScript 最具“魅惑”的知识点,不同的应用场合 this 的取值可能会有意想不到的结果,在此我们对以往学习过的关于【 this 默认的取值】情况进行归纳和总结。
普通函数的调用方式决定了 this 的值,即【谁调用 this 的值指向谁】,如下代码所示:
xxxxxxxxxx281<script>2 // 普通函数3 function sayHi() {4 console.log(this) 5 }6 // 函数表达式7 const sayHello = function () {8 console.log(this)9 }10 // 函数的调用方式决定了 this 的值11 sayHi() // window12 window.sayHi()13 1415// 普通对象16 const user = {17 name: '小明',18 walk: function () {19 console.log(this)20 }21 }22 // 动态为 user 添加方法23 user.sayHi = sayHi24 uesr.sayHello = sayHello25 // 函数调用方式,决定了 this 的值26 user.sayHi()27 user.sayHello()28</script>注: 普通函数没有明确调用者时 this 值为 window,严格模式下没有调用者时 this 的值为 undefined。
箭头函数中的 this 与普通函数完全不同,也不受调用方式的影响,事实上箭头函数中并不存在 this !箭头函数中访问的 this 不过是箭头函数所在作用域的 this 变量。
xxxxxxxxxx351<script>2 3 console.log(this) // 此处为 window4 // 箭头函数5 const sayHi = function() {6 console.log(this) // 该箭头函数中的 this 为函数声明环境中 this 一致7 }8 // 普通对象9 const user = {10 name: '小明',11 // 该箭头函数中的 this 为函数声明环境中 this 一致12 walk: () => {13 console.log(this)14 },15 16 sleep: function () {17 let str = 'hello'18 console.log(this)19 let fn = () => {20 console.log(str)21 console.log(this) // 该箭头函数中的 this 与 sleep 中的 this 一致22 }23 // 调用箭头函数24 fn();25 }26 }2728 // 动态添加方法29 user.sayHi = sayHi30 31 // 函数调用32 user.sayHi()33 user.sleep()34 user.walk()35</script>在开发中【使用箭头函数前需要考虑函数中 this 的值】,事件回调函数使用箭头函数时,this 为全局的 window,因此DOM事件回调函数不推荐使用箭头函数,如下代码所示:
xxxxxxxxxx121<script>2 // DOM 节点3 const btn = document.querySelector('.btn')4 // 箭头函数 此时 this 指向了 window5 btn.addEventListener('click', () => {6 console.log(this)7 })8 // 普通函数 此时 this 指向了 DOM 对象9 btn.addEventListener('click', function () {10 console.log(this)11 })12</script>同样由于箭头函数 this 的原因,基于原型的面向对象也不推荐采用箭头函数,如下代码所示:
xxxxxxxxxx111<script>2 function Person() {3 }4 // 原型对像上添加了箭头函数5 Person.prototype.walk = () => {6 console.log('人都要走路...')7 console.log(this); // window8 }9 const p1 = new Person()10 p1.walk()11</script>以上归纳了普通函数和箭头函数中关于 this 默认值的情形,不仅如此 JavaScript 中还允许指定函数中 this 的指向,有 3 个方法可以动态指定普通函数中 this 的指向:
使用 call 方法调用函数,同时指定函数中 this 的值,使用方法如下代码所示:
xxxxxxxxxx291<script>2 // 普通函数3 function sayHi() {4 console.log(this);5 }67 let user = {8 name: '小明',9 age: 1810 }1112 let student = {13 name: '小红',14 age: 1615 }1617 // 调用函数并指定 this 的值18 sayHi.call(user); // this 值为 user19 sayHi.call(student); // this 值为 student2021 // 求和函数22 function counter(x, y) {23 return x + y;24 }2526 // 调用 counter 函数,并传入参数27 let result = counter.call(null, 5, 10);28 console.log(result);29</script>总结:
call 方法能够在调用函数的同时指定 this 的值call 方法调用函数时,第1个参数为 this 指定的值call 方法的其余参数会依次自动传入函数做为函数的参数使用 call 方法调用函数,同时指定函数中 this 的值,使用方法如下代码所示:
xxxxxxxxxx281<script>2 // 普通函数3 function sayHi() {4 console.log(this)5 }67 let user = {8 name: '小明',9 age: 1810 }1112 let student = {13 name: '小红',14 age: 1615 }1617 // 调用函数并指定 this 的值18 sayHi.apply(user) // this 值为 user19 sayHi.apply(student) // this 值为 student2021 // 求和函数22 function counter(x, y) {23 return x + y24 }25 // 调用 counter 函数,并传入参数26 let result = counter.apply(null, [5, 10])27 console.log(result)28</script>总结:
apply 方法能够在调用函数的同时指定 this 的值apply 方法调用函数时,第1个参数为 this 指定的值apply 方法第2个参数为数组,数组的单元值依次自动传入函数做为函数的参数bind 方法并不会调用函数,而是创建一个指定了 this 值的新函数,使用方法如下代码所示:
xxxxxxxxxx141<script>2 // 普通函数3 function sayHi() {4 console.log(this)5 }6 let user = {7 name: '小明',8 age: 189 }10 // 调用 bind 指定 this 的值11 let sayHello = sayHi.bind(user);12 // 调用使用 bind 创建的新函数13 sayHello()14</script>注:bind 方法创建新的函数,与原函数的唯一的变化是改变了 this 的值。