欢迎来到飞鸟慕鱼博客,开始您的技术之旅!
当前位置: 首页知识笔记正文

javascript高级进阶技巧,js中的防抖与节流

墨初 知识笔记 132阅读
JavaScript 进阶 - 第4天 深浅拷贝 浅拷贝

首先浅拷贝和深拷贝只针对引用类型

浅拷贝拷贝的是地址

常见方法

拷贝对象Object.assgin() / 展开运算符 {…obj} 拷贝对象拷贝数组Array.prototype.concat() 或者 […arr]

如果是简单数据类型拷贝值引用数据类型拷贝的是地址 (简单理解 如果是单层对象没问题如果有多层就有问题)

深拷贝

首先浅拷贝和深拷贝只针对引用类型

深拷贝拷贝的是对象不是地址

常见方法

通过递归实现深拷贝lodash/cloneDeep通过JSON.stringify()实现 递归实现深拷贝

函数递归

如果一个函数在内部可以调用其本身那么这个函数就是递归函数

简单理解:函数内部自己调用自己, 这个函数就是递归函数递归函数的作用和循环效果类似由于递归很容易发生“栈溢出”错误stack overflow所以必须要加退出条件 return
<body>  <script>    const obj  {      uname: pink,      age: 18,      hobby: [乒乓球, 足球],      family: {        baby: 小pink      }    }    const o  {}    // 拷贝函数    function deepCopy(newObj, oldObj) {      debugger      for (let k in oldObj) {        // 处理数组的问题  一定先写数组 在写 对象 不能颠倒        if (oldObj[k] instanceof Array) {          newObj[k]  []          //  newObj[k] 接收 []  hobby          //  oldObj[k]   [乒乓球, 足球]          deepCopy(newObj[k], oldObj[k])        } else if (oldObj[k] instanceof Object) {          newObj[k]  {}          deepCopy(newObj[k], oldObj[k])        }        else {          //  k  属性名 uname age    oldObj[k]  属性值  18          // newObj[k]   o.uname  给新对象添加属性          newObj[k]  oldObj[k]        }      }    }    deepCopy(o, obj) // 函数调用  两个参数 o 新对象  obj 旧对象    console.log(o)    o.age  20    o.hobby[0]  篮球    o.family.baby  老pink    console.log(obj)    console.log([1, 23] instanceof Object)    // 复习    // const obj  {    //   uname: pink,    //   age: 18,    //   hobby: [乒乓球, 足球]    // }    // function deepCopy({ }, oldObj) {    //   // k 属性名  oldObj[k] 属性值    //   for (let k in oldObj) {    //     // 处理数组的问题   k 变量    //     newObj[k]  oldObj[k]    //     // o.uname  pink    //     // newObj.k   pink    //   }    // }  </script></body>
js库lodash里面cloneDeep内部实现了深拷贝
<body>  <!-- 先引用 -->  <script src./lodash.min.js></script>  <script>    const obj  {      uname: pink,      age: 18,      hobby: [乒乓球, 足球],      family: {        baby: 小pink      }    }    const o  _.cloneDeep(obj)    console.log(o)    o.family.baby  老pink    console.log(obj)  </script></body>
JSON序列化
<body>  <script>    const obj  {      uname: pink,      age: 18,      hobby: [乒乓球, 足球],      family: {        baby: 小pink      }    }    // 把对象转换为 JSON 字符串    // console.log(JSON.stringify(obj))    const o  JSON.parse(JSON.stringify(obj))    console.log(o)    o.family.baby  123    console.log(obj)  </script></body>
异常处理

了解 JavaScript 中程序异常处理的方法提升代码运行的健壮性。

throw

异常处理是指预估代码执行过程中可能发生的错误然后最大程度的避免错误的发生导致整个程序无法继续运行

总结

