本文介绍`Object.defineProperty()`方法,并基于此简单讨论数据劫持的实现方案。

defineProperty

Object.getOwnPropertyDescriptor(target,attrName)方法用于获取对象的属性描述符对象,该方法的第一个参数为目标对象,第二个参数为指定的属性名。

我们可以利用该方法来查看对象属性的描述符配置项(包括:value值writable可重写enumerable可枚举configurable可配置等)。默认正常的对象属性中,这些配置项的值都是 true

var o = { name: "文顶顶", age: 18 };
var des = Object.getOwnPropertyDescriptor(o, "name");
console.log(des);
/* { value: '文顶顶',writable: true,enumerable: true,configurable: true } */

Object.defineProperty(target,attrName,options)方法用于定义(设置)对象并对指定的属性描述符对象进行配置。该方法的第一个参数为目标对象,第二个参数为指定的属性名,第三个参数为配置对象。

/* 备注:给o对象添加address属性,并设置属性值为香悦山 */
/* 说明:默认新添加的属性,属性描述配置项均为false */
var o = { name: "文顶顶", age: 18 };
Object.defineProperty(o, "address", { value: "香悦山" });
console.log(Object.getOwnPropertyDescriptor(o, "address"));
/* { value: '香悦山',writable: false,enumerable: false,configurable: false } */ /* 备注:重新定义age属性,设置属性值为20,该属性值可配置但无法重写和枚举 */
Object.defineProperty(o, "age", { value: 20, enumerable: false, writable: false });
console.log(Object.getOwnPropertyDescriptor(o, "age"));
/* { value: 20,writable: false,enumerable: false,configurable: true } */
o.age = 99;
console.log(o.age); //20
for (var key in o) {
console.log(key, o[key]);
}
/* name 文顶顶 */
/* 在for...in循环中,age键值对 ,以及新添加的address键值对均没有被枚举 */

Object.defineProperties(target,options)方法用于一次性设置(添加)对象的多个属性,与之对应的Object.getOwnPropertyDescriptors(target)方法用于获取对象中所有成员的 详细 配置信息。

Object.defineProperties(o, {
"className": {
value: "H5",
configurable: true,
},
"friends": {
value: ["胡适", "沈从文", "辜鸿铭"],
configurable: true,
writable: true
}
});
console.log("_____");
console.log(Object.getOwnPropertyDescriptors(o));
/*
{ name:{ value: '文顶顶', writable: true,enumerable: true,configurable: true },
age:{ value: 20,writable: false,enumerable: false,configurable: true },
address:{ value: '香悦山',writable: false,enumerable: false,configurable: false },
className:{ value: 'H5',writable: false,enumerable: false,configurable: true },
friends:{ value: [ '胡适', '沈从文', '辜鸿铭' ],
writable: true, enumerable: false,configurable: true } } */
[Object.defineProperty ]()方法主要用于对象中的某个属性进行访问配置,如果需要对整个对象执行类似的操作则可使用`Object.preventExtensions()`、`Object.seal()`和`Object.freeze()` 等方法,它们分别对应着`禁止扩展`、`密封对象`以及要`冻结`对象。

Getter and Setter

对于对象字面量创建的对象而言,我们可以直接通过get attrNameset attrName的方式来对属性的设置和读取操作进行拦截和监听。通过下面的代码,我们可以观察到,对象属性的 Getter 和 Setter 的代码并不复杂但却需要借助一个无关的中间变量_age来实现。

/* getter 和 setter */
var o = {
name: "文顶顶",
_age: 17,
get age() {
console.log("监听到执行了getter方法");
return this._age;
},
set age(val) {
console.log("监听到执行了setter方法");
this._age = val;
}
}
console.log(o.age);
o.age = 100;
console.log(o.age);
/*
监听到执行了getter方法
17
监听到执行了setter方法
监听到执行了getter方法
100
*/

Object.defineProperty()方法的配置对象中也支持对象属性的 GetterSetter操作。

(function() {
var o = { name: "文顶顶", age: 17 };
var temp = 18;
Object.defineProperty(o, "age", {
get() {
console.log("——getter———");
return temp;
},
set(val) {
console.log("——setter———");
temp = val;
}
});
console.log(o.age);
o.age = 100;
console.log(o.age); /* 执行情况 */
// ——getter———
// 18
// ——setter———
// ——getter———
// 100
})();

利用`Object.defineProperty()`方法,来监听对象属性的设置和读取操作,可以不必借助于中间属性来实现而改用一个外部变量即可,这样的处理方式为代码的封装提供了可能。

注意defineProperty 方法内部使用 set 和 get 函数时不能与 value 和 writable 共存。上述的代码演示了监听对象单个属性读写的方案,如果需要为对象中所有的属性都添加 set 和 get 监听,可以考虑对上述代码进行封装。

let observer = (target) => {
if (typeof target !== "object" || target == null) return;
for (var key in target) {
if (target.hasOwnProperty(key)) defineReactive(target, key, target[key]);
}
} let defineReactive = (target, key, val) => {
observer(val); /* 递归解决多层对象解构问题 */
/* val 是外部传入的参数:就是指定属性的默认值 */
Object.defineProperty(target, key, {
get() {
handler("getter")
return val;
},
set(_val) {
handler("setter")
val = _val;
}
})
} let handler = (text) => {
console.log("监听到" + text);
} /* 测试代码 */
var o = { name: "文顶顶", age: 18, car: { color: "white" } };
observer(o);
o.age = 100;
console.log(o.age);
o.car.color = "black";
console.log(o.car.color); /* 执行情况 */
// 监听到setter
// 监听到getter
// 100
// 监听到getter
// 监听到setter
// 监听到getter
// 监听到getter
// black

