彻底掌握 Object.difineProperty
文章目录
- 一、Object.defineProperty()
- 1.1 什么意思?
- 1.2 尝试一下
- 1.3 调用
- 1.4 语法
- 1.5 描述
- 二、descriptor 描述符
- 2.1 configurable 可配置的
- 2.2 enumerable 可枚举的
- 2.2 补充 如何枚举 enumerable:false 的对象属性
- 2.3 writable 可写的
- 2.4 get 获取
- 2.5 set 设置
- 2.6 异常
- 2.7 描述符默认值汇总
- 三、案例
- 3.1 自定义 set 和 get
- 3.1.1 实现一个自存档类
- 3.1.2 get总是返回相同的属性值
- 3.2 继承属性时的一些注意事项
- 四、Object.defineProperties()
一、Object.defineProperty()
Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。
更加具体的去描述或操作一个对象内部属性的操作性。
1.1 什么意思?
- defineProperty 给对象定义属性
- define 规定、定义
- Property 属性 对象的key // Attribute
1.2 尝试一下
let obj = {}let newObj = Object.defineProperty(obj, 'a', {value: 1
})console.log(newObj === obj); // true
console.log('obj: ', obj);
console.log('newObj: ', newObj);
测试结果:
由此可知,确实给对象定义了一个新属性 => a=1,且返回的就是该对象( newObj 恒等于 obj )
1.3 调用
defineProperty是Object的静态方法,不能在普通对象上直接调用(没在原型链上),
function Star(){...}Star.sex = '男' // 静态成员
Star.sing = function (){ // 静态方法...
}
1.4 语法
语法 Object.difineProperty(obj,prop,descriptor)
obj:要定义的对象
prop:要定义或修改的属性名称
descriptor:定义或修改的操作符(五个)
1.5 描述
- 该方法允许精确地添加或修改对象的属性
- 通过赋值操作添加的普通属性是可枚举的,在枚举对象属性时会被枚举到(for…in 或 Object.keys 方法)
- 默认情况下,使用 Object.defineProperty() 添加的属性值是不可修改(immutable)的。
- 这个方法允许修改默认的额外选项(或配置)
接下来我们进行测试:
let obj = {}
let newObj = Object.defineProperty(obj, 'a', {value: 1
})obj.a = 2 // 没变化,不可修改
delete obj.a // 没变化,不可删除for (let k in obj) {console.log(k, obj[k]); // 没输出,不可枚举
}
测试结构:
控制台啥也没有,由此可知 我们通过 Object.defineProperty() 添加的属性有三个特点:
- 不可修改
- 不可删除
- 不可枚举
二、descriptor 描述符
2.1 configurable 可配置的
configurable 可配置 able=>可能的,有能力的
configurable 特性表示对象的属性是否可以被删除,以及除 value 和 writable 特性外的其他特性是否可以被修改。
configurable :默认为 false。
let obj = {}
let newObj = Object.defineProperty(obj, 'a', {value: 1,configurable: true,
})
delete obj.a
console.log(obj); // {}
通过上述测试可知,当configurable为true时,我们就可以删除该属性了。
2.2 enumerable 可枚举的
enumerable默认为false
let obj = {}
let newObj = Object.defineProperty(obj, 'a', {value: 1,enumerable: true, // 可枚举的 Default:false
})
for (let k in obj) {console.log(k);
}
通过上述测试可知,当enumerable为true,可枚举该属性
2.2 补充 如何枚举 enumerable:false 的对象属性
需求:枚举对象obj的所有属性
let obj = {}
Object.defineProperty(obj, 'a', {value: 1,enumerable: false
})
Object.defineProperty(obj, 'b', {value: 2,enumerable: false
})
普通方法:
for (let k in obj) {console.log(k); // 空
}
进阶方法:
let keys = Object.getOwnPropertyNames(obj)
console.log(keys); // ["a", "b"]
Object.getOwnPropertyNames() 方法返回一个由指定对象的所有自身属性的属性名(包括不可枚举属性但不包括Symbol值作为名称的属性)组成的数组。
注意:拿不到继承而来的属性,而 for…in 可以拿到继承的属性
更多示例:
var arr = ["a", "b", "c"];
console.log(Object.getOwnPropertyNames(arr).sort());
// // ["0", "1", "2", "length"]
2.3 writable 可写的
writable默认为false.
let obj = {}
let newObj = Object.defineProperty(obj, 'a', {value: 1,writable:true,// 可写的 Default:false
})
obj.a = 2
console.log(obj);
通过上述测试可知,当writable为true时,可修改该属性。
其他测试:
2.4 get 获取
- 当访问该属性时,会调用此函数。
- 该函数的返回值会被用作属性的值。
let obj = {}
Object.defineProperty(obj, 'a', {// value: 1get() {console.log('get a:', 1);return 1},
})console.log(obj.a);
通过上述测试可知,当我们定义了get()方法后,每次访问该属性都会先调用该方法,且该方法的返回值就是属性的值。
2.5 set 设置
let obj = {}
Object.defineProperty(obj, 'a', {// value: 1set(newValue){console.log('set a:',newValue);}
})
obj.a = 2
通过上述测试可知,当我们每次设置或修改该属性时,都会先调用set方法,且该方法有一个参数(也就是被赋予的新值)
2.6 异常
如果一个描述符同时拥有 value
或 writable
和 get
或 set
键,则会产生一个异常。
value || writable
<= 不能与之共处 => get || set
以下为 错误 示例:会抛出一个异常
//以下为错误示例
let obj = {}
let newObj = Object.defineProperty(obj, 'a', {value: 1,get() {...}
})
newObj = Object.defineProperty(obj, 'a', {value: 1,set() {...}
})
newObj = Object.defineProperty(obj, 'a', {writable: true, //这里true 和 false 都会抛出异常get() {...}
})
newObj = Object.defineProperty(obj, 'a', {writable: true,//这里true 和 false 都会抛出异常set() {...}
})
以上情况都会出现下面的异常。
2.7 描述符默认值汇总
拥有布尔值的键 configurable、enumerable 和 writable 的默认值都是 false。
属性值和函数的键 value、get 和 set 字段的默认值为 undefined。
三、案例
3.1 自定义 set 和 get
3.1.1 实现一个自存档类
function Archiver() {let archive = []let item = nullObject.defineProperty(this, 'item', {set(newValue) {item = newValuearchive.push({ item: newValue })},get() {console.log('get!');return item}})this.getArchiver = () => archive
}let person = new Archiver()person.item = 'pengsir'
person.item = '彭先生'
console.log(person.item);
console.log(person.getArchiver());
测试结果:
3.1.2 get总是返回相同的属性值
let pattern = {get() {return '我默认是18岁!'},set() {this.age = 18}
}
function TestDefineSetAndGet() {Object.defineProperty(this, 'uname', pattern)
}
let obj = new TestDefineSetAndGet()
obj.uname = '彭先生'
console.log(obj);
测试结果:
3.2 继承属性时的一些注意事项
如果访问者的属性是被继承的,它的 get 和 set 方法会在子对象的属性被访问或者修改时被调用。如果这些方法用一个变量存值,该值会被所有对象共享。
function Star() { }
let attribute = null
Object.defineProperty(Star.prototype, 'x', {set(newValue) {attribute = newValueconsole.log('set!:', newValue);},get() {console.log('get!');return attribute}
})let ldh = new Star()
let zxy = new Star()ldh.x = 1
console.log(ldh.x);
console.log(zxy.x);
测试结果:
如何让继承属性的同时,值不是共享的呢?
这可以通过将值存储在另一个属性中解决。在 get 和 set 方法中,this 指向某个被访问和修改属性的对象。
function Star() { }
let attribute = null// 属性值共享:
// Object.defineProperty(Star.prototype, 'x', {// set(newValue) {// attribute = newValue
// console.log('set!:', newValue);
// },
// get() {// console.log('get!');
// return attribute
// }
// })// 属性值不共享:
Object.defineProperty(Star.prototype, 'x', {set(newValue) {this.attribute = newValueconsole.log('set!:', newValue);},get() {console.log('get!');return this.attribute}
})let ldh = new Star()
let zxy = new Star()ldh.x = 1
console.log(ldh.x);
console.log(zxy.x);
测试结果:
继承的值是不可写的(writable) ,那么子对象的值是否可写呢?
//'use strict';function Star() { }
Star.prototype.x = 1
Object.defineProperty(Star.prototype, 'y', {writable: false,value: 2
})let instance = new Star()instance.x = 111
console.log(instance.x); // 111
console.log(Star.prototype.x); // 1instance.y = 222console.log(instance.y); // 2 => 在严格模式下会报错
// Uncaught TypeError: Cannot assign to read only property 'y' of object '#<Star>console.log(Star.prototype.y); // 2
四、Object.defineProperties()
参数都相同,只是可以同时定义多个属性。
Object.defineProperties(obj, {name: {configurable: true,enumerable: true,writable: true,value: "why",},age: {configurable: false,enumerable: false,get() {return this._age;},set(value) {this._age = value;},},
});
彻底掌握 Object.difineProperty相关推荐
- 做diff_Vue3.0时代你必须了解的:diff算法原理和优化
关注前端公众号 [前端每日一博] 前言 面试官: 你知道 Vue3.0 Object.difineProperty和vue3.0的proxy的区别吗? 你知道 Vue3.0 diff算法原理和它有什么 ...
- 在kotlin companion object中读取Bean,注入Bean对象
在kotlin companion object中读取Bean,注入Bean对象 在使用kotlin时,或多或少地会使用到一些公共组件,如 http. mongo. redis相关的组件. 使用组 ...
- 在kotlin companion object中读取spring boot配置文件,静态类使用@Value注解配置
在kotlin companion object中读取配置文件 静态类使用@Value注解配置 class Config {@Value("\${name}")fun setNam ...
- Object的finalize()方法的作用是否与C++的析构函数作用相同
Object的finalize()方法的作用是否与C++的析构函数作用相同 public class Finalization {private static Finalization finaliz ...
- libgstreamer-1.0.so.0: cannot open shared object file: No such file or directory
1. 问题现象 error while loading shared libraries: libgstreamer-1.0.so.0: cannot open shared object file: ...
- RuntimeError: Expected object of backend CUDA but got backend CPU for argument
RuntimeError: Expected object of backend CUDA but got backend CPU for argument #4 'mat1' 原因:变量没有加cud ...
- RuntimeError: Expected object of device type cuda but got device type cpu for argument pytorch数据位置
RuntimeError: Expected object of device type cuda but got device type cpu for argument #2 'target' i ...
- Python错误:AttributeError: 'generator' object has no attribute 'next'解决办法
今天在学习生成器对象(generation object)运行以下代码时,遇到了一个错误: #定义生成器函数 def liebiao(): for x in range(10): yield x #函 ...
- Java OOP(Object Oriented Programming)个人理解及总结
面向对象编程(Object Oriented Programming,OOP,面向对象程序设计) 其三大特征:封装,继承,多态: 封装:解决数据的安全问题. 继承:解决代码的重用问题. 多态:解决程序 ...
最新文章
- Python使用matplotlib函数subplot可视化多个不同颜色的折线图、自定义数据点的形状、自定义折线图的颜色
- 香港科技大学谢知遥教授实验组招收机器学习全奖博士生
- Mysql-cobar集群安装部署手册
- django构建网页_通过解决问题的方式学习django,律师如何构建副业
- mysql:Failed to read auto-increment value from storage engine
- HTML 取消超链接下划线
- 浏览器指纹实现方案:Cookie、Flash Cookies、帆布指纹识别
- 利用 dbghelp.dll 生成 dump 文件
- mybatis3 配置文件解析
- Python爬虫解析网页的4种方式 值得收藏
- 美国红帽软件公司是做什么的
- 苹果电脑装系统出现未能与服务器取得联系,Mac您的磁盘未能分区 Mac磁盘分区出错解决办法...
- 怎么用dos命令打开计算机,如何使用DOS命令打开C盘下的文件夹dos如何打开文件夹...
- 山东科技大学计算机学院陈卓艳,转发教务部表彰大学生学习竞赛获奖单位和个人通知...
- 安装Centos8设置基础软件仓库时出错
- MAE源代码理解 part2 : 预训练调试
- jcp jsr_JCP成为“可怕的单一文化”
- poi导入excel日期处理_POI处理Excel中各种日期格式问题
- 有衬线字体 无衬线字体_字体101:衬线与无衬线
- VM虚拟机下载与安装