Js进阶(4)

原型链

基于原型对象的继承使得不同构造函数的原型对象关联在一起,并且这种关联的关系是一种链状的结构,我们将原型对象的链状结构关系称为原型链

原型链查找规则

  1. 当访问一个对象的属性(包括方法)时,首先查找这个对象自身有没有该属性
  2. 如果没有就查找它的原型
  3. 如果还没有就查找原型对象的原型
  4. 以此类推一直找到Object为止(null)
  5. _proto_对象原型的意义就在于为对象成员查找机制提供方向
  6. 可以使用instanceof运算符用于检测函数的prototype属性是否出现在某个实例对象的原型链上
js 复制代码
console.log(ldh instanceof Person)

Array在Object的原型链上

高级技巧

浅拷贝和深拷贝只针对引用类型。开发当中我们需重复制一个对象。直接赋值会有问题:堆和栈

深浅拷贝

浅拷贝

拷贝的是地址

  1. 常见方法
  • 拷贝对象:Object.assgin()/展开运算符{...Object}

  • 拷贝数组:Array.prototype.concat()或[...arr]

只能拷贝到外面一层

深拷贝

拷贝的是对象,不是地址。

  1. 常见方法:
  • 通过递归实现深拷贝
  • lodash/clonelDeep
  • JSON.stringify()实现
  1. 递归函数:如果一个函数在内部可以调用其本身,那么这个函数就是递归函数
  • 作用与循环效果类似
  • 容易发生"栈溢出",必须写退出条件
  1. newObj[k] 属性名 = oldObj[k] 属性值

    如果有变量,使用中括号

    一定先写数组在写对象

  2. JS库lodash里面cloneDeep内部实现了深拷贝

    写法: _.cloneDeep(obj)

异常处理

异常处理是指预估代码可能出现的问题,然后最大程度的避免问题的方法

throw抛异常

  1. throw抛出异常信息,程序也会终止执行
  2. throw后面跟的是错误信息提示
  3. 配合Error使用
js 复制代码
<script>
        function fn(x, y) {
            if (!x || !y) {
                throw new Error('没有参数传递')
            }
            return x + y
        }
        console.log(fn())


    </script>

try/catch捕获异常

try试试 catch拦截 finally最后

拦截错误,提示错误信息,但不中断程序,如果需要中断则加入return

  1. try...catch用于捕获错误信息
  2. 将预估可能发生错误的代码写在try中
  3. 如果try中发生错误后,会执行catch代码,截取错误信息
  4. finally不管是否有错,都会执行
js 复制代码
        function fn() {
            try {
                const p = document.querySelector('p')
                p.style.color = 'red'
            } catch (err) {
                //拦截错误,提示错误信息,但不中断程序
                console.log(err.message)

            }
            //不管程序对不对,都会执行
            finally {
                alert('嘻嘻')
            }
        }
        fn()

debugger

js 复制代码
<script>
        h = {
            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] = []
                    deepCopy(newObj[k], oldObj[k])
                } else if (oldObj[k] instanceof Object) {
                    newObj[k] = {}
                    deepCopy(newObj[k], oldObj[k])
                }
                else {
                    newObj[k] = oldObj[k]
                }
            }
        }
        deepCopy(o, h)
        console.log(o)




    </script>

处理this

this指向

普通函数:谁调用指向谁,严格模式下指向undefined

箭头函数:指向上一层作用域

  • 如果需要DOM对象的this,则不推荐箭头函数
  • 原型对象也不推荐
    总结:
  1. 函数内不存在this沿用上一级
  2. 不适用于构造函数,原型函数,dom事件函数
  3. 适用于需要使用上层this的地方

改变this指向

  1. call()

语法:fun.call(thisArg,1,2,...)

js 复制代码
<script>
        const obj = {
            uname: 'pink'
        }
        function fn(x, y) {
            console.log(this)
            console.log(x + y);

        }
        fn.call(obj, 1, 2)
    </script>
  1. apply()

语法:fun.apply(thisArg,[argsArray])

  • thisArg:指定this的值
  • argsArray:包含的值必须包含在数组里
  • 返回值就是函数的返回值
  • apply主要与数组有关,可以求数组最大值
js 复制代码
 const obj = {
            age: 18
        }
        function fn(x, y) {
            console.log(this)
            console.log(x + y)

        }
        fn.apply(obj, [1, 2])

        //求数组最值
        const max = Math.max.apply(Math, [1, 2, 3])
        const min = Math.min.apply(Math, [1, 2, 3])
        console.log(max)
        console.log(min)
  1. bind() 不会调用函数

语法:fun.bind(thisArg,1,2,...)

返回值是一个函数,但函数指向更改过

  1. 总结:

相同点:都可以改变this指向

不同点:

  • call和apply会调用函数,并且改变指向
  • call和apply传递参数不同,call传递常数参数,apply传递数组参数
  • bind只能改变指向,不能调用函数

使用场景:

call改变指向,调用函数

apply可以实现数组的最值问题

bind只改变指向

性能优化

防抖

  1. 定义:单位时间内,频繁触发事件,只执行最后一次
  2. lodash可提供防抖函数 _.debounce(执行函数,延迟时间)
  3. 手写防抖函数
html 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<style>
    .box {
        width: 200px;
        height: 200px;
        margin: 100px auto;
        background-color: pink;
        font-size: 30px;
        text-align: center;
        color: gray;
    }
</style>

<body>
    <div class="box"></div>
    <script src="../lodash.min.js"></script>
    <script>

        //使用lodash库实现防抖效果
        const box = document.querySelector('.box')
        let i = 1
        function move() {
            box.innerHTML = i++
        }
        //box.addEventListener('mousemove', move)
        //使用lodash
        //box.addEventListener('mousemove', _.debounce(move, 500)) */

        //手写防抖函数实现防抖效果 利用setTimeout定时器
        function debounce(fn, t) {
            let timer
            //返回一个匿名函数
            return function () {
                if (timer) clearTimeout(timer)
                timer = setTimeout(function () {
                    fn()
                }, t)
            }
        }
        box.addEventListener('mousemove', debounce(move, 500))
    </script>