前端开发系列121-进阶篇之defineProperty的更多相关文章

  1. openlayers5-webpack 入门开发系列一初探篇(附源码下载)

    前言 openlayers5-webpack 入门开发系列环境知识点了解: node 安装包下载webpack 打包管理工具需要依赖 node 环境,所以 node 安装包必须安装,上面链接是官网下载 ...

  2. leaflet-webpack 入门开发系列一初探篇(附源码下载)

    前言 leaflet-webpack 入门开发系列环境知识点了解: node 安装包下载webpack 打包管理工具需要依赖 node 环境,所以 node 安装包必须安装,上面链接是官网下载地址 w ...

  3. 【Windows10 IoT开发系列】配置篇

    原文:[Windows10 IoT开发系列]配置篇 Windows10 For IoT是Windows 10家族的一个新星,其针对不同平台拥有不同的版本.而其最重要的一个版本是运行在Raspberry ...

  4. ESP8266开发之旅 进阶篇② 闲聊Arduino IDE For ESP8266烧录配置

    授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...

  5. 【webpack 系列】进阶篇

    本文将继续引入更多的 webpack 配置,建议先阅读[webpack 系列]基础篇的内容.如果发现文中有任何错误,请在评论区指正.本文所有代码都可在 github 找到. 打包多页应用 之前我们配置 ...

  6. iOS开发系列--Swift进阶

    概述 上一篇文章<iOS开发系列--Swift语言>中对Swift的语法特点以及它和C.ObjC等其他语言的用法区别进行了介绍.当然,这只是Swift的入门基础,但是仅仅了解这些对于使用S ...

  7. 旨在脱离后端环境的前端开发套件 - IDT Server篇

    IDT,一个基于Nodejs的,旨在脱离后端环境的前端开发套件,目的就是能让前端开发完全脱离后端的环境,无论后端是什么模板引擎(主流),都能应付自如. IDT主要包括两大部分:Server + Bui ...

  8. 前端开发【第2篇:CSS】

    鸡血 样式的属性多达几千个,但别担心,按照80-20原则,常用的也就几十个,你完全可以掌握它. Css初识 HTML的诞生 早期只有HTML的时候为了让HTML更美观一点,当时页面的开发者会把颜色写到 ...

  9. [置顶]【实用 .NET Core开发系列】- 导航篇

    前言 此系列从出发点来看,是 上个系列的续篇, 上个系列因为后面工作的原因,后面几篇没有写完,后来.NET Core出来之后,注意力就转移到了.NET Core上,所以再也就没有继续下去,此是原因之一 ...

  10. openlayers4 入门开发系列之风场图篇

    前言 openlayers4 官网的 api 文档介绍地址 openlayers4 api,里面详细的介绍 openlayers4 各个类的介绍,还有就是在线例子:openlayers4 官网在线例子 ...

随机推荐

  1. 使用Python可视化洛伦兹变换

    引言 大家好!今天我们将探讨一个非常有趣且重要的物理概念-洛伦兹变换.它是相对论的核心内容之一,描述了在高速运动下,时间.长度以及其他物理量是如何发生变化的.通过使用 Python 进行可视化,我们不 ...

  2. python爬虫(BeautifulSoup)爬取B站视频字幕

    比如"https://www.bilibili.com/video/BV1zU4y1p7L3"这个视频,有1.2万条弹幕 首先,B站视频的弹幕是有专门的接口传递数据的:http:/ ...

  3. Quill自定义插入视频video实例

    import Quill from 'quill' const BlockEmbed = Quill.import('blots/block/embed') class VideoBlot exten ...

  4. 全局搜索——Lucene.Net与盘古分词的实现思路

    一.Lucene.Net 1.Lucene.Net介绍: Lucene.Net是一个C#开发的开源全文索引库(自带的有索引管理.分词.查询) Lucene.Net.Index 提供索引管理,词组排序. ...

  5. SpringBoot错误处理

    SpringBoot错误处理 1 SpringMVC写法 1.1 在单独的Controller写一个处理异常的方法处理 @Slf4j @RestController public class Hell ...

  6. 【HUST】网络攻防实践|5_二进制文件补丁技术|实验三 热补丁

    文章目录 实验要求 实验过程 1. 64位Ubuntu下先安装32位库 2. 利用Preload Hook实现热补丁修补 3. 利用系统调用`ptrace`对运行状态的程序进行hook 3.1 编写补 ...

  7. 算法:请找出数组a所有重复元素和比较数组a和数组b得到不重复的新数组和比较数组a和数组b请找出所有重复元素

    /** * 1.给定数组int[] a,int[] b * (1)请找出数组a所有重复元素,例:int[] a = {1,2,3,4,8,9,3,5,1,3},结果int[] a1 = {1,1,3, ...

  8. Node v18.6 发布的这个新特性未来可能改变前端工程化

    @charset "UTF-8"; .markdown-body { line-height: 1.75; font-weight: 400; font-size: 15px; o ...

  9. 自实现模态对话框-DoModal函数

    参考CDialog::DoModal函数的实现方式,自己实现了模态框相关功能. ModalBase.h头文件 1 #include <afxwin.h> 2 3 #define ID_NU ...

  10. K8stools工具

    简介 K8stools 是一个 Kubernetes 日常运维辅助工具集,旨在提升运维效率,辅助平台治理与资源优化.功能涵盖资源分析.趋势评估.异常检测.行为采集.成本估算等常见场景,适用于 DevO ...