【JavaScript】11-JS高阶技巧

本文介绍JS中的一些高阶技巧。

目录

1. 深浅拷贝

1.1 浅拷贝

1.2 深拷贝

1.2.1 通过递归实现

1.2.2 lodash / cloneDeep

1.2.3 JSON.stringify()

2. 异常处理

2.1 throw 抛异常

2.2 try / catch 捕获异常

2.3 debugger

3. 处理this

3.1 this指向

3.1.1 普通函数this

3.1.2 箭头函数的this

3.2 改变this

3.2.1 call方法改变

3.2.2 apply方法改变

3.2.3 bind方法改变

4. 防抖 debounce

4.1 lodash 

4.2 手写防抖

5. 节流 throttle

5.1 lodash库

5.2 手写节流

5.3 节流与防抖总结


1. 深浅拷贝

开发中经常需要复制一个对象,如果直接复制会有以下问题:

    

给o的复制相当于把地址给了o,修改后对obj也修改了


1.1 浅拷贝

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

浅拷贝拷贝的是地址

常见方法:

    
    

但是只是对于简单的不会被改,比如下面的问题

    

内层的仍然被修改,内层拷贝的仍然是地址,只有外层的是只拷贝了值

所以是拷贝


1.2 深拷贝

只针对引用类型

深拷贝:拷贝的是对象 而非地址

常见方法:

1.2.1 通过递归实现

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

即 自己调用自己 类似循环

由于递归容易发生栈溢出错误,所以必须要加退出条件 return

    

利用递归函数实现 setTimeout 模拟 setInterval 效果

需求:

① 页面每隔一秒输出当前时间

② 输出时间用 new.Date().toLocaleString()


    

数组情况:

    

在这里注意 newobj[k] 是[ ]存的变量k

如果对象里还有嵌套对象 可以仿照数组的形式

加上以下内容即可

                // 处理对象问题
                else if(oldobj[k] instanceof Object){
                    // 遍历对象 
                    // 递归调用自己来实现复制
                    // 先创建一个新对象
                    newobj[k] = {};
                    deepCopy(newobj[k],oldobj[k]);  // 传入的参数是数组
                }

注意:

一定先写数组后写对象,因为数组也是对象,不然操作出现错误


1.2.2 lodash / cloneDeep

JS库的lodash里面cloneDeep


    
    
    

1.2.3 JSON.stringify()

    

对象 —— 字符串 —— 新对象

新对象和之前的对象没有任何关系


2. 异常处理

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

2.1 throw 抛异常

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

    

2.2 try / catch 捕获异常

try先判断是否有错,有错就 catch 拦住  finally 最后执行什么


    

123


2.3 debugger

在某位置加上debugger后

打开Sources 刷新后自动跳到debugger位置

【JavaScript】11-JS高阶技巧_第1张图片


3. 处理this

3.1 this指向

3.1.1 普通函数this

普通函数的调用方式决定了this的值,即谁调用this的值就指向谁


    
    

3.1.2 箭头函数的this

箭头函数于普通函数完全不同,也不受调用方式影响,事实上箭头函数并不存在this

1. 箭头函数会默认绑定外层的this,所以箭头函数的this和外层的this一样

2. 箭头函数的this引用的时最近作用域的this

3. 向外层的作用域中,一层一层查找this,直到有this的定义

注意不推荐的:

1. DOM事件中如果需要DOM对象里的this 不推荐使用箭头函数

2. 原型对象不推荐使用箭头函数 否则this不指向实例对象了 


3.2 改变this

3.2.1 call方法改变

call调用函数,同时指定被调用函数中的this的值

语法:

fun.call(thisArg, arg1, arg2...)

thisArg:在fun函数运行时指定的this值

arg1 arg2:传递的其他参数

返回值就是函数的返回值,因为它是调用函数

    

3.2.2 apply方法改变

apply调用函数,同时指定被调用函数中的this的值

语法:

fun.call(thisArg, [argsArray])

thisArg:在fun函数运行时指定的this值

