返回顶部
首页 > 资讯 > 精选 >JavaScript defineProperty怎么实现属性劫持
  • 644
分享到

JavaScript defineProperty怎么实现属性劫持

2023-06-20 16:06:40 644人浏览 八月长安
摘要

本篇内容主要讲解“javascript defineProperty怎么实现属性劫持”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“JavaScript defineProperty怎么实现属性劫

本篇内容主要讲解“javascript defineProperty怎么实现属性劫持”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“JavaScript defineProperty怎么实现属性劫持”吧!

目录
  • 前言

  • 描述符

  • 细说get 和 set

  • 劫持对象的某个属性

  • 劫持对象的所有属性

  • 劫持对象的所有属性 - 包括对象类型的属性值

  • defineProperty的缺陷

  • defineProperty还可以挂载属性

  • defineProperty还能写日志

前言

defineProperty是Vue实现数据劫持的核心,本文一点点的说明defineProperty怎么实现属性劫持的。

其实我们一般的操作对象属性的方式,增加或者修改属性,均可以使用Object.defineProperty。

let obj = {};// 寻常操作:增加/修改 新属性obj.a = 1;// 等同于:Object.defineProperty(o, "a", {  value: 1,  writable: true,  configurable: true,  enumerable: true});

当然寻常的例子,我们是不会这么玩的,太啰嗦了。

但defineProperty可以更精确地添加或修改对象的属性。

描述符

先说个专有名词:描述符。

其实就是defineProperty的第三个参数,是个对象。这个对象的有以下属性:

  • configurable 属性:能不能修改描述符,就是能不能再次修改描述符的其他属性

  • enumerable 属性:能不能枚举该属性,就是 a 属性能不能被 for 到

  • writable 属性:能不能修改属性值,就是能不能这样修改obj.a = 1

  • value 属性:该属性的值

  • get 属性:是个函数,当访问该属性的时候,函数自动调用,函数返回值就是该属性的值

  • set 属性:是个函数,当修改该属性的时候,函数自动调用,函数有且只有一个参数,赋值的新值

注意!!!

  • 描述符里的value属性 writable属性 与 get属性 set属性是互斥的关系,只能存在一个

  • 另外的属性默认值都是false,不想false的话,记得配置哈,不细说(主要我也不怎么用)。

细说get 和 set

  • get 属性:是个函数,当访问该属性的时候,函数自动调用,函数返回值就是该属性的值

  • set 属性:是个函数,当修改该属性的时候,函数自动调用,函数有且只有一个参数,赋值的新值

默念三遍,背诵。

写个get 和 set 的例子辅助理解。

这个例子必须掌握,弄懂之后基本就掌握了数据劫持的精髓了

let obj = {};let value = 1;Object.defineProperty(obj, "b", {  get() {    console.log("读取b属性", value);    return value;  },  set(newValue) {    console.log("设置b属性", newValue);    value = newValue;  }});// 触发get函数,get的返回值就是属性值// 1console.log(obj.b);// 触发set函数,value的值变成了2,注意!!!,此时内存里,属性值并没有改变obj.b = 2;// 但是,想要读取属性值的时候,就必然会触发get函数,属性值也自然就改变了,这个思想真的很赞console.log(obj.b);

这里有个坑:get里是不能有读取的操作,不然一直死循环,所以使用到get set的地方,总需要借助一个变量

所以,这里,变量value的值就是属性的值,如果想要修改属性,修改 value 的值即可。

这个例子弄懂了,get,set 的精髓,我觉得也就差不多了。

劫持对象的某个属性

有了刚刚例子的基础,试着写写劫持对象的任意一个属性。

function observeKey(obj, key) {  let value = obj[key];  Object.defineProperty(obj, key, {    get() {      console.log("读取属性", value);      return value;    },    set(newValue) {      console.log("设置属性", newValue);      value = newValue;    }  });}let obj = { a: 1 };observeKey(obj, "a");// 读取a,触发get函数console.log(obj.a);// 设置a,触发set函数obj.a = 1;

劫持对象的所有属性

再试试劫持对象的所有属性

其实就是遍历:

function observeObj(obj) {  for (let key in obj) {    // 直接使用 obj.hasOwnProperty会提示不规范    if (Object.prototype.hasOwnProperty.call(obj, key)) {      observeKey(obj, key);    }  }  return obj;}function observeKey(obj, key) {  let value = obj[key];  Object.defineProperty(obj, key, {    get() {      console.log("读取属性", value);      return value;    },    set(newValue) {      console.log("设置属性", newValue);      value = newValue;    }  });}let obj = { a: 1, b: 2 };observeObj(obj);console.log(obj);// 读取a,触发get函数console.log(obj.a);// 设置a,触发set函数obj.a = 1;

劫持对象的所有属性 - 包括对象类型的属性值

上面的有个缺陷,就是当属性值也是对象的时候,不能劫持属性值,如{a:1,c:{b:1}}

简单,递归,补上就行。

function observeObj(obj) {  // 加上参数限制,必须是对象才有劫持,也是递归的终止条件  if (typeof obj !== "object" || obj == null) {    return;  }  for (let key in obj) {    // 直接使用 obj.hasOwnProperty会提示不规范    if (Object.prototype.hasOwnProperty.call(obj, key)) {      observeKey(obj, key);      // 这里劫持该属性的属性值,如果不是对象直接返回,不影响      observeObj(obj[key]);    }  }  return obj;}function observeKey(obj, key) {  let value = obj[key];  Object.defineProperty(obj, key, {    get() {      console.log("读取属性", value);      return value;    },    set(newValue) {      console.log("设置属性", newValue);      value = newValue;    }  });}let obj = { a: 1, b: 2, c: { name: "c" } };observeObj(obj);console.log(obj);// 读取a,触发get函数console.log(obj.a);// 设置a,触发set函数obj.a = 1;// 触发set函数obj.c.name = "d";

注意,observeObj这个函数,不能劫持对象的新增属性,只能劫持对象已有的属性。

defineProperty的缺陷

  • 不能监测对象增加属性

  • 不能监测对象删除属性

  • 不能劫持数组的修改

当然数组的修改可以通过别的方式监测到的,其是通过劫持改变数组方法实现的。

以上缺陷,也是vue里面为啥有$set/$delete以及对数组只能使用特定方法才能检测到。

let obj = { a: 1, b: [1, 2] };observeObj(obj);// 新增属性obj.c = 3;// 不会触发get函数console.log(obj.c);// 不会触发set函数obj.b.push(3);

defineProperty还可以挂载属性

其实就是访问options.data.name 可以简写成 options.name,专业话术,将data上的属性挂载到options上

相当于,用defineProperty,在options上增加新属性:

// 先挂载单个属性// options.data相当于source options相当于targetfunction proxyKey(target, source, key) {  Object.defineProperty(target, key, {    // 这里的source[key]相当于变量value,所以说最简单的那个例子是核心    get() {      return source[key];    },    set(newValue) {      if (newValue === source[key]) {        return;      }      source[key] = newValue;    }  });}// 遍历属性,挂载下function proxyObj(target, source) {  for (let key in source) {    // 直接使用 obj.hasOwnProperty会提示不规范    if (Object.prototype.hasOwnProperty.call(source, key)) {      proxyKey(target, source, key);    }  }}let options = {  data: { name: 1 }};proxyObj(options, options.data);// 1console.log(options.name);

话说,vue的属性劫持和挂载属性,核心原理差不多就是上面这些。

defineProperty还能写日志

比如 obj 有个属性,此属性值经常变化,想要记录其所有变化的值,以此可以形成日志。

let obj = { a: 1 };let log = [obj.a];let value = obj.a;Object.defineProperty(obj, "a", {  get() {    return value;  },  set(newValue) {    if (newValue === value) {      return;    }    value = newValue;    log.push(newValue);  }});obj.a = 2;obj.a = 3;obj.a = 4;// [1,2,3,4]console.log(log);

通用的可以抽离出一个类,专门记录某个值的变化

class ArcHiver {  constructor() {    let value = null;    this.archive = [];    Object.defineProperty(this, "a", {      get() {        return value;      },      set(newValue) {        if (newValue === value) {          return;        }        value = newValue;        this.archive.push(newValue);      }    });  }}let archiver = new Archiver();archiver.a = 1;archiver.a = 2;// [1,2]console.log(archiver.archive);

到此,相信大家对“JavaScript defineProperty怎么实现属性劫持”有了更深的了解,不妨来实际操作一番吧!这里是编程网网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

--结束END--

本文标题: JavaScript defineProperty怎么实现属性劫持

本文链接: https://lsjlt.com/news/298340.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • JavaScript defineProperty怎么实现属性劫持
    本篇内容主要讲解“JavaScript defineProperty怎么实现属性劫持”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“JavaScript defineProperty怎么实现属性劫...
    99+
    2023-06-20
  • JavaScript defineProperty如何实现属性劫持
    目录前言描述符 细说get 和 set劫持对象的某个属性 劫持对象的所有属性 劫持对象的所有属性 - 包括对象类型的属性值 defineProperty的缺陷defineProper...
    99+
    2024-04-02
  • Vue2中的数据劫持怎么实现
    今天小编给大家分享一下Vue2中的数据劫持怎么实现的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。我们今天要编写的项目通过需要...
    99+
    2023-07-05
  • JavaScript中怎么实现属性赋值
    这篇文章给大家介绍JavaScript中怎么实现属性赋值,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。原型链每个对象都有一个包含了一个或者多个对象的原型链,该对象正是这个原型链的起始对...
    99+
    2024-04-02
  • 美国主机出现域名劫持怎么办
    美国主机出现域名劫持的解决方法:1、检查美国主机是否有未知的DNS解析,如果有继续及时进行清除;2、需要修改美国主机管理员密码,防止被黑客恶意利用;3、需要检查美国主机的网站是否存在挂马或者中病毒情况,可以使用安全程序软件进行扫描查看并及时...
    99+
    2024-04-02
  • JavaScript如何实现动态属性名
    小编给大家分享一下JavaScript如何实现动态属性名,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!动态属性名我一直以为必须先声明一个对象,然后才能分配动态属性...
    99+
    2023-06-27
  • javascript中怎么获取属性
    这篇文章主要介绍javascript中怎么获取属性,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完! javascript获取属性的方法:1、创建一个对象的构...
    99+
    2024-04-02
  • JavaScript怎么获取id属性
    这篇文章主要介绍JavaScript怎么获取id属性,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!在js中,可以使用getAttribute方法获取id属性,语法格式为“对象.getAttribute(id名称)”。...
    99+
    2023-06-15
  • JavaScript计算属性与监视属性怎么使用
    本篇内容主要讲解“JavaScript计算属性与监视属性怎么使用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“JavaScript计算属性与监视属性怎么使用”吧!计算属性(computed)计算...
    99+
    2023-07-04
  • C#中怎么实现属性化
    这篇文章将为大家详细讲解有关C#中怎么实现属性化,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。C#属性化的方法属性的概念对大家来说应该是很熟悉的,类成员函数可以自由地访问本类中的任何属性成员...
    99+
    2023-06-17
  • JavaScript中怎么操作float属性
    今天就跟大家聊聊有关JavaScript中怎么操作float属性,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。JS操作css的float属性的特殊写...
    99+
    2024-04-02
  • javascript中title属性怎么使用
    本篇内容介绍了“javascript中title属性怎么使用”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!...
    99+
    2024-04-02
  • 怎么在javascript中移除属性
    这期内容当中小编将会给大家带来有关怎么在javascript中移除属性,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。在javascript中,可以利用removeAttribute() 方法来删除属性。r...
    99+
    2023-06-14
  • vue怎么使用defineProperty实现数据的双向绑定
    这篇文章主要讲解了“vue怎么使用defineProperty实现数据的双向绑定”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“vue怎么使用defineProperty实现数据的双向绑定”吧...
    99+
    2023-07-04
  • css怎么实现属性选择器
    这篇文章主要介绍了css怎么实现属性选择器,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。属性选择器属性选择器,在标签后面是有中括号标记,其基...
    99+
    2024-04-02
  • Hibernate中怎么实现属性查询
    Hibernate中怎么实现属性查询,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。List list =session.createQuery(&quo...
    99+
    2023-06-17
  • JavaScript面向对象的支持怎么实现
    本篇内容介绍了“JavaScript面向对象的支持怎么实现”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!在JavaScript中,我们需要通...
    99+
    2023-06-03
  • JavaScript中怎么删除对象属性
    今天就跟大家聊聊有关JavaScript中怎么删除对象属性,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。 1.将属性设置为 undefin...
    99+
    2024-04-02
  • JavaScript中怎么获取元素属性
    今天就跟大家聊聊有关JavaScript中怎么获取元素属性,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。首先我们需要把它们归类下:innerHTML...
    99+
    2024-04-02
  • 怎么理解Javascript中原型属性
    这篇文章主要介绍“怎么理解Javascript中原型属性”,在日常操作中,相信很多人在怎么理解Javascript中原型属性问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”怎么...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作