[Questions d'entretien] JavaScript avancé quatre, compétences avancées

JavaScript avancé quatre, compétences avancées

1. Copie profonde et superficielle

  • Tout d'abord, la copie superficielle et la copie approfondie ne concernent que les types de référence

(1) copie superficielle

  • Copie superficielle : copiez la valeur de l'attribut de l'objet ( 简单类型la valeur stockée est 值本身, 引用类型la valeur stockée est 对象的堆地址), donc s'il y en a une dans la valeur de l'objet copié 引用类型属性, le nouvel attribut de l'objet copié et l'attribut de l'objet source pointent vers la même adresse , 修改et l'objet pointu sera 相互影响.

  • Méthode commune :

    • Copier des objets : Object.assgin() ou l'opérateur de propagation {...obj}
    • Copier le tableau : Array.prototype.concat() ou [...arr]

Le cas est le suivant :

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>浅拷贝</title>
</head>

<body>
    <script>
        const user = {
            uname: 'pink',
            age: 18,
            family: {
                baby: '小pink'
            }
        }

        // 浅拷贝
        const o1 = {...user
        }
        o1.age = 20 //对象属性值类型修改不影响
        console.log(o1.age) //20
        console.log(user.age) //18

        // 浅拷贝
        const o2 = {}
        Object.assign(o2, user)
        o2.age = 20
        o2.family.baby = '老pink' //对象属性引用类型修改会相互影响
        console.log(o2.family.baby) //老pink
        console.log(user.family.baby) //老pink
    </script>
</body>

</html>

(2) Copie profonde

  • Copie en profondeur : lors de la copie des propriétés d'un objet, un nouvel objet est créé lorsqu'un type de référence est rencontré, puis de manière récursive jusqu'à ce que tous les champs soient copiés.
  • Méthode commune :
    • La fonction récursive implémente la copie en profondeur
      • Une fonction est récursive si elle peut s'appeler en interne
      • Comme la récursivité est sujette aux erreurs de "débordement de pile" (stack overflow), il est nécessaire d'ajouter la condition de sortie return
    • lodash.cloneDeep réalise une copie profonde
    • JSON.stringify réalise une copie profonde

La fonction récursive implémente la copie en profondeur :

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>递归函数实现深拷贝</title>
</head>

<body>
    <script>
        const obj = {
            uname: 'pink',
            age: 18,
            hobby: ['乒乓球', '足球'],
            family: {
                baby: '小pink'
            }
        }
        const o = {}

        // 拷贝函数
        function deepCopy(newObj, oldObj) {
            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]
                }
            }
        }

        // 函数调用  两个参数 o 新对象  obj 旧对象
        deepCopy(o, obj)
        o.age = 20
        o.hobby[0] = '篮球'
        o.family.baby = '老pink'
        console.log(o.age) //20
        console.log(o.hobby[0]) //篮球
        console.log(o.family.baby) //老pink
        console.log(obj.age) //18
        console.log(obj.hobby[0]) //乒乓球
        console.log(obj.family.baby) //小pink
    </script>
</body>

</html>

lodash.cloneDeep réalise une copie profonde :

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>lodash.cloneDeep实现深拷贝</title>
</head>

<body>
    <!-- 先引用 -->
    <script src="./lodash.min.js"></script>
    <script>
        const obj = {
            uname: 'pink',
            age: 18,
            hobby: ['乒乓球', '足球'],
            family: {
                baby: '小pink'
            }
        }
        const o = _.cloneDeep(obj)
        o.age = 20
        o.hobby[0] = '篮球'
        o.family.baby = '老pink'
        console.log(o.age) //20
        console.log(o.hobby[0]) //篮球
        console.log(o.family.baby) //老pink
        console.log(obj.age) //18
        console.log(obj.hobby[0]) //乒乓球
        console.log(obj.family.baby) //小pink
    </script>
</body>

</html>

JSON.stringify implémente la copie en profondeur :

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>JSON.stringify实现深拷贝</title>
</head>

<body>
    <script>
        const obj = {
                uname: 'pink',
                age: 18,
                hobby: ['乒乓球', '足球'],
                family: {
                    baby: '小pink'
                }
            }
            // 把对象转换为 JSON 字符串    
        const o = JSON.parse(JSON.stringify(obj))
        o.age = 20
        o.hobby[0] = '篮球'
        o.family.baby = '老pink'
        console.log(o.age) //20
        console.log(o.hobby[0]) //篮球
        console.log(o.family.baby) //老pink
        console.log(obj.age) //18
        console.log(obj.hobby[0]) //乒乓球
        console.log(obj.family.baby) //小pink
    </script>
</body>

</html>

2. Gestion des exceptions

  • La gestion des exceptions consiste à estimer les erreurs pouvant survenir lors de l'exécution du code, puis à éviter au maximum l'apparition d'erreurs afin que l'ensemble du programme ne puisse pas continuer à s'exécuter.

(1) lancer lève une exception

  • jeter  抛出异常信息, le programme aussi会终止执行
  • lancer suivi du message d'erreur
  • L'objet Error est utilisé conjointement avec throw pour définir des informations d'erreur plus détaillées

