一、描述符分类:
属性描述符:修饰属性的属性 ,元属性,是属性的特征;
数据描述符:具有writable value属性描述符的属性;
访问描述符:具有set和get的属性。
set&get:set中value必须写;成对出现;
<script type="text/javascript">
/*
属性描述符:修饰属性的属性 元属性 属性的特征
数据描述符:具有writable 和 value属性描述符的属性
访问描述符:具有set和get属性描述符的属性
*/
var obj ={}
Object.defineProperty(obj,"age",{
/*value:30,
writable:true,*/
get:function(){
return this.__age__;
},
set:function(val){
this.__age__ = val;
}
})
</script>
二、属性描述符
1、元属性
属性的属性 称为元属性
2、定义属性:defineProperty
<!--定义属性:defineProperty-->
<script type="text/javascript">
var obj={
name:"snw"
};
Object.defineProperty(obj,"age",{
value:18,
writable:true,
configurable:true,
enumerable:true
});
console.log(obj); //Object {name: "snw", age: 18}
console.log(obj.age);//18
Object.defineProperty(obj,"sex",{
value:"man"
})
var result =Object.getOwnPropertyDescriptor(obj,"sex");
console.log(result);//默认值都是false
</script>
3、获取属性描述符:getOwnPropertyDescriptor
<!--获取属性:getOwnPropertyDescriptor-->
<script type="text/javascript">
var a="a";
var a;
b="b";
console.log(Object.getOwnPropertyDescriptor(window,"a"));
console.log(Object.getOwnPropertyDescriptor(window,"b"));
delete a;
delete b;
console.log(a);
console.log(b);
</script>
4、属性描述符定义
属性描述符:修饰属性的属性 ,元属性,是属性的特征。属性描述符共有以下五类:
1)writable&value :控制属性的可读写权限
<script type="text/javascript">
// writable决定了属性值的读写权限
var zd={};
Object.defineProperty(zd,"wife",{
value:"zdy",
writable:true
})
//静默失败
zd.wife="18岁的zdy";
console.log(zd);
</script>
2)enumerable :决定属性可枚举权限
可枚举:能否出现对象的for in循环中
<script type="text/javascript">
// enumerable决定了属性能否出现在对象的for in循环中
var zd={};
Object.defineProperty(zd,"wife",{
value:"18岁zdy",
writable:true
})
Object.defineProperty(zd,"wife1",{
value:"19岁zdy",
writable:true
})
Object.defineProperty(zd,"wife2",{
value:"20岁zdy",
writable:true,
enumerable:true
})
Object.defineProperty(zd,"wife3",{
value:"21岁zdy",
writable:true
})
Object.defineProperty(zd,"wife4",{
value:"22岁zdy",
writable:true,
enumerable:true
})
Object.prototype.fromObjectP ="test";
for(item in zd){
console.log(item);
}
console.log(Object.getOwnPropertyDescriptor(zd.__proto__,"toString"))
</script>
3)configurable :决定属性可配置权限
可配置:能否重新定义和能否删除(delete)
<script type="text/javascript">
/* configurable决定了属性的可配置权限
1.属性可否重新定义
2.属性是否可删除
注意:configurable为false时
value只受writable的控制
writable可以从true变为false
其他的改动一律不允许
*/
var zd={};
Object.defineProperty(zd,"wife",{
value:"19岁zdy",
writable:true,
enumerable:true
})
Object.defineProperty(zd,"wife",{
value:"19岁zdy",
writable:false,
enumerable:false
})
console.log(zd);
</script>
4)getter&setter
对属性进行操作时,我们可以绑上自己的业务逻辑
get:
对属性进行获取调用get方法
set:
对属性进行设置时调用set方法
注意: get&set与value&writable不能同时出现;
5、注意事项
- value只受writable控制;writable值可以从true到flase
- 操作符(in)可以上原型链。
- JS中方法是浅不变形的!不会遍历原型链,只影响读写直接属性值。
6、属性存在性
1)存在性检查
方法 : obj.hasOwnProperty("toString")
<script type="text/javascript">
var obj={
age:18
}
console.log(obj.age)
console.log("age" in obj)
console.log(obj.hasOwnProperty("age"))
</script>
2) 应用:解决for in 中能够获取原型链中属性(只获取直接属性)。
<!--for in
问题:循环遍历时会获取所有属性包括原型链中属性,但是通常只获取直接属性
解决:使用hasOwnProperty过滤掉 原型链中属性-->
<script type="text/javascript">
// enumerable决定了属性能否出现在对象的for in循环中
var zd={
son:{
name:"xfz"
}
};
Object.defineProperty(zd,"wife",{
value:"18岁周",
writable:true
})
Object.defineProperty(zd,"wife1",{
value:"19岁周",
writable:true
})
Object.defineProperty(zd,"wife2",{
value:"20岁周",
writable:true,
enumerable:true
})
Object.defineProperty(zd,"wife3",{
value:"21岁周",
writable:true
})
Object.defineProperty(zd,"wife4",{
value:"22岁周",
writable:true,
enumerable:true
})
Object.defineProperty(Object.prototype,"demo",{
value:"demo",
writable:true,
enumerable:true
})
for(item in zd){
if(zd.hasOwnProperty(item)){
console.log(item);
}
}
</script>
三、对象不变性
1、基本介绍
常量属性:默认属性为false。将属性的writable和configurable设置为false。
禁止对象扩展:Object.preventExtensions(obj)
**
密封对象:Object.seal(obj)
冻结对象:Object.freeze(obj)
深度冻结
2、代码示例:
01_常量属性.html
<script type="text/javascript">
var math ={};
Object.defineProperty(math,"PI",{
value:3.141592654,
enumerable:true
})
</script>
02_禁止对象的扩展.html
<script type="text/javascript">
//对象不变性的第一个级别:禁止对象的扩展
var obj ={
age:18,
name:"达姆",
wife:{
name:"周冬雨",
age:18
}
};
Object.defineProperty(obj,"PI",{
value:3.141592654,
enumerable:true
})
Object.preventExtensions(obj)
obj.age=19;
delete obj.wife.age;
delete obj.name;
console.log(obj)
</script>
03_密封对象.html
<script type="text/javascript">
var obj ={
age:18,
name:"达姆",
wife:{
name:"周冬雨",
age:18
}
};
Object.defineProperty(obj,"PI",{
value:3.141592654,
enumerable:true
})
// 浅密封
Object.seal(obj)
obj.age=19;
delete obj.wife.age;
delete obj.name;
console.log(obj)
</script>
04_冻结对象.html
<script type="text/javascript">
var obj ={
age:18,
name:"达姆",
wife:{
name:"周冬雨",
age:18
}
};
Object.defineProperty(obj,"PI",{
value:3.141592654,
enumerable:true
})
//冻结对象
Object.freeze(obj)
obj.age=19;
delete obj.wife.age;
delete obj.name;
console.log(obj)
</script>
05_深度冻结对象.html
<script type="text/javascript">
var obj ={
age:18,
name:"达姆",
wife:{
name:"周冬雨",
age:18
}
};
// 浅冻结
Object.freeze(obj);
//深度冻结操作:遍历每一个子元素,并分别冻结
for(item in obj){
//除了Object.prptotype
if(obj[item] instanceof Object){
Object.freeze(obj[item]);
}
}
obj.wife.name="aaa";
delete obj.wife.age;
console.log(obj)
</script>
四、属性的设置与获取
1、 属性查找: [[Get]]:代表的属性查找的算法
[[Get]]:
1.在对象中查找是否具有相同名称的属性,如果找到,就会返回这个属性的值。
2.如果没有找到,则遍历原型链
3.无论·如何都没找到,返回undefined
属性的设置与获取.html
<script type="text/javascript">
/*
属性(writable为true的数据描述符)
属性的获取:
先在当前对象中找
如果找到则使用
如果找不到 上隐式原型链
如果找到使用
如果找不到 返回undefined
属性的设置
不管怎么样都影响对象的直接属性
*/
/*[[Get]]:
1.在对象中查找是否具有相同名称的属性,如果找到,就会返回这个属性的值。
2.如果没有找到,则遍历原型链
3.无论·如何都没找到,返回undefined
4.如果属性是访问描述符就看get方法的逻辑!!*/
/*
obj.a="a";
[[put]]:
1.如果属性直接存在于对象中 不在原型链上
4.如果属性直接存在于对象中 也在原型链上
找到直接存在于对象中的属性
-数据描述符(没有setter/getter)
直接修改对象中的属性(注意writbale的值)
-访问描述符
直接调用set方法
2.如果属性不直接存在于对象中也不在原型链上
在对象的直接属性中添加一个属性(数据描述符)
value:"a"
writable:true
configurable:true
enumerable:true
3.如果属性不直接存在于对象中 在原型链上
①.该属性是数据描述符(没有setter/getter)
-writbale为true
直接在对象中添加一个属性,我们称之为屏蔽属性
-writbale为false
报错,不会生成屏蔽属性
②.该属性是访问描述符
调用set,不会生成屏蔽属性
*/
/*
3.如果属性不直接存在于对象中 在原型链上
①.该属性是数据描述符(没有setter/getter)
-writbale为true
直接在对象中添加一个属性,我们称之为屏蔽属性
-writbale为false
静默失败,不会生成屏蔽属性
②.该属性是访问描述符
调用set,不会生成屏蔽属性
*/
var obj={};
Object.defineProperty(Object.prototype,"age",{
/*value:18,
writable:false*/
get:function(){
},
set:function(val){
}
})
obj.age=1;
console.log(obj,Object.prototype.age);
</script>
2、属性设置:[[Put]]:代表的属性设置的算法
[[put]]:
1.如果属性直接存在于对象中 不在原型链上
找到直接存在于对象中的属性
-数据描述符(没有setter/getter)
直接修改对象中的属性(注意writbale的值)
-访问描述符
直接调用set方法
2.如果属性不直接存在于对象中也不在原型链上
在对象的直接属性中添加一个属性(数据描述符)
value:"a"
writable:true
configurable:true
enumerable:true
3.如果属性不直接存在于对象中 在原型链上
①.该属性是数据描述符(没有setter/getter)
-writbale为true
直接在对象中添加一个属性,我们称之为屏蔽属性
-writbale为false
报错,不会生成屏蔽属性
②.该属性是访问描述符
调用set,不会生成屏蔽属性
4.如果属性直接存在于对象中 也在原型链上
找到直接存在于对象中的属性
-数据描述符(没有setter/getter)
直接修改对象中的属性(注意writbale的值)
-访问描述符
直接调用set方法
01如果属性直接存在于对象中,不在原型链上.html
<script type="text/javascript">
// 如果属性直接存在于对象中 不在原型链上
console.log(Object.prototype)
// -数据描述符(没有setter/getter)
// 直接修改对象中的属性(注意writbale的值)
var obj={
a:"a"
}
Object.defineProperty(obj,"a",{
writable:false
})
obj.a="b";
console.log(obj.a)
// -访问描述符
// 直接调用set方法
var obj2={
a:"a"
}
Object.defineProperty(obj2,"a",{
get :function(){
return this._a_;
},
set :function(val){
this._a_ = val;
}
})
obj2.a="b";
console.log(obj2)
console.log(obj2.a)
</script>
02如果属性不直接存在于对象中也不在原型链上.html
<script type="text/javascript">
// 如果属性不直接存在于对象中也不在原型链上
console.log(Object.prototype)
var obj={}
obj.a="a";
console.log(obj.a)
var result =Object.getOwnPropertyDescriptor(obj,"a");
console.log(result);
</script>
03如果属性不直接存在于对象中 在原型链上.html
<script type="text/javascript">
// 如果属性不直接存在于对象中 在原型链上
Object.prototype.a="prototypeA";
console.log(Object.prototype);
var result = Object.getOwnPropertyDescriptor(Object.prototype,"a");
console.log(result);
// ①.该属性是数据描述符(没有setter/getter)
// -writbale为true
// 直接在对象中添加一个属性,我们称之为屏蔽属性
var obj={};
obj.a="a";
console.log(obj,"------------------------------")
// -writbale为false
// 报错,不会生成屏蔽属性
Object.defineProperty(Object.prototype,"a",{
writable:false
});
console.log(Object.prototype);
var result = Object.getOwnPropertyDescriptor(Object.prototype,"a");
console.log(result);
var obj2={};
obj2.a="a";
console.log(obj2,"------------------------------")
// ②.该属性是访问描述符
// 调用set,不会生成屏蔽属性
Object.defineProperty(Object.prototype,"a",{
// get:function(){
//
// },
set:function(val){
}
});
console.log(Object.prototype);
var result = Object.getOwnPropertyDescriptor(Object.prototype,"a");
console.log(result);
var obj3={};
obj3.a="a";
console.log(obj3,"------------------------------")
</script>
04如果属性直接存在于对象中 也在原型链上.html
<script type="text/javascript">
// 如果属性直接存在于对象中 也在原型链上
Object.prototype.a="prototypeA";
console.log(Object.prototype)
var obj={
get a(){
return this._a_;
},
set a(val){
this._a_="_a_";
}
}
obj.a="b";
console.log(obj)
console.log(Object.prototype)
</script>