argsArray:传递的其他参数必须包含在数组内

返回值就是函数的返回值,因为它是调用函数

apply主要和数组有关,比如调用Math.max()求数组最大值

    

3.2.3 bind方法改变

bind() 不会调用函数 但是可以改变内部this指向

语法:

fun.bind(thisArg, arg1, arg2...)

thisArg:在fun函数运行时指定的this值

arg1 arg2:传递的其他参数

返回由指定的this值和初始化参数改造的原函数拷贝(新函数)

只想改变this指向 但是不想调用函数的时候bind()

    

改变定时器内部的 this 指向


    
    

4. 防抖 debounce

单位时间内,频繁触发事件,只执行最后一次。

【JavaScript】11-JS高阶技巧_第2张图片

使用场景:

搜索框搜索输入字符时,只需要用户输完最后一个字,再发送搜索请求。

例如:

利用防抖处理-鼠标滑过盒子就显示文字

鼠标在盒子上移动,里面的数字会变化+1

方法:

4.1 lodash 

_.debounce(func, [wait = 0], [options=])

该函数会从上一次被调用后,延迟wait毫秒后调用func方法




    
    
    Document
    


    

4.2 手写防抖

防抖核心:setTimeout实现

① 声明一个计时器变量

② 当鼠标每次滑动都先判断是否有定时器了,如果有定时器先清除以前的定时器

③ 如果没有以前的定时器就开启定时器,存到变量里

④ 定时器里调用要执行的函数

        // 2.手写防抖效果
        // 防抖核心:setTimeout实现
        // 1.声明一个计时器变量
        // 2.每次鼠标移动都先判断是否有定时器,如果有先清除以前的定时器
        // 3.如果没有以前的定时器就开启定时器,存到变量里
        // 4.定时器里实现函数调用
        function debounce(fn,t){
            let timer;  // 声明计时器变量
            // return 返回一个匿名函数 相当于将这个匿名函数给了下面的debounce
            // 每触发一次事件 下面的debounce就会接收一个function
            return function(){
                if(timer) clearTimeout(timer);  // 是否有定时器 清除
                timer = setTimeout(function(){  // 开启定时器
                    fn();  //小括号调用
                },t)
            }
        }
        box.addEventListener('mousemove',debounce(mouseMove,500)); 
        // 每次鼠标经过时就会 debounce - function() 

5. 节流 throttle

节流:单位时间内,频繁触发事件,只执行一次

防抖是执行最后一个,节流是只能执行第一个

【JavaScript】11-JS高阶技巧_第3张图片

只有本次执行结束后才能执行下一次

使用场景:

高频事件:鼠标移动 mousemove、页面尺寸缩放 resize、滚动条滚动 scoll 

仍然是上面的例子,鼠标在盒子上滑动,不管移动多少次,每隔500ms+1

5.1 lodash库

_.throttle(func, [wait = 0], [options = ])

在wait秒内最多执行func一次的函数

    

5.2 手写节流

节流核心:setTimeout实现

① 声明一个计时器变量

② 当鼠标每次滑动都先判断是否有定时器了,如果有定时器则不再开始新定时器

③ 如果没有以前的定时器,就开启定时器,存到变量里

— 定时器里调用执行的函数

— 定时器里要把定时器清空  时间到了才开启下一个新的定时器

④ 定时器里调用要执行的函数

        function throttle(fn,t){
            let timer = null;  //声明一个计时器变量
            return function(){
                if(!timer){
                    timer = setTimeout(function(){
                        fn();
                        // 清空定时器 才能开启下一个新的定时器
                        timer = null;  
                        // 在定时器里面 不使用clearTimeout 在开启定时器的里面再关闭是不对的
                    },t)
                }
            }
        }
        box.addEventListener('mousemove',throttle(mouseMove,1000))

5.3 节流与防抖总结


本文介绍JS中的一些高阶技巧。

你可能感兴趣的:(JavaScript【已完结】,javascript,前端,ecmascript,es6)