谈谈JS中的Object.defineProperty()

谈谈JS中的Object.defineProperty()

今天和大家来聊一聊Object.defineProperty这个方法,学过vue的人都知道,vue的劫持原理就是通过该方法进行数据拦截的,如果想要深入了解vue的原理,Object.defineProperty是避免不了的。

首先来介绍一下语法

定义

Object.defineProperty的作用是在一个对象上定义一个新属性,或对已有属性进行修改。

用法

/**
 * @param {Object} target 需要定义/修改属性的目标对象
 * @param {String} propName  需要定义/修改的属性名称
 * @param {Object} descriptor 需要定义/修改的属性描述符
 */
Object.defineProperty(target, propName, descriptor);

target和name我就不多解释了,详细的来解释一下desc。

描述符

Object.defineProperty()的描述符分为两大类: 第一类叫数据描述符,专门用来对数据进行限制说明的,比如是否可修改,是否可枚举(遍历),是否可删除/修改等。 第二类叫存储器描述符(访问器描述符),用于对数据的获取和修改进行说明的,比如当我这个数据调用时我需要返回什么样的数据,该数据修改时需要按照什么样的逻辑修改等。 数据描述符有4个,分别是value,writable,enumerable,configurable。 操作描述符有2个,分别是get和set。

value

value是需要定义/修改的属性的值,或者说我更喜欢将其叫做默认值。

Object.defineProperty(window, "name", {
    value: '张三'
});
console.log(window.name); // '张三'

比如我需要在全局属性window对象下定义一个名字叫做name的属性,我可以用上述代码,这段代码等价于var name = '张三';但又有一点区别,不要急,我接着讲,大家接着看,我等会告诉大家区别在哪。

writable

writable决定着该属性是否可以被重新赋值,用Object.defineProperty()定义时默认为false,用var name = '张三'表达式定义时默认为true。

Object.defineProperty(window, "name", {
    value: '张三'
});
window.name = '李四';
console.log(window.name); // 张三

Object.defineProperty(window, "age", {
    value: 15,
    writable: true
});
window.age = 20;
console.log(window.age); // 20

参考上边两个栗子,我们可以看到,默认情况下该属性不可修改,当将writable设置为true时,该属性输出了我们新输入的值。

var name = '张三';
name = '李四';
console.log(name); // 李四

我们可以联想到,平时定义一个变量时是可以随时修改的,那么我们可以大胆猜想,表达式定义的属性默认的writable是true,这也是上面遗留问题的区别之一。验证一下。

Object.defineProperty(window, "name", {
    value: '张三'
});
var age = 12;
console.log(Object.getOwnPropertyDescriptor(window, 'name')); // {value: "张三", writable: false, enumerable: true, configurable: true}
console.log(Object.getOwnPropertyDescriptor(window, 'age')); // {value: 12, writable: true, enumerable: true, configurable: false}

用Object.getOwnPropertyDescriptor()可以查看描述符的具体值,这个语法下面我会详细介绍,现在不用太纠结,只要知道该方法可以获取该值描述符的具体值就行。 我们可以看到,用var定义的属性的writable确实是true,而用Object.defineProperty定义的是false。这里我们是不是可以联想到常量,常量的定义是不是也可以通过该描述符进行定义呢?这个留给大家思考,这里不详细介绍了。

enumerable

enumerable决定该属性的值是否可以被枚举,也就是我们所说的遍历,true为可以被枚举,false为不可以,在Object.defineProperty()中定义的属性默认false,表达式格式定义的默认为true。

var obj = {a: 1, b: 2}
Object.defineProperty(obj, 'c', {
  value: 3,
  enumerable:false
});
console.log(obj); // {a: 1, b: 2, c: 3}
for (let key in obj) {console.log(key)}; // a, b
console.log(Object.keys(obj)); // ['a', 'b']

我们看到,当我们将enumerable设置为false时,无论用for...in还是Object.keys(),都无法获取到c属性,当我们将enumerable设置为true时可以获取到,这里就不验证了,大家自行验证。

configurable

configurable决定着目标属性是否可以被删除或者已经设置的描述符是否可以修改,默认为false。

var a = 100;
delete a;
console.log(a); // 100

var obj = {};
Object.defineProperty(obj, 'a', {
  value: 100
});
delete obj.a;
console.log(obj.a); // 100