Le cas est le suivant :

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>throw抛出异常</title>
</head>

<body>
    <script>
        function fn(x, y) {
            if (!x || !y) {
                // throw '没有参数传递进来'
                throw new Error('没有参数传递过来')
            }

            return x + y
        }
        console.log(fn())
    </script>
</body>

</html>

image-20230530140409885

(2) essayer /attraper l'exception de capture

  • try...catch est utilisé pour capturer les messages d'erreur
  • Écrivez le code qui estime que des erreurs peuvent se produire dans le segment de code try
  • Si une erreur se produit dans le segment de code try, le segment de code catch sera exécuté et le message d'erreur sera intercepté
  • finally sera exécuté qu'il y ait ou non une erreur

Le cas est le suivant :

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>try-catch捕获异常</title>
</head>

<body>
    <p>123</p>
    <script>
        function fn() {
            try {
                // 可能发送错误的代码 要写到 try
                const p = document.querySelector('.p')
                p.style.color = 'red'
            } catch (err) {
                // 拦截错误,提示浏览器提供的错误信息,但是不中断程序的执行
                console.log(err.message)
            } finally {
                // 不管你程序对不对,一定会执行的代码
                console.log('不管你程序对不对,一定会执行的代码')
            }
            console.log(11)
        }
        fn()
    </script>
</body>

</html>

image-20230530140903442

(3) débogueur

  • Vous pouvez ajouter un débogueur dans le code pour déboguer le code avec un point d'arrêt

image-20230530141922325

3. Gérez ceci

(1) cette orientation

  • Fonction ordinaire vers laquelle pointe

    • Qui en appelle la valeur à qui
    • Lorsqu'une fonction ordinaire n'a pas d'appelant clair, la valeur de this est window, et lorsqu'il n'y a pas d'appelant en mode strict, la valeur de this est indéfinie
  • La fonction fléchée vers laquelle pointe

  • Le this dans la fonction de flèche n'existe pas, le this dans la fonction de flèche est le this dans la portée liée la plus proche, et ceci est recherché dans la portée externe couche par couche jusqu'à ce qu'il y ait une définition de this

  • Non applicable : constructeurs, fonctions prototypes, fonctions dans des objets littéraux, fonctions d'événement dom, etc.

  • Situation applicable : où la couche supérieure doit être utilisée

Le cas est le suivant :

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>普通函数的this指向</title>
</head>

<body>
    <button>点击</button>
    <script>
        // 普通函数:谁调用我,this就指向谁
        console.log(this) // window
        function fn() {
            console.log(this) // window    
        }
        window.fn()
        window.setTimeout(function() {
            console.log(this) // window 
        }, 1000)
        document.querySelector('button').addEventListener('click', function() {
            console.log(this) // 指向 button
        })
        const obj = {
            sayHi: function() {
                console.log(this) // 指向 obj
            }
        }
        obj.sayHi()
    </script>
</body>

</html>

(2) changer ceci

  • JavaScript permet également de spécifier le pointage de this dans une fonction, et il existe 3 méthodes pour spécifier dynamiquement le pointage de this dans une fonction normale
  • appel()
    • En utilisant la méthode call 调用函数,  la valeur 指定dans la fonction appelée  en même tempsthis
    • grammaire:fun.call(thisArg, arg1, arg2, ...)
      • thisArg : la valeur this spécifiée lorsque la fonction fun est en cours d'exécution
      • arg1, arg2 : arguments supplémentaires passés
      • La valeur de retour est la valeur de retour de la fonction, car c'est la fonction appelante
  • appliquer()
    • Utilisez la méthode apply 调用函数, tandis que  la valeur 指定de la fonction appelée this
    • grammaire:fun.apply(thisArg, [argsArray])
      • thisArg : la valeur this spécifiée lorsque la fonction fun est en cours d'exécution
      • argsArray : valeurs passées,必须包含在数组里面
      • La valeur de retour est la valeur de retour de la fonction, car c'est la fonction appelante
      • 因此 apply 主要跟数组有关系,比如使用 Math.max() 求数组的最大值
  • lier()
    • méthode bind() 不会调用函数. 指定la valeur dans la fonction appelée  this , renvoyant la nouvelle fonction
    • grammaire:fun.bind(thisArg, arg1, arg2, ...)
      • thisArg : la valeur this spécifiée lorsque la fonction fun est en cours d'exécution
      • arg1, arg2 : arguments supplémentaires passés
      • Renvoie la valeur modifiée par la valeur spécifiée et les paramètres d'initialisation 原函数拷贝 (新函数)
      • 因此只改变 this 指向,不调用函数时,使用 bind,比如改变定时器内部的this指向.

Le cas d'appel est le suivant :

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>call</title>
</head>

<body>
    <script>
        const obj = {
            uname: 'pink'
        }

        function fn(x, y) {
            console.log(this) // window
            console.log(x + y)
        }

        // 1. 调用函数  
        // 2. 改变this指向obj,原来是window调用指向window
        // 3. 返回值就是函数的返回值
        fn.call(obj, 1, 2)
    </script>
