JavaScript 中的众生平等,万物皆对象:字符串、数值、数组、函数...
另外,
JavaScript 允许自定义对象。
对象的本质可以理解为属性的集合,对象的属性包括:
命名属性
: 可直接通过“.”访问到的属性
数据属性
: 专门保存一个值的属性
访问器属性
: 保护数据属性的特殊属性
内部属性
: 不能通过“.”直接访问的属性 (比如 : class __proto__)
下面重点分析一波,
数据属性
和
访问器属性
1.数据属性: 专门存储数据的属性
数据属性的四大特性:
{
value : 值,
writable : true/false, (默认true)
enumerable : true/false,(默认true)
configurable : true/false (默认true)
}
- writable —— 是否为可写,改为false,当前属性变为只读。
- enumerable —— 是否为可枚举,改为false,for in时不会被遍历,但使用 "."依然可访问。
- configurable —— 是否为可配置的,改为false之后,不能删除修改(不可逆)
/*****************************************/
"use strict";
var bob={id:101,name:"Bob",salary:1000};
//访问对象bob的id属性
console.log(Object.getOwnPropertyDescriptor(bob,"id"));
//修改bob对象id属性为只读,不可枚举,不可配置
Object.defineProperty(bob,"id",{
writable:false,
configurable:false,
enumerable:false
})
Object.defineProperty( bob, "id", {
configurable : true,
//报错
} );
for( var i in bob){
console.log( i + '--' + bob[i] );
// name--Bob salary--1000
}
/*****************************************/
writable为false的时候,如果对这个属性name进行重新赋值(修改)在非严格模式下,赋值会被忽略,在严格模式下会报错.
configurable为false的时候,如果删除name属性,在非严格模式下,删除操作会被忽略,在严格模式下会报错,而且如果对一个设置了configurable为false的属性,想把它重新改为true,会报错。
enumerable的值为false,那么这个属性是不能被for...in遍历(循环/枚举)
1) Object.getOwnPropertyDescriptor()
Object.getOwnPropertyDescriptor(obj,"属性名");
可以得到给定属性的特性, 返回值为一个对象。
2) Object.defineProperty()
Object.defineProperty(obj , 属性名 , { 特性 })
注意: 如果obj中包含指定属性,则修改现有属性的值,如果obj中不包含指定属性,则在obj中自动添加新属性
特性的默认值:
1. 属性在创建对象时就定义好了,所有特性的默认值都为true
2. 而当使用defineProperty添加的属性,特性的默认值都为false。
没有使用Object.defineProperty定义对象:
var obj1= {
name : 'ajun',
age : 18,
};
var ajun1= Object.getOwnPropertyDescriptor( obj1, "name" );
console.log( ajun1.configurable ); //true
console.log( ajun1.enumerable ); //true
console.log( ajun1.writable ); //true
console.log( ajun1.value ); //ajun
使用Object.defineProperty定义的对象:
var obj2 = { }
Object.defineProperty( obj2 , "name", {
value : 'ajun'
});
var ajun2= Object.getOwnPropertyDescriptor( obj2 , "name" );
console.log( ajun2.configurable ); //false
console.log( ajun2.enumerable ); //false
console.log( ajun2.writable ); //false
console.log( ajun2.value ); //ajun
所以,在使用defineProperty添加属性时,必须显式定义属性的特性为true,否则默认为false。
2.访问器属性: 专门保护数据属性的特殊属性,不实际存储数据
getter/setter访问器:
1.get方法负责读取变量的值
2. set方法负责修改变量的值
注意:当使用了getter或setter方法,不允许使用writable和value这两个属性?
何时调用get/set:
试图通过访问器属性取值时,自动调用get特性的函数
试图通过访问器属性设置值时,自动调用set特性的函数
一般在set中设置对要设置的新值得验证
特殊: 如果省略set特性,则该属性为只读
四大特性:{
get : function(){return 局部变量},
set : function(value){局部变量=value},
enumerable : 同数据属性 ,
configurable : 同数据属性
}
注意: 使用访问器属性,必须有一个受保护的局部变量都要通过闭包来添加访问器属性:
单独添加访问器属性:
(function(){
var 局部变量 = 值 ;
Object.defineProperty(obj,"属性名",{
get : function(){return 局部变量},
set : function(value){局部变量=value},
enumerable : true,
configurable : true
})
})();
在构造函数中添加访问器属性:
function(属性参数){
this.公有属性=参数,
...
Object.defineProperty(obj,"属性名",{
get:function(){return 属性参数},
set:function(value){属性参数=value},
enumerable:true,
configurable:true
})
}
定义命名属性:
1. 只定义一个命名属性:
Object.defineProperty(obj,"属性名",{
四大特性
})
2. 同时定义多个属性:
Object.defineProperties(obj,{
属性名1 : {
四大特性
},
... : {...}
})
如果指定名称的属性存在,则修改现有属性
如果指定名称的属性不存在,则自动创建同名属性
重要的事再说一遍,非defineProperty定义的属性,四大特性默认值都是true。defineProperty添加的属性,四大特性默认值都是false。
实际用处
何时修改四大特性: 只要保护属性,就用四大特性控制
何时使用数据属性: 只想控制只读,遍历或删除
何时使用访问器属性: 希望用自定义逻辑保护变量