javascript的属性描述符
什么是属性描述对象(attributes object)?
顾名思义,就是用来描述对象属性的对象.javascript内部提供了一个数据结构,用来描述对象的属性以及控制属性的行为.
比如该对象的某属性是否可写,可遍历等
属性描述符的6个元属性
- value 该属性的值,默认是undefined
- configurable 表示可配置,默认为true;如果改为false,则无法删除该属性并且无法改变该属性的属性描述符对象(除了value值)
- writable 表示该属性值是否可改变,默认为true;如果改为false,则属性值不能改变
- enumerable 该属性是否可遍历,如果设置为false,则object.keys和for...in 无法遍历到该属性
- get 获取该属性值是会被调用
- set 设置该属性值是会被调用
获取属性描述对象
Object.getOwnPropertyDescriptor(对象obj,指定属性);
两个参数,第一个参数是对象,第二个参数是想要获取属性描述符的属性(类型是字符串)
默认情况下,configurable,enumerable,writable都是true
通过Object.defineProperty(对象,属性,{});这样添加的属性,此属性的属性描述符configurable,enumable,writable默认都为false
let obj = {
a:1,
b:2
}
console.dir(Ojbect.getOwnPropertyDescriptor(obj, 'a'));
// 输出
// {configurable: true,
// enumerable: true,
// value: 1,
// writable: true}
Object.defineProperty(obj,'c',{});
console.dir(Object.defineOwnPropertyDescriptor(obj,'c'));
// 输出
// {configurable: false,
// enumerable: false,
// value: undefined,
// writable: false}
注意: Object.getOwnPropertyDescriptor(obj, 属性); 只能用在对象自身的属性,不能用于继承过来的属性
获取对象自身的属性名
- Object.keys(obj)
- Object.getOwnPropertyNames(obj)
区别,Object.keys(obj)返回对象自身可枚举的属性;Object.getOwnPropertyNames(obj)会返回对象自身的全部属性,不管是否可遍历
// 声明定义对象
let obj = {
a: 1,
b: 2
}
// 给对象obj添加一个属性c,并且属性c不可枚举(不可遍历)
Object.defineProperty(obj, 'c', {
enumerable: false
});
// 输出对象obj所有键
console.log(Object.keys(obj));
console.log(Object.getOwnPropertyNames(obj));
// 可以看出Object.keys()可以吧对象自身的所有不可枚举的属性打印出来
// Object.getOwnPropertyNames()可以吧对象自身的所有属性都可以打印出来
定义属性描述对象
可以使用Object.defineProperty(obj, propertyName, attrObject);来定义一个属性描述对象
用法,三个参数:
- obj 要定义的对象
- propertyName 属性名(如果对象上没有此属性则新加此属性,如果对象上有此属性则更新此属性的属性描述对象)
- attrObject 定义的对象上的属性描述符对象
如果一次性修改或定义多个属性的属性描述符对象,则可以使用Object.defineProperties(obj, { key1: key1AttrbuteObject, ... });
注意: 如果属性描述符定义了存取器(get,set),就不能再设置writable,或者value,否则会报错
let obj = {
a: 1
}
Object.defineProperty(obj, 'a', {
// 情况一
// writable: false,
// 情况二
// wirtable: true,
// 情况三
value: 123,
get: function(){
console.log('get方法');
}
});
// 以上情况都会报错
// Uncaught TypeError: Invalid property descriptor. Cannot both specify accessors and a value or writable attribute, #<Object>
判断某个属性是否可以枚举(可遍历)
使用propertyIsEnumerable(属性名)可以判断该属性是否可以枚举,propertyIsEnumerable(属性名)是定义在实例对象上的,也就是Object.prototype.propertyIsEnumerabl(),只要是Object的实例都可以访问
propertyIsEnumerable()只能判断自身的属性,如果判断的是继承过来的属性或者自身不存在的属性,则直接返回false
let obj = {
b: 2
}
Object.defineProperty(obj, 'a', {
enumerable:false
});
// 自身可枚举的属性 true
console.log(obj.propertyIsEnumerable('b'));
// 自身不可枚举的属性 false
console.log(obj.propertyIsEnumerable('a'));
// 继承过来的属性 false
console.log(obj.propertyIsEnumerable('toString'));
// 自身不存在的属性 false
console.log(obj.propertyIsEnumerable('c'));
属性描述符的元属性
writable
决定该属性是否可以改变值,false不可以改变;true可以改变(不能与get/set同时存在)
如果writable为false,再改变值的话还是之前的值;如果是严格模式会报错enumerable
决定该属性是否可以枚举
enumerable为false时,以下三个不会取到该属性- for...in...
- Object.keys()
- JSON.stringify()
let obj = {
a: 1,
}
Object.defineProperty(obj, 'a', {
value: 123,
enumerable: false
});
// 123
console.log(obj.a);
// []
console.log(Object.keys(obj));
// {}
console.log(JSON.stringify(obj));
value
读取或者改写属性的值let obj = {
a: 1
}
// 读取值
console.log(Object.getOwnPropertyDescriptor(obj,'a').value);
// 改写值
Object.defineProperty(obj, 'a', {vaue: 123});
configurable
configurable决定了属性的可配置性,当configurable为false时,value\enumerable\writable\configurable都不可以修改配置,并且不能使用delete删除该属性get
set
也可以称为存取器
两种写法:
一,Object.defineProperty(obj,'a',{get: function(){ }})
二,var obj = {get p(){},set p(val)var obj = Object.defineProperty({}, 'a', {
get: function(){
return 'getter';
},
set: function(){
console.log('a的set方法');
}
}); var obj1 = {
get a(){
return 'getter'
},
set a(){
console.log('a的set方法');
}
}
对象的拷贝
浅拷贝
- 直接赋值引用
问题是改变一个对象的属性值会影响到另一个let obj = {a:1}
let objC = obj;
objC.a = 2;
// 因为obj和objC指向同一个内存地址,所以改变objC必然会影响到obj
- 将对象的每个属性及属性值赋给拷贝对象
问题是如果被拷贝的对象的某一属性值是对象的话,拷贝的还是引用,还是会相互影响的// 被拷贝的对象
let obj = {a:1, b: { c:2 }}
let objC = {}
for(let key in obj){
if(!obj.hasOwnProperty(key))continue;
objC[key] = obj[key]
}
objC.b.c = 3;
// 因为objC和obj的属性b都指向同一个地址,所以会相互影响
以上的方式不能够拷贝属性的存取器
let obj = {get a(){return 1},get b(){return 2}}
let objC = {}
for(let key in obj){
// 因为Object.getOwnPropertyDescriptor()只能获取自身的,获取不到继承的属性,会报错
if(!obj.hasOwnProperty(key))continue;
Object.defineProperty(objC, key, Object.getOwnPropertyDescriptor(obj, key));
}
深拷贝
function extend(to,from){
for(let fr in from){
if(!from.hasOwnProperty(fr))continue;
if(typeof from[fr] === 'object'){
if(Object.prototype.toString.call(from[fr]) === '[object Object]'){
to[fr] = {};
extend(to[fr], from[fr]);
// console.log(Object.prototype.toString.call(from[fr]));
}else if(Object.prototype.toString.call(from[fr]) === '[object Array]'){
to[fr] = [];
for(let i=0;i<from[fr].length;i++){
to[fr][i] = from[fr][i]
}
}
}else{
to[fr] = from[fr];
}
}
return objC;
}
控制对象的状态
冻结对象的读写状态,防止对象被改变
- Object.preventExtension(obj);
// 阻止对象添加属性
// 判断对象是否可以被扩展
Object.isExtensible(obj) - Object.seal(obj)
// 阻止对象添加属性和删除旧属性
// 判断是否使用了seal方法
Object.isSealed(obj)
使用了Object.seal(obj)之后,Object.isExtensible(obj)也变为false - Object.freeze(obj)
// 使得对象扩展属性,删除属性,并且值也不能改变,变成了常量
// 判断对象是否用了freeze方法
Object.isFrozen(obj)
使用了Object.freeze(obj)之后,Object.isSealed(obj)返回true,Object.isExtensible(obj)返回false
最新文章
- EnTaroTassadar
- PNG使用技巧 PNG的使用技巧
- Jpinyin笔记
- Linux下使用fdisk扩展分区容量
- 《.NET简单企业应用》项目开发环境
- QMetaObject感觉跟Delphi的类之类有一拼,好好学一下
- 中文版kendoUI API — Grid(一)
- VLC命令行的应用
- 跟我一起学extjs5(25--模块Form的自己定义的设计[3])
- shell oracle
- 写给Android App开发人员看的Android底层知识(2)
- D3.js从入门到“放弃”指南
- Android 增量更新和升级
- 最详细的JavaWeb开发基础之java环境搭建(Windows版)
- 关于RecyclerView嵌套导致item复用异常,界面异常的问题
- 商誉专题RN及H5项目总结
- java中读取资源文件的方法
- CAN自收自发问题小结
- vMware 按装 MacOs
- 内存管理-slab[原理]
热门文章
- JS逆向之浏览器补环境详解
- angular在服务中调用组件的某个方法,并传参给组件,(反向调用),变量改变后,强制更新视图
- RealWorld CTF 5th ShellFind 分析
- maven依赖管理,生命周期,插件
- SQL优化的一些方法
- 带你读AI论文丨S&;P21 Survivalism: Living-Off-The-Land 经典离地攻击
- vue学习笔记(一) ----- vue指令(菜单列表案例)
- SQLSERVER 的 truncate 和 delete 有区别吗?
- Django框架之drf:9、接口文档,coreapi的使用,JWT原理、介绍、快速使用、定制、认证
- C-08\变量类别和名称粉碎机制