get

get是用于获取该属性值的方法。

var obj = {};
Object.defineProperty(obj, 'a', {
  get () {
    return 100;
  }
});
console.log(obj.a); // 100

注意,get不能和configurable共存,否则会报错。

set

set是用于修改该属性值的方法。

var obj = {};
var value = 100;
Object.defineProperty(obj, 'a', {
  get () {
    return value;
  },
  set (val) {
    value = val;
  }
});
console.log(obj.a); // 100
obj.a = 99;
console.log(obj.a); // 99

注意,set和get一样,不能和configurable共存,否则会报错。

总结

1、value:需要定义/修改的属性的默认值

2、writable:决定着值是否可以被修改

3、enumerable:决定着值是否可以被枚举

4、configurable:决定着值是否可以被删除或其他描述符是否可以修改

5、get:用于获取该属性的值,不能和configurable共存

6、set:用于设置该属性的值,不能和configurable共存

原文链接:juejin.im

上一篇:给 Vuepress 添加暗色夜间模式
下一篇:大前端有必要知道的网络知识

相关推荐

  • 🙋Hanjst汉吉斯特改进+enSafeExpression安全表达式等

    Hanjst汉吉斯特模版语言及模版引擎,近期持续改进升级。 这次改进主要是增加了对安全输出表达式兼容,由于涉及到对软件开发过程中的效率和软件运行效率的平衡和取舍,所以多写了几句,以描述这个权衡利弊对...

    14 天前
  • 🙋Hanjst汉吉斯特升级:+showImageAsync及性能改进等

    自2019年元旦🙋Hanjst汉吉斯特 模板语言及其编译引擎发布,已经过去一年多了。 这期间随着 🙋Hanjst汉吉斯特 的推广应用,我们也陆续发布了如下一些更新内容: 🛠️Hanjst/汉吉...

    2 个月前
  • 😉我用 Nuxt.js 仿了个掘金

    前言 首先肯定是要夸夸掘金啦,最开始从 CSDN 到 博客园 再到 掘金,个人感觉掘金的技术氛围非常的nice,真是个宝藏社区👏。技术文章大多以前端为主,对前端开发者非常友好,质量也是歪瑞古的。

    25 天前
  • 😀一个原生js弹幕库

    danmujs 😀一个原生js弹幕库,基于 CSS3 Animation 地址、核心代码 本项目基于 rcbullets,项目约70%的代码基于rcbullets,首先要感谢这个项目的作者,如...

    4 个月前
  • 🕵️‍♀️由原型到JS中的“模拟类”

    讲述了有关 JavaScript 中原型相关知识,又引出了 JavaScript 中的“类“究竟是什么?,以及一系列相关问题。 一、前置知识 1、JavaScript 的面向对象(OOP) ​ 面向...

    2 个月前
  • 🔥《吊打面试官》系列 Node.js 必知必会必问!

    (/public/upload/f204a3b224d986128f1b4d9b8d06cd17) 前言 codeing 应当是一生的事业,而不仅仅是 30 岁的青春🍚 本文已收录 Git...

    3 个月前
  • 💖CSS + JS 送学妹满屏幕小爱心

    故事开始 午饭时间,暗恋已久的学妹拉着我的衣袖:“学长学长,你能不能让这些爱心变成五颜六色的吗~”。 我在旁边笑开了花~~~ image.png(/public/upload/04aaa24e...

    1 个月前
  • (vuejs学习)2、使用ElementUI(*)

    1.element安装 开发环境是win10,一到node官网下载node的.msi包(https://npm.taobao.org/mirrors/node/v10.16.0/nodev10.16....

    10 个月前
  • (vuejs学习)1、Vue初上手(*)

    参考《官方(https://cli.vuejs.org/zh/guide/installation.html)》官方: Node 版本要求: Vue CLI 需要 Node.js 8.9 或更高...

    10 个月前
  • 黄金搭档 -- JS 装饰器(Decorator)与Node.js路由

    很多面对象语言中都有装饰器(Decorator)函数的概念,Javascript语言的ES7标准中也提及了Decorator,个人认为装饰器是和一样让人兴奋的的变化。

    1 年前

官方社区

扫码加入 JavaScript 社区