JS中的自执行函数,函数的节流和防抖,数据劫持

85 阅读3分钟

自执行函数

作用:自定义函数不用调用,自己自动执行,节省代码量
书写时注意:
    =>自执行函数前必须在最前面添加一个分号,和上一行代码起到分隔作用
    =>自执行函数如果需要传参时,将实参写在 第二个小括号里

 例:
     ;(function fn (num){
         return num
     })(5)
     

函数的节流和防抖

1.节流:
    事件在执行时,第一次开始执行时,在结束之前或者在指定时间之前,无法触发下一次,除非等到第一次执行结束或者在指定时间到达后,才可以进行下一次
2.防抖:
    事件在开始执行时,如果快速触发了第二次,那么第二次会取代第一次,只会执行第一次
节流与防抖的实例:
    <input type="text" class"inp">
    <script>
        const inp = document.querySelector('.inp')
        //基础版
        inp.oninput  = function (){
            console.log(input.value)
        }
        //节流
        inp.oninput = (function(flag){
            return function () {
                if(flag === flase) return
                flag = flase
                setTimeout(()=>{
                    flag = true
                    console.log(this.value)
                },300);
            }
        })(true)
        //防抖
        inp.oninput = (function (timer){
            return function (){
                clearInterval (timer)
                timer = setTimeout(() => {
                    console.log(this.value)
                },300)
            };
        })(0)
    </script>

数据劫持

我们在使用框架的时候(vue),框架目前都支持"数据驱动视图",完成数据驱动试图  需要借助  数据劫持帮助我们完成
以原始数据为基础,对数据进行一份复刻,复刻出来的数据不允许修改,值 从原始数据中获取
语法1:
    Object.definedProperty('劫持到哪一个对象','属性',{配置项})
    配置项:
        value:这个属性对应的值
        writable:该属性是否可以被重写,默认值是 false 不允许被修改
        enumerable:该属性是否可以被枚举,默认是false 不能被枚举到
        get:是一个函数,叫做 getter 获取器,可以决定当前属性的值,不能与 value,writable 同时出现
        set:是一个函数,叫做 setter 设置器,当你需要修改这个属性的时候,会触发该函数
例:
    <h1 class="box"></h1>
    <h1 class="box2"></h1>
    <script>
        const box = document.querySelector('.box')
        const box2 = document.querySelector('.box2')
        //原始对象
        const obj = {}
        obj.name = '彭于晏'
        obj.age = 41
        // 如果劫持的属性多了,原本的写法不太方便, 代码量比较多, 所以封装数据劫持
        function obsever(origin, callback){
        
            // 1.创建一个对象,将origin 内部的属性劫持到这个对象中
            const target = {}
            
            // 2.劫持 origin 上的属性到 target 中
            for(let key in origin){
                Object.defineProperty(target,key,{
                    enumerable:true,
                    get(){
                        return origin[key]
                    },
                    set(val){
                        origin[key] = val
                        callback(target)
                    }
                })
            }
            // 将劫持后的 target 返回出去
            return target
        }
        const newObj = obsever(obj,()=>{console.log('回调函数执行')})
        function fn (res){
            box.innerHTML = `姓名:${target.name};年龄:${target.age}`
        }
    </script>
语法2:
    Object.defineProperties('哪个队象',{配置项})
例:
  <h1 class="box"></h1>
  <h1 class="box2"></h1>
  <script>
      const box = document.querySelector('.box')
      const box2 = document.querySelector('.box2')
      const obj = {}
      obj.name = '彭于晏'
      obj.age = 41
      
      // 将数据劫持后的对象属性存放在 res 对象中
      const res = {}
      Object.defineProperties(res, {
      age:{
          get(){
            return obj.age
          },
          set(val){
            box2.innerHTML = `res 对象的 age 属性:${val}, name 属性:${res.name}}`
            obj.age = val
          }
      },
      name:{
          get(){
            return obj.name
          },
          set(val2){
            box2.innerHTML = `res 对象的 age 属性:${res.name},name 属性:${val2}`
            obj.name = val2
          }
      }
    })
    box.innerHTML = `obj 对象的 age 属性:${obj.age},name 属性:${obj.name}`
    box2.innerHTML = `res 对象的 age 属性:${res.age},name 属性:${res.name}`
    
    console.log(res)
    </script>
    
    //升级版  自己劫持自己(全都在 原始对象上进行操作)
    for (let key in obj){
        Object.defineProperties(obj,{
            // 不会再对象的原始属性上操作, 而是复制出来一份一模一样的数据操作
            //为了和原属性姓名相同, 所以会在 原本的属性名前 加一个下划线, 用来区分
            ['_' + key]: {
                value:obj[key],
                writable: true
            },
            [key]: {
                get() {
                    return obj['_' + key]
                },
                set(){
                    obj['_' + key] = val
                    box.innerHTML = `obj 对象的 name 属性:${obj.name},age 属性:${obj.age}`
                }
            }
        })
    }
    //首次打开页面时,给页面做一个赋值
    box.innerHTML = `obj 对象的 name 属性:${obj.name},age 属性:${obj.age}`
    //首次渲染页面后,更改对象的属性值
    obj.name = '秦霄贤'
    obj.age = 24

数据代理

数据代理类似于自己劫持自己
数据代理 是 官方定义的一个名字,有部分程序员还是习惯性的叫做  数据劫持
proxy  是 ES6 以后官方推出的  是一个内置构造函数
        new proxy 第一个参数  要代理的对象
                  第二个参数  一些配置项
                  最后会返回一个代理后的对象,我们需要使用一个变量去接收
    
例:
    const obj = {
        name;"秦霄贤",
        age:24
    }
    const res = new Proxy(obj,{
        get(target, property){
            return target[property]
        },
        set(target, property, val){
            target[property] = val
        }
    })
    //在代理完成后给原始对象新加一个属性, 此时代理对象依然是能够访问到(Proxy   独有的功能)
    obj.sex= '男'
    console.log(res.name)
    console.log(res.age)
    console.log(res.sex)