手头有点紧 晚上偷偷学习劫持小技巧

102 阅读4分钟

函数柯里化

  • 函数的科里化 就是将一个可以接收多个参数的函数改装为只能接收一个参数 然后多次调用的函数
  • 利用函数闭包延长外部函数的参数的使用时间

函数柯里化封装

  • 思路
    • 外层函数负责接收参数
    • 内层函数在参数接收到指定数量的时候将参数传递给功能函数
      • 同时判断参数的数量是否达到要求
      • (函数名.length)可以获取到函数的形参
      • js函数的constructor属性中有length属性 该属性为函数的形参数量
      function my(a, c, f, g) {
          console.log(arguments.length)
      }
      my(1,2,2,3)
      console.log(my.prototype)
      
      • arguments.length为调用时传递实参的数量
  • 科里化的步骤
    • 首先书写一个可以接收多个参数的函数
        function myAdd(a, b, c, d) {
            return a + b + c + d
        }//该函数接收4个数字 在实参传递不足的情况下 会返回NaN(Not a Number)
    
    • 所以 我们可以封装一个函数来保证传递的参数一定达到要求
    • 随便写一个吧 (约定首个参数为功能函数且可以接收多个形参)
        function myCurring(callback, ...arg) {
            return (...Arg) => {
                Arg = [...arg,...Arg]
                if (callback.length === 4) {
                    return callback(...Arg)
                } else {
                    return myCurring(callback, ...Arg)
                    //参数不足 继续接收参数 直到达到要求
                }
            }
        }
        let s = myCurring(myAdd,1)
        console.log(s(2, 3, 4))// 10
    

函数的防抖与节流

  • 节流:在一定时间内快速触发某一事件 在规定时间内只能触发一次 上一次事件结束之后才可以继续触发
    • 实现思路:
      • 需要一个初始变量 假设为flag = true
      • 在事件开始时判断其是否为false是则返回中断函数 同时将flag的值赋值为false
      • 事件结束时将flag重新赋值为 true
   <style>
        div{
            height: 100px;
            width: 100px;
            background-color: pink;
        }
    </style>
   <body>
    <div></div>
    <script>
        let flag = true
        let oDiv = document.querySelector('div')
        oDiv.onclick = function (e) {
            if (!flag) return
            flag = false
                let num = 5
            let timer = setInterval(() => {
                num--
                this.innerHTML = num
                if(num == 0){
                    clearInterval(timer)
                    flag = true
                }
            },1000)
        }
    </script>
</body>

数据劫持

  • 数据劫持 顾名思义 就是劫持一个数据
  • 方法(语法):Object.defineProperty(劫持对象(非人),要劫持的属性,{配置劫持方法})
  • 内部的一些劫持方法
    • value 访问该劫持属性是 会获取到的值
    • writable 决定当前属性是否能被修改
    • enumerable 决定当前属性能否被枚举(遍历)
    • getter 是一个函数 当访问这个属性时会执行的函数
    • setting 函数 当要修改这个属性的时候会调用的函数
    • getter 不能和 value writable同时使用
  • 例(语法)
     Object.defineProperty(obj, 'age', {
            enumerable: true,
            get() {
                // console.log('你当前访问了 这个 age 属性, 触发了 get 函数')
                return 'qwer'
            },
            set(val) {
                console.log('你当前想要修改这个 age 属性, 修改的值 是: ', val)
            }
        })

模拟数据劫持 + 渲染

  • 实现数据驱动视图(视图与数据更新保持同步)
  • 实现原理 setting函数在每一设置属性时 都会被调用 所以在该函数内渲染界面(每次修改都会重新渲染界面)
    <body>
    <div></div>
    <script>
        let oDiv = document.querySelector('div')
        let obj = {
            a:10
        }
        const res = {}
        Object.defineProperty(res,a,{
            get () {
                return obj.a
            },
            set (val) {
                obj.a = val
                Odiv.innerText = res.a
            }
        })
        Odiv.innerText = res.a //1100
        res.a = 1100
    </script>
</body>

数据劫持升级

  • 将上一步操作进行封装(模仿框架的0.0000001%功能)
  • 满足部分功能
  • 语法
    1. 升级版 语法: Object.defineProperties(到那个对象, { 属性1: 配置项, 属性2: 配置项 })
      for (let k in obj) {
            Object.defineProperties(obj, {
                ['_' + k]: {    // 我在我这个对象内把所有属性复制一份, 放在自己这个对象内部
                    value: obj[k],
                    writable: true
                },
                [k]: { //将k作为变量使用 需要添加[]包裹 否则将会被当做字符串
                    get () {
                        return obj['_' + k]
                    },
                    set(val) {
                        obj['_' + k] = val
                    }
                }
            })
        }

数据代理

  • 数据代理 类似一个第三方 好比销售代理 我随时可获取你的产品 我帮你销售就行 你只管更新产品
  • Proxy(劫持对象,配置项) 接收一个参数 和一个配置项 target p
    • Proxy内的get方法接收两个参数 target p
      • target为当前代理对象 P为该对象的每一个key 也就是说 Proxy自带遍历
      • p为遍历后的每一个key
    • set方法接收第三个参数 `set(target, p, value)
      • value为我们需要使用的参数
                    const obj = {
            name: 'QF001',
            age: 18
        }
        const res = new Proxy(obj, {
            get (target, p) {
                return target[p]
            },
            set (target, p, val) {
                target[p] = val
                console.log('你想要修改某一个属性')
                return true // 代表修改成功
            }
        })
    
        res.age = 99
    
        obj.abc = 999
    
        res.abc = 666
    
        console.log(res)