第三章 属性高级
一、属性描述符
1.获取对应属性的描述符
属性描述符:属性的特征;也叫元属性;修饰属性的属性
Object.getOwnPropertyDescriptor(obj,"name"); 第一个参数:对应的对象 第二个参数:对应对象的属性
//res是一个对象
{
}
2.为对象新增或修改属性
var obj={ name:"snw" }; Object.defineProperty(obj,"age",{ value:18, writable:true, configurable:true, emumerable:true }); console.log(obj); //Object {name: "snw", age: 18} console.log(obj.age);//18 属性描述符的默认值都是false
3.writable(可写的)
writable决定是否可以修改属性的值
当writable为false时,对应的属性的值是无法修改的。
// writable为false 时 configurable一般也为false
在默认情况下:
继续修改的话会静默失败
在严格模式下:
会报错
var obj={
name:"Lebron",
age:33,
team:"湖人"
}
//obj.team="骑士"; 位置在这儿能被修改
Object.defineProperty(obj,"team",{
writable:false
})
obj.team="热火";
console.log(obj);
4.configurable(可配置的)
configurable来决定属性是否可以配置
可配置:属性能否重新定义 属性能否删除 当configurable为false时,对应的属性是无法重新定义的,无法删除的。但该对象是还可以继续添加属性的。 默认情况下
进行重新定义会报错
进行删除会静默失败 注意一个小小的例外: 当configurable为false时,writable可以进行重新定义,但只满足由writable:true ==> writable:false
5.enumerable
//enumerable可枚举:控制了属性的可枚举权限 //可枚举:能否出现在对象的for in 循环中 var obj={ name:"zyy", age:26, behavior:"play basketball" } Object.defineProperty(obj,"behavior2",{ value:"eat", enumerable:false }) for(var item in obj){ console.log(item); }
6.严格模式
<!--
严格模式的语法比较严谨
没有通过var定义的变量 在严格模式底下就会报错
this的指向
普通调用时 如果是严格模式 那this指向undefined
严格模式的管理范围:作用域
在属性描述符writable为flase的情况下 对属性值进行修改 就会报错不会静默失败
在属性描述符configurable为flase的情况下 对属性进行删除 就会报错不会静默失败
--> <script> function test() { "use strict" inner(); function inner() { console.log(this) } } (function () { "use strict" test() })()
7.属性的指定方式
/*属性的指定方式: 1. 字面量初始化的时候直接通过 键值对的形式指定 属性描述符的默认值基本都是true 2. 通过对象点的形式来指定 属性描述符的默认值基本都是true 3. 原始的指定形式的方式 ` 属性描述符的默认值基本都是false value:undefined 4. var a = "a"; 给window添加的属性 configurable: false enumerable: true writable: true 5. b="b";给window添加的属性 属性描述符的默认值基本都是true */ var a = "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);
8.存在性检查
var obj={ a:undefined, wife:{ name:"xxx" } }; console.log(obj.a); //in关键字 会影响对象的直接属性 也访问原型链 可是不访问对象的深层属性 console.log("a" in obj) console.log("b" in obj) console.log("toString" in obj) console.log("name" in obj,"------") //在js中所有的方法都是 浅不变形 的;只会影响对象的直接属性 不访问原型链 也不访问对象的深层属性 console.log(obj.hasOwnProperty("a")); console.log(obj.hasOwnProperty("b")); console.log(obj.hasOwnProperty("toString")); console.log(obj.hasOwnProperty("name")); var res = Object.getOwnPropertyNames(obj); console.log(res);
9.访问描述符(get&&set)
// 属性描述符 : 属性的特征 属性的属性 // 数据描述符 : 具有writable 和 value属性描述符 的属性! // 访问描述符 : 具有set 和 get属性描述符 的属性!
var obj={
get age(){
return obj.__age__;
},
set age(val){
if (val > 150){
val =150;
}else if(val < 0){
val =0;
}
obj.__age__=val;
}
}
obj.age=33;
console.log(obj.age);
二、对象不变性
1.对象常量属性
将属性的writable和configurable设置为false
var MathCopy = {};
Object.defineProperty(MathCopy,"PI",{
value:3.141592654,
writable:false,
configurable:false,
enumerable:true
})
MathCopy.PI=1;
console.log(MathCopy.PI)
2.禁止对象扩展
由于属性描述符是对属性的管理
所以想禁止对象扩展不能使用属性描述符来控制,而是需要调用Object.preventExtensions(obj);
参数:要求禁止扩展的对象
默认情况下
为对象添加新的属性会静默失败
严格模式底下
报错
注意:禁止对象扩展只是禁止了对象去扩展属性,
而之前的属性是可以进行重新定义或者删除的,
属性值也是可以修改的
3.密封对象
在禁止对象扩展(Object.preventExtensions(obj);的基础上把现有属性的configurable都调整为false
调用Object.seal(obj)密封一个对象
密封之后禁止了对象去扩展属性,原有的属性不可以进行重新定义或者删除,但属性值是可以修改的
var obj = {
a:"a",
b:'b'
};
Object.seal(obj);
delete obj.a;
obj.c="c";
obj.a="aa";
console.log(obj);
输出:{a: "aa", b: "b"} 没有被删除,也没有添加c
4.冻结对象(浅)
在密封对象(Object.seal(obj))的基础上把现有属性的writable都调整为false
调用Object.freeze(obj)密封一个对象
冻结之后禁止了对象去扩展属性,原有的属性不可以进行重新定义或者删除,属性值不可以进行修改
var obj = { a:"a", b:'b' }; Object.freeze(obj); delete obj.a; obj.c="c"; obj.a="aa"; console.log(obj);
5.冻结对象(深)
<script> var obj = { name: "zyy", age: 20, hobby: { No1: "playball", No2: "eat", No3: "sleep" } } function deep(obj) { var keys = Object.getOwnPropertyNames(obj); keys.forEach(function (key) { var val = obj[key] if (Object.prototype.toString.call(val) === "[object Object]") { deep(val) } }); return Object.freeze(obj) } deep(obj); obj.hobby.No1="watch"; console.log(obj) </script>
三、属性查找和设置
1.基本规则
/* 数据描述符 configurable: true enumerable: true writable: true */ // 查找: 先在对象的直接属性中找 找到了就返回 找不到上原型链 整体原型链都没有 返回 undefined // 设置: 只影响对象的直接属性
2.完整的规则(查找)
// [[Get]]:代表的属性查找的算法 // [[Get]]: // 1.在对象中查找是否具有相同名称的属性,如果找到,就会返回这个属性的值。 // 2.如果没有找到,则遍历原型链 // 3.无论如何都没找到,返回undefined // 4.访问描述符具体看get方法的逻辑
3.完整的规则(设置)
/* [[Put]]:代表的属性设置的算法 obj.a="a"; [[put]]: 1. 如果属性直接存在于对象中 不在原型链上 找到直接存在于对象中的属性 -数据描述符(没有setter/getter) 直接修改对象中的属性(注意writbale的值) -访问描述符 直接调用set方法 4. 如果属性直接存在于对象中 也在原型链上 找到直接存在于对象中的属性 -数据描述符(没有setter/getter) 直接修改对象中的属性(注意writbale的值) -访问描述符 直接调用set方法 2. 如果属性不直接存在于对象中也不在原型链上 在对象的直接属性中添加一个属性(数据描述符) value:"a" writable:true configurable:true enumerable:true 3. 如果属性不直接存在于对象中 在原型链上 ①.该属性是数据描述符(没有setter/getter) -writbale为true 直接在对象中添加一个属性,我们称之为屏蔽属性 (√)(√)(√)(√)-writbale为false 报错,不会生成屏蔽属性 (√)(√)(√)(√) ②.该属性是访问描述符 调用set,不会生成屏蔽属性 */ // Object.prototype.a="a"; Object.defineProperty(Object.prototype,"a",{ set:function(val){ } }) var obj={}; obj.a="aaaa"; console.log(obj,Object.prototype) </script>
object
静态方法
Object.create()
Object.defineProperty()
Object.getOwnPropertyDescriptor()
Object.getOwnPropertyNames()
Object.preventExtensions()
Object.seal()
Object.freeze()
Object.keys()
实例方法
Object.prototype.toString()
Object.prototype.valueOf()
Object.prototype.propertyIsEnumerable()