</body>

</html>

Le cas d'application est le suivant :

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>apply</title>
</head>

<body>
    <script>
        const obj = {
            age: 18
        }

        function fn(x, y) {
            console.log(this)
            console.log(x + y)
        }
        // 1. 调用函数
        // 2. 改变this指向
        // 3. 返回值就是函数的返回值
        fn.apply(obj, [1, 2])

        // 使用场景:求数组最大值最小值
        const arr = [100, 44, 77]
        const max = Math.max.apply(Math, arr)
        const min = Math.min.apply(null, arr)
        console.log(max, min)
    </script>
</body>

</html>

Le cas de liaison est le suivant :

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>bind</title>
</head>

<body>
    <button>发送短信</button>
    <script>
        const obj = {
            age: 18
        }

        function fn() {
            console.log(this)
        }

        // 1. bind不会调用函数 
        // 2. 能改变this指向
        // 3. 返回值是个函数,但是这个函数里面的this是更改过的obj
        const fun = fn.bind(obj)
        fun()

        // 需求:有一个按钮,点击里面就禁用,2秒钟之后开启
        document.querySelector('button').addEventListener('click', function() {
            // 禁用按钮
            this.disabled = true
            window.setTimeout(function() {
                    // 在这个普通函数里面,我们要this由原来的window 改为 btn
                    this.disabled = false
                }.bind(this), 2000) // 这里的this 和 btn 一样
        })
    </script>
</body>

</html>

4. Optimisation des performances

(1) Anti-tremblement

  • L'anti-shake signifie qu'après le déclenchement de l'événement, la fonction ne peut être exécutée qu'une seule fois dans les n secondes. Si l'événement se déclenche à nouveau dans les n secondes, le 重新计算temps d'exécution de la fonction sera réduit.
  • Scénario d'utilisation : saisie dans la zone de recherche, définissez la requête à envoyer après n secondes après chaque saisie, s'il y a encore une saisie pendant la période, recalculez le temps

Le cas est le suivant :

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>防抖</title>
    <style>
        .box {
            width: 500px;
            height: 500px;
            background-color: #ccc;
            color: #fff;
            text-align: center;
            font-size: 100px;
        }
    </style>
</head>

<body>
    <div class="box"></div>
    <script>
        const box = document.querySelector('.box')
        let i = 1

        //数值加1
        function mouseMove() {
            box.innerHTML = ++i
        }

        // 防抖函数
        function debounce(fn, t) {
            let timeId
            return function() {
                // 如果有定时器就清除
                if (timeId) clearTimeout(timeId)

                // 开启定时器
                timeId = setTimeout(function() {
                    fn()
                }, t)
            }
        }
        //鼠标移动触发函数
        box.addEventListener('mousemove', debounce(mouseMove, 1000))
    </script>
</body>

</html>

(2) étranglement

  • Le soi-disant étranglement fait référence au déclenchement d'événements en continu mais à l'exécution d'une fonction une seule fois en n secondes
  • Scénarios : Lorsque la souris se déplace, la taille de la page change et la barre de défilement défile, etc., la surcharge est relativement élevée

Le cas est le suivant :

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>节流</title>
    <style>
        .box {
            width: 500px;
            height: 500px;
            background-color: #ccc;
            color: #fff;
            text-align: center;
            font-size: 100px;
        }
    </style>
</head>

<body>
    <div class="box"></div>
    <script>
        const box = document.querySelector('.box')
        let i = 1

        //数值加1
        function mouseMove() {
            box.innerHTML = ++i
        }

        // 节流函数
        function throttle(fn, t) {
            // 起始时间
            let startTime = 0
            return function() {
                // 得到当前的时间
                let now = Date.now()

                // 判断如果大于等于 500 调用函数
                if (now - startTime >= t) {
                    // 调用函数
                    fn()

                    // 起始的时间 = 现在的时间
                    startTime = now
                }
            }
        }
        box.addEventListener('mousemove', throttle(mouseMove, 1000))
    </script>
</body>

</html>

(3) étranglement lodash et anti-tremblement

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>lodash节流和防抖</title>
    <style>
        .box {
            width: 500px;
            height: 500px;
            background-color: #ccc;
            color: #fff;
            text-align: center;
            font-size: 100px;
        }
    </style>
</head>

<body>
    <div class="box"></div>
    <script src="./lodash.min.js"></script>
    <script>
        const box = document.querySelector('.box')
        let i = 1

        //数值加1
        function mouseMove() {
            box.innerHTML = ++i
        }

        // lodash 节流
        // box.addEventListener('mousemove', _.throttle(mouseMove, 500))
        // lodash 防抖
        box.addEventListener('mousemove', _.debounce(mouseMove, 500))
    </script>
</body>

</html>

Banque de questions d'entrevue frontale ( nécessaire pour l'entrevue) recommandation : ★★★★★            

Adresse : banque de questions d'entrevue frontale

Je suppose que tu aimes

Origine blog.csdn.net/weixin_42981560/article/details/132304176
conseillé
Classement