</body>

</html>

节流-throttle

  1. 定义:单位时间内,频繁触发事件,只执行一次
  2. lodash提供节流函数 _.throttle(执行函数,时间)
  3. 手写节流函数
html 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<style>
    .box {
        width: 200px;
        height: 200px;
        margin: 100px auto;
        background-color: pink;
        font-size: 30px;
        text-align: center;
        color: gray;
    }
</style>

<body>
    <div class="box"></div>
    <script src="../lodash.min.js"></script>
    <script>

        //使用lodash库实现节流效果
        const box = document.querySelector('.box')
        let i = 1
        function move() {
            box.innerHTML = i++
        }
        //box.addEventListener('mousemove', _.throttle(move, 500))
        function throttle(fn, t) {
            let timer = null
            return function () {
                if (!timer) {
                    timer = setTimeout(function () {
                        fn()
                        //用null的形式清空
                        timer = null
                    }, t)
                }

            }

        }
        box.addEventListener('mousemove', throttle(move, 500))
    </script>
</body>

</html>

定时器函数中无法清空定时器,需要使用timer = null实现

总结

防抖会被打断,只执行最后一次

节流不会被打断

案例

模态框

html 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<style>
    * {
        margin: 0;
        padding: 0;
    }

    button {
        margin: 10px 5px;
    }

    .modal {
        width: 300px;
        height: 200px;
        margin: 200px auto;

        border: 1px solid grey;
        box-shadow: 0 2px 10px;
    }

    .header {
        margin: 30px;
    }

    .header i {
        margin-left: 165px;
        color: darkgrey;
        cursor: pointer;
    }

    .body {
        text-align: center;
    }
</style>

<body>
    <button id="delete">删除</button>
    <button id="login">登录</button>
    <button id="add">新增</button>
    <!-- <div class="modal">

    </div> -->
    <script>

        function Modal(title = '', message = '') {
            this.modalBox = document.createElement('div')
            this.modalBox.className = 'modal'
            this.modalBox.innerHTML = `
            <div class="header">${title}<i>x</i></div>
            <div class="body">${message}</div>
            `
            console.log(this.modalBox)

        }

        //挂在open方法
        Modal.prototype.open = function () {
            //先判断是否有modal盒子  重点*******!!!!!!!!!
            const box = document.querySelector('.modal')
            box && box.remove()
            //把创建的MOdalBOx创建到页面中
            document.body.append(this.modalBox)
            this.modalBox.querySelector('i').addEventListener('click', () => {
                this.close()
            })
        }
        //close方法
        Modal.prototype.close = function () {
            this.modalBox.remove()
        }

        //点击删除按钮
        document.querySelector('#delete').addEventListener('click', () => {
            //调用modal构造函数
            const del = new Modal('温馨提示', '您没有权限删除操作')
            //实例对象调用open方法
            del.open()
        })
        //点击登录按钮
        document.querySelector('#login').addEventListener('click', () => {
            //调用modal构造函数
            const login = new Modal('友情提示', '您还没有注册账号')
            //实例对象调用open方法
            login.open()
        })

        //点击新增按钮
        document.querySelector('#add').addEventListener('click', () => {
            //调用modal构造函数
            const add = new Modal('提示', '您还没有新增权限')
            //实例对象调用open方法
            add.open()
        })

    </script>
</body>

</html>

视频节流

html 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <div class="container">
        <div class="header">
            <a href="">
                <img src="" alt="">
            </a>
        </div>
        <div class="video">
            <video src="../766b28f4e90a8b86db4854f2fb648791.mp4" controls>
            </video>
        </div>
        <div class="elevator">
            <a href="javascript:;" data-ref="video">视频介绍</a>
            <a href="javascript:;" data-ref="intro">课程简介</a>
            <a href="javascript:;" data-ref="outline">评论列表</a>
        </div>
    </div>
    <script src="../lodash.min.js"></script>
    <script>
        const video = document.querySelector('video')
        video.ontimeupdate = _.throttle(() => {
            localStorage.setItem('currentTime', video.currentTime)
        }, 1000)

        video.onloadeddata = () => {
            video.currentTime = localStorage.getItem('currentTime') || 0
        }
    </script>
</body>

</html>
  1. ontimeupdate 事件在视频/音频当前的播放位置而安生改变时触发
  2. onloadeddate 事件在当前帧的数据加载完成且还没有足够数据播放的下一帧触发
相关推荐
小碗羊肉1 小时前
【JavaWeb | 第七篇】部门管理项目实战
java·开发语言·servlet
维诺菌2 小时前
claude code安装
java·开发语言·ai编程·calude
谙弆悕博士2 小时前
快速学C语言—— 第0章:C语言简介
c语言·开发语言·经验分享·笔记·程序人生·课程设计·学习方法
顶点多余2 小时前
自定义协议、序列化、反序列化实现
java·linux·开发语言·c++·tcp/ip
风味蘑菇干2 小时前
使用接口定义规范,实现类完成具体逻辑。
java·开发语言
MATLAB代码顾问2 小时前
【智能优化】无穷优化算法(INFO)原理与Python实现
开发语言·python·算法
2401_833269302 小时前
Java多线程:从入门到进阶
java·开发语言
z200509302 小时前
C++中的右值引用
开发语言·c++
SilentSamsara2 小时前
迭代器协议:`__iter__` / `__next__` 的完整执行流程
开发语言·人工智能·python·算法·机器学习