throw 抛出异常信息程序也会终止执行throw 后面跟的是错误提示信息Error 对象配合 throw 使用能够设置更详细的错误信息
<script>  function counter(x, y) {    if(!x || !y) {      // throw 参数不能为空!;      throw new Error(参数不能为空!)    }    return x  y  }  counter()</script>

总结

throw 抛出异常信息程序也会终止执行throw 后面跟的是错误提示信息Error 对象配合 throw 使用能够设置更详细的错误信息 try … catch
<script>   function foo() {      try {        // 查找 DOM 节点        const p  document.querySelector(.p)        p.style.color  red      } catch (error) {        // try 代码段中执行有错误时会执行 catch 代码段        // 查看错误信息        console.log(error.message)        // 终止代码继续执行        return      }      finally {          alert(执行)      }      console.log(如果出现错误我的语句不会执行)    }    foo()</script>

总结

try...catch 用于捕获错误信息将预估可能发生错误的代码写在 try 代码段中如果 try 代码段中出现错误后会执行 catch 代码段并截获到错误信息 debugger

相当于断点调试

处理this

了解函数中 this 在不同场景下的默认值知道动态指定函数 this 值的方法。

this 是 JavaScript 最具“魅惑”的知识点不同的应用场合 this 的取值可能会有意想不到的结果在此我们对以往学习过的关于【 this 默认的取值】情况进行归纳和总结。

普通函数

普通函数的调用方式决定了 this 的值即【谁调用 this 的值指向谁】如下代码所示

<script>  // 普通函数  function sayHi() {    console.log(this)    }  // 函数表达式  const sayHello  function () {    console.log(this)  }  // 函数的调用方式决定了 this 的值  sayHi() // window  window.sayHi()// 普通对象  const user  {    name: 小明,    walk: function () {      console.log(this)    }  }  // 动态为 user 添加方法  user.sayHi  sayHi  uesr.sayHello  sayHello  // 函数调用方式决定了 this 的值  user.sayHi()  user.sayHello()</script>

注 普通函数没有明确调用者时 this 值为 window严格模式下没有调用者时 this 的值为 undefined

箭头函数

箭头函数中的 this 与普通函数完全不同也不受调用方式的影响事实上箭头函数中并不存在 this 箭头函数中访问的 this 不过是箭头函数所在作用域的 this 变量。

<script>      console.log(this) // 此处为 window  // 箭头函数  const sayHi  function() {    console.log(this) // 该箭头函数中的 this 为函数声明环境中 this 一致  }  // 普通对象  const user  {    name: 小明,    // 该箭头函数中的 this 为函数声明环境中 this 一致    walk: () > {      console.log(this)    },        sleep: function () {      let str  hello      console.log(this)      let fn  () > {        console.log(str)        console.log(this) // 该箭头函数中的 this 与 sleep 中的 this 一致      }      // 调用箭头函数      fn();    }  }  // 动态添加方法  user.sayHi  sayHi    // 函数调用  user.sayHi()  user.sleep()  user.walk()</script>

在开发中【使用箭头函数前需要考虑函数中 this 的值】事件回调函数使用箭头函数时this 为全局的 window因此DOM事件回调函数不推荐使用箭头函数如下代码所示

<script>  // DOM 节点  const btn  document.querySelector(.btn)  // 箭头函数 此时 this 指向了 window  btn.addEventListener(click, () > {    console.log(this)  })  // 普通函数 此时 this 指向了 DOM 对象  btn.addEventListener(click, function () {    console.log(this)  })</script>

同样由于箭头函数 this 的原因基于原型的面向对象也不推荐采用箭头函数如下代码所示

<script>  function Person() {  }  // 原型对像上添加了箭头函数  Person.prototype.walk  () > {    console.log(人都要走路...)    console.log(this); // window  }  const p1  new Person()  p1.walk()</script>
改变this指向

以上归纳了普通函数和箭头函数中关于 this 默认值的情形不仅如此 JavaScript 中还允许指定函数中 this 的指向有 3 个方法可以动态指定普通函数中 this 的指向

call

使用 call 方法调用函数同时指定函数中 this 的值使用方法如下代码所示

<script>  // 普通函数  function sayHi() {    console.log(this);  }  let user  {    name: 小明,    age: 18  }  let student  {    name: 小红,    age: 16  }  // 调用函数并指定 this 的值  sayHi.call(user); // this 值为 user  sayHi.call(student); // this 值为 student  // 求和函数  function counter(x, y) {    return x  y;  }  // 调用 counter 函数并传入参数  let result  counter.call(null, 5, 10);  console.log(result);</script>

总结

call 方法能够在调用函数的同时指定 this 的值使用 call 方法调用函数时第1个参数为 this 指定的值call 方法的其余参数会依次自动传入函数做为函数的参数 apply

使用 call 方法调用函数同时指定函数中 this 的值使用方法如下代码所示

<script>  // 普通函数  function sayHi() {    console.log(this)  }  let user  {    name: 小明,    age: 18  }  let student  {    name: 小红,    age: 16  }  // 调用函数并指定 this 的值  sayHi.apply(user) // this 值为 user  sayHi.apply(student) // this 值为 student  // 求和函数  function counter(x, y) {    return x  y  }  // 调用 counter 函数并传入参数  let result  counter.apply(null, [5, 10])  console.log(result)</script>

总结

apply 方法能够在调用函数的同时指定 this 的值使用 apply 方法调用函数时第1个参数为 this 指定的值apply 方法第2个参数为数组数组的单元值依次自动传入函数做为函数的参数 bind

bind 方法并不会调用函数而是创建一个指定了 this 值的新函数使用方法如下代码所示

<script>  // 普通函数  function sayHi() {    console.log(this)  }  let user  {    name: 小明,    age: 18  }  // 调用 bind 指定 this 的值  let sayHello  sayHi.bind(user);  // 调用使用 bind 创建的新函数  sayHello()</script>

bind 方法创建新的函数与原函数的唯一的变化是改变了 this 的值。

防抖节流 防抖debounce
所谓防抖就是指触发事件后在 n 秒内函数只能执行一次如果在 n 秒内又触发了事件则会重新计算函数执行时间节流throttle
所谓节流就是指连续触发事件但是在 n 秒中只执行一次函数

标签:
声明:无特别说明,转载请标明本文来源!