JavaScript 拦截器的简单了解(分享)

文章目录

      • 1. 闭包语法糖
      • 2. class/get/set
      • 3. 属性拦截器
      • 4. 对象代理拦截器

1. 闭包语法糖

// 这种set、get方法可以添加约束
// set必须要有参数,get必须要有返回值
function fn() {
  let num = 10
  return {
    set num(value) {
      console.log("num被修改了");
      num = value
    },
    get num() {
      console.log("num被访问了");
      return num
    }
  }
}

let obj = fn()
obj.num  	  // num被访问了
obj.num = 20  // num被修改了

2. class/get/set

// 和闭包一样,对 num 这个私有属性添加约束
class Fn {
  #num = 10
  set num(value) {
    console.log("num被修改了");
    this.#num = value
  }
  get num() {
    console.log("num被访问了");
    return this.#num
  }
}

let obj = new Fn()
obj.num 	  // num被访问了
obj.num = 20  // num被修改了

3. 属性拦截器

// vue2就是采用 Object.defineProperty 的方法对数据进行数据劫持
// 下面这个方法会有很多的问题,只能对一个属性添加依赖,并且只相对于第一层属性
let obj = {
  name: "小红"
}
let temp = obj.name
Object.defineProperty(obj, "name", {
  set(value) {
    console.log("你修改了该属性");
    temp = value
  },
  get() {
    console.log("你访问了该属性");
    return temp
  }
})
obj.name  		   // 你访问了该属性
obj.name = "小黄"  // 你修改了该属性
// 代码优化
// 这里手动封装了一个添加依赖的方法,但是还是只能一个一个添加
// 其实也可以采用递归深拷贝的方式,为每一个属性添加依赖,这样就不用一个个添加了
// 当然这种方式也会存在一些问题,比如添加或删除属性时,这种方式拦截不到
let obj = {
  name: "小红",
  age: 18,
  a: {
    b: {
      c: 111
    }
  }
}

// 封装添加约束方法
function defineReactive(obj, data) {
  let value = obj[data]
  Object.defineProperty(obj, data, {
    set(newValue) {
      console.log("你修改了该属性");
      value = newValue
    },
    get() {
      console.log("你访问了该属性");
      return value
    }
  })
}
defineReactive(obj, "name")
obj.name  		   // 你访问了该属性
obj.name = "小黄"  // 你修改了该属性

defineReactive(obj.a.b, "c")
obj.a.b.c 		 // 你访问了该属性
obj.a.b.c = 20   // 你修改了该属性

4. 对象代理拦截器

  • vue3就是采用 Proxy 代理对象对数据进行劫持的
  • vue2和vue3的这两种方式要等以后vue文章里面会讲到
// 这种方法对于增删改查都可以拦截到
let obj = {
  name: "小红",
  age: 18,
  a: {
    b: 10
  }
}

let proxy = new Proxy(obj, {
  get(obj, prop) {
    console.log("访问了该属性:", prop);
    return prop
  },
  set(obj, prop, value) {
    if (obj[prop]) {
      console.log("修改了该属性:", prop, " 修改后的值为:", value);
      obj[prop] = value
    } else {
      console.log("添加了该属性:", prop, " 添加的值为:", value);
      obj[prop] = value
    }
  },
  deleteProperty(obj, prop) {
    console.log("删除了该属性:", prop);
    return true
  },
})

proxy.name  // 访问了该属性: name
proxy.sex = "男" // 添加了该属性: sex  添加的值为: 男
proxy.sex = "女" // 修改了该属性: sex  修改后的值为: 女
delete proxy.sex // 删除了该属性: sex

// 这一步我想访问 b 但是显示的却是 a,说明 Proxy 这种方式只对第一层做了拦截
// 这种方法也是可以采用递归去解决的,把更深层的属性添加到 Proxy 返回对象对应的属性上
proxy.a.b // 访问了该属性: a

你可能感兴趣的:(JS,javascript,前端,vue.js)