• JavaScript高级,ES6 笔记 第四天


    目录

    throw

    try  catch  finally

    浅拷贝

    深拷贝

     1、递归方式

    2.loadsh

    3.JSON(推荐)

    call

    apply

    bind

     节流

     防抖

    视频案例

    事件总线


    throw

    抛出自定义错误

    1. html>
    2. <html>
    3. <body>
    4. <p>Please input a number between 5 and 10:p>
    5. <input id="demo" type="text">
    6. <button type="button" onclick="myFunction()">Test Inputbutton>
    7. <p id="message">p>
    8. <script>
    9. function myFunction() {
    10. var message, x;
    11. message = document.getElementById("message");
    12. message.innerHTML = "";
    13. x = document.getElementById("demo").value;
    14. try {
    15. if(x == "") throw "is Empty";
    16. if(isNaN(x)) throw "not a number";
    17. if(x > 10) throw "too high";
    18. if(x < 5) throw "too low";
    19. }
    20. catch(err) {
    21. message.innerHTML = "Input " + err;
    22. }
    23. }
    24. script>
    25. body>
    26. html>

    try  catch  finally

    try里面放可能会出错误的代码    catch是当发生错误时执行的,且有参数,代表错误本身,finally表示不管有没有错误都会执行

    1. <p>123p>
    2. <script>
    3. try{
    4. let ss = document.querySelector('.p');//Cannot read properties of null (reading 'style')
    5. ss.style.color = 'red'
    6. }catch(err){
    7. console.log(err.message);
    8. }finally{
    9. alert('sdasda')
    10. }
    11. script>

    浅拷贝

    浅拷贝与深拷贝都只针对  引用类型

    浅拷贝拷贝的是值(其实也是地址)

    但是这样有问题:

    1. const obj={
    2. age :18,
    3. obj1:{
    4. sex:1
    5. }
    6. }
    7. let o = {...obj}
    8. let o1={}
    9. Object.assign(o1,obj)
    10. o1.obj1.sex = 2
    11. console.log(o1);
    12. console.log(obj);//sex都为2

    欠拷贝只直接拷贝最外一层的值,而对于obj1来说,最外层的值是他的地址,所以就直接把地址给了o1,改变o1时也会改变obj

    深拷贝

    直接拷贝对象 不是地址

     1、递归方式

    设置函数,当originValue里面还有引用数据类型时,再次调用自己,只是将originValue改为里面的引用数据类型

    这里比较难的地方在于    obj.self = obj  ,也就是在obj中创造了self指向自己

    在深拷贝时,传入map = new WeakMap()用于记录已经生成的应用对象,当拷贝到self时,这个时候又需要创造一个obj对象,这时可以将map中存储好的obj直接拿出来赋值给它

    2.loadsh

    先去下载库,并引入js

    Lodash 简介 | Lodash 中文文档 | Lodash 中文网

    调用cloneDeep()

    1. var oo = _.cloneDeep(obj)
    2. console.log(oo);

    3.JSON(推荐)

    JSON 语法 | 菜鸟教程

    但是JSON有个问题,如果 对象有  函数  或者  symbol  则无法解析

    call

    可以改变this指向,在调用的时候用,第一个值就是设置指向

    1. let obj={
    2. }
    3. function fn(x,y){
    4. console.log(this);
    5. }
    6. fn.call(obj,1,2)//obj

    apply

    也是改变this指向 ,类似,传参必须为数组,这个用的比较多

    1. let obj={
    2. }
    3. function fn(x,y){
    4. console.log(this);//obj
    5. console.log(x+y);//3
    6. }
    7. fn.apply(obj,[1,2])

    值得注意的是,当不匹配时:

    1. let obj={
    2. }
    3. function fn(x){
    4. console.log(this);//obj
    5. console.log(x);//1
    6. }
    7. fn.apply(obj,[1,2])

    不会将数组全部传入

    提供了另外一种求最大值的方式

    1. let aa = [1,4,5,8,9]
    2. //Math.max(1,4,7,98)
    3. console.log(Math.max(...aa));
    4. console.log(Math.max.apply(null,aa));

    bind

    前面两种都必须要调用函数,这个不需要,返回值是函数,其实就是改变原函数的this得到了一个新函数

    1. let aa = [1,4,5,8,9]
    2. function fn(){
    3. console.log(this);
    4. }
    5. fn.bind(null)//无输出
    6. let fun = fn.bind(aa);
    7. fun()//a

    小应用,点击按钮禁用,两秒开启

    1. <script>
    2. let btn = document.querySelector('button');
    3. btn.addEventListener('click',function(){
    4. this.disabled = true
    5. setTimeout(function(){
    6. this.disabled = false
    7. }.bind(this),2000)
    8. })
    9. script>

    这个地方把定时器的this改为了btn,因为bind(this)里面这个this还是btn

     节流

    在一定的时间内只能执行一次,不管触发了多少次,在这个时间内只执行一次

    例子:div滑动时,200ms内只改变span一次

    1. var start = 0
    2. document.querySelector('div').addEventListener('mousemove',function(){
    3. let now = Date.now()
    4. if(now-start>=200){
    5. document.querySelector('span').innerHTML =i++
    6. start = now
    7. }
    8. })

    每次调用函数时都将此时的时间赋给now,当now与start差别大于200毫秒时才会改变i,然后将现在的时间赋给start以进行下次函数

    上面用的是时间差值的方法,也可以采用定时器的方法

    这里再加了一个immediate 变量,具体原理参照  防抖

    1. <input type="text">
    2. <button>cancelbutton>
    3. <button class="throttle">throttlebutton>
    4. <script>
    5. let ipt = document.querySelector('input')
    6. let mythrottle = function(fn,interval,immediate =true){
    7. let timeout = null
    8. let immediate_done = false
    9. let _throttle = function(){
    10. if (!immediate_done && immediate) {
    11. fn.apply(this)
    12. immediate_done = true
    13. return
    14. }
    15. if(!timeout){
    16. timeout = setTimeout(()=>{
    17. fn.apply(this)
    18. timeout = null
    19. },interval)
    20. }
    21. }
    22. return _throttle
    23. }
    24. ipt.addEventListener('input',mythrottle(function(){
    25. console.log(this.value);
    26. },1000))
    27. script>

     防抖

    触发后n秒内只执行一次,但是如果这段时间内还触发了,则会重新计算时间

    也就是说,在一定时间内我不停的进行高速的事件触发,但是只会在最后一次触发结束后进行执行

    应用场景:输入框,一般是等我输入完了才会去匹配

    例子:在div滑动时 停下来一秒钟才会改变span

    1. document.querySelector('div').addEventListener('mousemove',function(){
    2. if(timeget) clearTimeout(timeget)
    3. timeget = setTimeout(function(){
    4. document.querySelector('span').innerHTML =i++
    5. },1000)
    6. })

    例子:再次采用函数实现,需求是对输入框,输入结束一段时间后反应,这里还提供了应该取消接口,可以在这段时间结束前 结束响应

    1. "text">
    2. <button>cancelbutton>
    3. <script>
    4. let mydebounce = function(fn,delay){
    5. let timeout = null
    6. let _debounce = function(){
    7. if(timeout) clearTimeout(timeout)
    8. timeout = setTimeout(()=>{
    9. fn.apply(this)
    10. },delay)
    11. }
    12. _debounce.cancel = function(){
    13. if(timeout) clearTimeout(timeout)
    14. }
    15. return _debounce
    16. }
    17. let ipt = document.querySelector('input')
    18. let btn = document.querySelector('button')
    19. let debounce = mydebounce(function(){
    20. console.log(this.value);
    21. },2000)
    22. ipt.addEventListener('input',debounce)
    23. btn.addEventListener('click',debounce.cancel)
    24. script>

    再加一个立即执行功能,即在输入时,第一次输入马上响应,后面输入则等待一段时间,然后再次输入又马上响应

    1. let mydebounce = function(fn,delay,immediate=false){
    2. let timeout = null
    3. let immediate_done = false
    4. let _debounce = function(){
    5. if(timeout) clearTimeout(timeout)
    6. if(!immediate_done && immediate){
    7. fn.apply(this)
    8. immediate_done = true
    9. return
    10. }
    11. timeout = setTimeout(()=>{
    12. fn.apply(this)
    13. immediate_done = false
    14. },delay)
    15. }
    16. _debounce.cancel = function(){
    17. if(timeout) clearTimeout(timeout)
    18. immediate_done = false
    19. }
    20. return _debounce
    21. }

    定义了 immediate表示是否需要这个功能,immediate_done判断是否完成,当输入时,immediate为1,immediate_done为0时,会马上执行fn函数,然后使得immediate_done为1。在执行完时间间隔后,又将immediate_done为0

    还可以将_debounce函数返回为promise,好处是在fn传入时有返回值的情况下,可以拿到这个返回值

    1. let res = null
    2. let _debounce = function () {
    3. return new Promise((resolve, reject)=>{
    4. if (timeout) clearTimeout(timeout)
    5. if (!immediate_done && immediate) {
    6. res = fn.apply(this)
    7. resolve(res)
    8. immediate_done = true
    9. return
    10. }
    11. timeout = setTimeout(() => {
    12. res = fn.apply(this)
    13. resolve(res)
    14. immediate_done = false
    15. }, delay)
    16. })
    17. }

     若fn有返回值,就可以通过.then得到

    1. let ipt = document.querySelector('input')
    2. let btn = document.querySelector('button')
    3. let debounce = mydebounce(function () {
    4. console.log(this.value);
    5. return(111)
    6. }, 1000)
    7. ipt.addEventListener('input', debounce)
    8. btn.addEventListener('click', debounce.cancel)
    9. debounce().then(res=>{
    10. console.log(res);
    11. })

     还可以使用lodash

    节流

    _.throttle(fn,300)

    在300ms内只能执行一次fn函数

    1. function fn(){
    2. document.querySelector('span').innerHTML =i++
    3. }
    4. document.querySelector('div').addEventListener('mousemove',_.throttle(fn,300))

     防抖

     _.debounce(fn,300)

    停下来300ms后才执行fn函数

    1. function fn(){
    2. document.querySelector('span').innerHTML =i++
    3. }
    4. document.querySelector('div').addEventListener('mousemove',_.debounce(fn,300))

    视频案例

    1. const video = document.querySelector('video')
    2. video.onloadeddata = function(){
    3. video.currentTime = localStorage.getItem('time')||0
    4. }
    5. video.ontimeupdate = _.throttle(function(){
    6. localStorage.setItem('time',video.currentTime)
    7. },1000)

    得到video视频

    每次打开页面都把存储中的time拿出来,赋值给视频的currentTime,即跳转到对应的时间

    视频的时间发生改变时,添加防抖,每隔1s更新存储中的time值

    实现每次页面打开可以返回上次视频播放的地方

    事件总线

    当项目中有很多组件,很多文件,当一个文件中的某一个事件触发,希望另外一个文件得到响应,就需要用到事件总线

    这里我们自己用js实现

    一般来说这个事件总线是一个对象,里面有emit函数,用于发送时间,也有on函数,用于接受事件

    1. <script>
    2. class EventBus{
    3. constructor(){
    4. this.eventMap = {}//这个map用于存储on绑定的函数
    5. }
    6. on(eventname,fn){
    7. let fns = this.eventMap[eventname]
    8. if(!fns){//第一次如果没有函数数组时,自己创造一个
    9. fns=[]
    10. this.eventMap[eventname] = fns
    11. }
    12. fns.push(fn)//将回调函数放入对应的函数数组
    13. }
    14. emit(eventname,...args){
    15. let fns = this.eventMap[eventname]
    16. if(!fns) return
    17. fns.forEach(fn => {
    18. fn(...args)
    19. });
    20. }
    21. }
    22. let eventBus = new EventBus()
    23. eventBus.on('btnclick',()=>{
    24. console.log(1111);
    25. })
    26. eventBus.on('btnclick',()=>{
    27. console.log(2222);
    28. })
    29. let btn = document.querySelector('button')
    30. btn.addEventListener('click',function(){
    31. console.log('自己得到');
    32. eventBus.emit('btnclick')
    33. })
    34. script>

    因为on函数,对于一种事件的响应函数可能不止一个,所以需要eventMap来存储函数,其数据结构为{ eventname:[fn1,fn2]}

    在emit时,先取得事件对应的函数数组,再以此执行

    还可以写一个删除函数函数

    1. off(eventname,fn){
    2. let fns = this.eventMap[eventname]
    3. if (!fns) return
    4. for(let i=0;ilength;i++){
    5. if(fn === fns[i]){
    6. fns.splice(i,1)
    7. break
    8. }
    9. }
    10. //如果fns已经被清空了,那直接将事件删除
    11. if(fns.length==0){
    12. delete this.eventMap[eventname]
    13. }
    14. }

  • 相关阅读:
    【Java】IO流 - 字节流
    【java8新特性】:常见的函数式接口
    SIP消息结构详解
    SAP Spartacus 和 CDC 集成的 HTTP 请求明细
    K8S群集调度
    数据结构与算法【队列】的Java实现
    字符串——实现 strStr()——KMP
    金仓数据库 KingbaseGIS 使用手册(6.14. 几何对象处理函数)
    Redis内存兜底策略——内存淘汰及回收机制
    XML概述
  • 原文地址:https://blog.csdn.net/qq_54517101/article/details/127158005