对象的查询和设置
属性特性
属性描述符
概念
-
属性描述符又叫元属性,也可以认为它是属性的属性。
-
对象属性的属性描述符一共有四个:
-
configurable: 表示能否通过delete来删除属性从而重新定义属性,能够修改属性的特性,默认为true;
var damu = {}; Object.defineProperty(damu,'wife',{ value:'zdy', configurable: true }) var result = Object.getOwnPropertyDescriptor(damu,'wife'); console.log(damu);//{wife: "zdy"} delete damu.wife; console.log(damu)//{}
- configurable设置决定是否可删除属性:
- configuarable:false:不能删
- configuarable:true:能删
- configurable设置决定是否可配置属性描述符:
- configuarable:true:可以配置
- configurable:false
- writable:可以从ture变为其他,不能从false变为其他;
- configurable:不能动
- enumerable:不能动
- configurable设置决定是否可删除属性:
-
enumberable: 表示是否能通过for-in循环返回属性。默认为true;
var damu={}; Object.defineProperty(damu,"a",{enumerable:true});//可遍历 Object.defineProperty(damu,"b",{enumerable:false});//不可遍历 Object.defineProperty(damu,"c",{enumerable:true}); Object.defineProperty(damu,"d",{enumerable:false}); Object.defineProperty(damu,"e",{enumerable:true}); Object.defineProperty(damu,"f",{enumerable:false}); Object.defineProperty(damu,"g",{enumerable:true}); for(item in damu){ console.log(item); }//aceg
- writable: 是否可以修改属性, 默认为true;
var damu = {}; //通过Object.defineProperty设置的对象,属性秒速服都是false,在此特意将writable: true改为true; Object.defineProperty(damu,'wife',{ value:'zdy', writable: true }) var result = Object.getOwnPropertyDescriptor(damu,'wife'); console.log(damu);//{wife: "zdy"} damu.wife = 'fbb'; //如果writable: false,设置属性值的话,会失败,叫做:静默失败。 //因为设置可改写,所以可以改写属性值。 console.log(damu)//{wife: "fbb"}
- value: 包含这个属性的数据值。读取属性值时3,从这个属性读,写入属性时,把新值保存到这个位置。默认值为undefine.
-
获取方式
- 获取属性描述符:
- Object.getOwnPropertyDescriptor(obj, prop);
- obj:属性所在的对象;
- prop:对象属性名称;
- 返回值:对象属性的描述符对象。返回指定对象上一个自有属性对应的属性描述符。(自有属性指的是直接赋予该对象的属性,不需要从原型链上进行查找的属性);
- Object.getOwnPropertyDescriptor(obj, prop);
var obj = {name:'kobe',age:29};
//字面量形式定义对象
console.log(Object.getOwnPropertyDescriptor(obj, 'name'));
//{value: "kobe", writable: true, enumerable: true, configurable: true}
var obj1 = {};
obj1 = Object.create(obj)
console.log(obj1);//{}
obj1 = Object.create(obj,{
sex:{
value:'男'
}
})
//通过creat,以指定对象为原型创建新的对象。
console.log(obj1);//{sex: "男"}
console.log(Object.getOwnPropertyDescriptor(obj1, 'sex'));
//{value: "男", writable: false, enumerable: false, configurable: false}
var obj2 = {};
//通过definedProperty定义的对象
Object.defineProperties(obj2,
{'wife2':{value:'lbb',},
'wife3':{value:'zdy'}
});
console.log(obj2);//{wife2: "lbb", wife3: "zdy"}
console.log(Object.getOwnPropertyDescriptor(obj2, 'wife2'));
//{value: "lbb", writable: false, enumerable: false, configurable: false}
属性描述符设置方式
-
属性描述符设置的区别
- 如果是字面量形式定义对象;此时得到的三种(除了value)属性描述符都为true;即,可配置,可写,可遍历。
var damu = {wife:'fbb'}; var result = Object.getOwnPropertyDescriptor(damu,'wife'); console.log(result); //{value: "fbb", writable: true, enumerable: true, configurable: true} //此时所有的属性描述符都是true
- 使用Object.defineProperty()定义对象的属性,得到的三种属性描述符都是false(使用creat方法也是);
var damu1 = {}; Object.defineProperty(damu1,'wifeagain',{value:'libb'}); var result = Object.getOwnPropertyDescriptor(damu1,'wifeagain'); console.log(result);//{value: "libb", writable: false, enumerable: false, configurable: false}
-
注意:当在全局中使用var定义变量以及不使用var定义变量时的属性描述符默认的区别:
- 使用var在全局中定义变量时,可配置描述符(configurable)为false,即不可配置,剩下的属性描述符(enumberable、writable)为true,即可写、可遍历。
var a=1; var result=Object.getOwnPropertyDescriptor(window,'a'); window.a = 5;//无作用 console.log(result);//{value: 1, writable: true, enumerable: true, configurable: false}
- 不使用声明在全局中赋值变量时,三个属性描述符都为true,即,可配置、可写、可遍历。
b=2; var result1=Object.getOwnPropertyDescriptor(window,'b'); // 帮助理解:隐含全局变量(无var的)严格来说不是真正的变量,而是全局对象的属性,因为属性可以通过 delete 删除,而变量不可以。 console.log(result1);//{value: 2, writable: true, enumerable: true, configurable: true}
访问描述符
概念
- 当你给一个属性定义setter或者getter,或者两者都有时,这个属性会被定义为“访问描述符”。
- 对于访问描述符来说,Javascript会忽略他们的value和writable特性。取而代之的是set和get函数。
- get: 在读取属性时,调用的函数。在读取属性时调用的函数。只指定get则表示属性为只读属性。默认值为undefined。
- 注意,get属性只有在调用它掌控的属性的时候,才会被调用该get方法的。
- set: 在写入属性时调用的函数。在写入属性时调用的函数。只指定set则表示属性为只写属性。默认值为undefined。
- get: 在读取属性时,调用的函数。在读取属性时调用的函数。只指定get则表示属性为只读属性。默认值为undefined。
var obj2 = {};
Object.defineProperties(obj2,
{'wife2':
{get : function () {return 'lbb';}},
'wife3':{value:'zdy'}
}
);
obj2.wife2 = 'zly';
obj2.wife3 = 'zly';
console.log(obj2);//{wife3: "zdy"}
console.log(obj2.wife2);//lbb
console.log(Object.getOwnPropertyDescriptor(obj2, 'wife2'));
//{set: undefined, enumerable: false, configurable: false, get: ƒ}
console.log(Object.getOwnPropertyDescriptor(obj2, 'wife3'));
//{value: "zdy", writable: false, enumerable: false, configurable: false}
//set的理解
var obj2 = {};
Object.defineProperties(obj2,
{'wife2':
{get :
function () {return 'lbb';}
,set :
function (data) {
//此时传入的实参就是想要改变的obj2.wife2的值obj2.wife2 = 'chenhao'。data就是用来接收它的。
console.log(data);//chenhao
}
},
'wife3':{value:'zdy',writable:true}
}
);
console.log(obj2.wife2);//lbb
obj2.wife2 = 'chenhao';
console.log(obj2.wife2);//lbb
//set和get理解
var obj2 = {};
Object.defineProperties(obj2,
{'wife2':
{get : function () {
this.value = 80;
//return出的值是什么,obj2.wife2的结果就会是什么。
return this.value;
}
,set : function (data) {
//data用来接收修改的值,obj2.wife2 = 'chenhao';
console.log(data);//chenhao
//此时将get中的return出去的值改成data,即chenhao。
//但是注意,因为之前的this.value = 80,这次的赋值覆盖了其它的值,所以输出的依然是80.
this.value = data;
}
},'wife3':{value:'zdy',writable:true}
}
);
console.log(obj2.wife2);//80
obj2.wife2 = 'chenhao';
console.log(obj2.wife2);//80
//get和set的理解3
var obj2 = {wname:'xiannv1',wname2:'xiannv2'};
Object.defineProperties(obj2,
{'wife2':
{get : function () {
//确定了obj2.wife2输出的值是return后面的内容,即this.wname = 'xiannv1'。
//get是读取对象属性值的方法。obj2对象的wife2通过get得到值。
return this.wname;
}
,set : function (data) {
//想修改obj2.wife2,通过data接收到修改的属性值。
//set是修改属性值的方法,想要修改obj2.wife2,就是修改get中ruturn的内容,即this.wname。然后将想要修改的属性值data=chenhao,赋值给this.wname。
console.log(data);//chenhao
this.wname = data;
}
}}
);
console.log(obj2.wife2);//xiannv1
obj2.wife2 = 'chenhao';
console.log(obj2.wife2);//chenhao
基于对象属性的几大特性
对象常量属性
- 概念:将属性的writable和configurable设置为false;
//将属性的writable和configurable设置为false var damu={}; Object.defineProperty(damu,"wife",{ value:"fbb" }) Object.defineProperty(damu,"wife",{ value:"fbb2" }); //无法更改,无法删除。可以添加 //console.log(damu);//报错,Cannot redefine property damu.wife="damu" delete damu.wife; console.log(damu);//{wife: "fbb"} damu.wife2="fbb2"; console.log(damu);//{wife2: "fbb2", wife: "fbb"}
禁止属性扩展
- 概念
- 如果一个对象可以添加新的属性,则这个对象是可扩展的,让这个对象变的不可扩展,也就是不能再有新的属性;
- 由于属性描述符是对属性的管理,所以想禁止对象扩展,不能使用属性描述符来控制,而是需要调用其他的对象的方法。
- 两种有关对象属性扩展的对象方法:
- Object.isExtensible 方法:Object.isExtensible() 方法判断一个对象是否是可扩展的(是否可以在它上面添加新的属性)。
- 语法: Object.isExtensible(obj)
- 参数: obj 需要检测的对象;
- 默认情况下,创建的对象默认是可扩展
//新对象默认是可扩展的无论何种方式创建的对象 //使用的是字面量方式 var empty = {a:1}; console.log(Object.isExtensible(empty) === true);//true //等价于 使用属性描述符 empty = Object.create({},{ "a":{ value : 1, configurable : true,//可配置 enumerable : true,//可枚举 writable : true//可写 } }); console.log(Object.isExtensible(empty) === true);//true //创建属性的方式 var damu={}; Object.defineProperty(damu,"wife",{ value:"fbb" }) console.log(Object.isExtensible(damu) === true);//true
- Object.preventExtensions 方法:方法让一个对象变的不可扩展,也就是永远不能再添加新的属性,并且返回原对象。
- 语法:Object.preventExtensions(obj);
- 参数:obj 将要变得不可扩展的对象;
var damu = {}; Object.defineProperty(damu,'wife',{ value:'lbb' }); console.log(damu);//{wife: "lbb"} Object.preventExtensions(damu); // damu.age = 18; // console.log(damu);//{wife: "lbb"} (function fail(){ "use strict"; damu.d = "4";//throws a TypeError })(); console.log(damu);//Cannot add property d, object is not extensible
- 描述:
- 如果一个对象可以添加新的属性,则这个对象是可扩展的。preventExtensions 可以让这个对象变的不可扩展,也就是不能再有新的属性。
- 需要注意的是不可扩展的对象的属性通常仍然可以被删除。
- 尝试给一个不可扩展对象添加新属性的操作将会失败,不过可能是静默失败(默认情况),也可能会抛出 TypeError 异常(严格模式)。
- 注意:Object.preventExtensions 只能阻止一个对象不能再添加新的自身属性,仍然可以为该对象的原型添加属性。
- Object.isExtensible 方法:Object.isExtensible() 方法判断一个对象是否是可扩展的(是否可以在它上面添加新的属性)。
密封对象
-
概念:
- 密封对象是指那些不可扩展的,且所有自身属性都不可配置的(non-configurable)对象。
- 或者可以说,密封对象是指那些不能添加新的属性,不能删除已有属性,以及不能修改已有属性的可枚举性、可配置性、可写性,但可能可以修改已有属性的值的对象。
-
可用方法:在禁止对象扩展(Object.preventExtensions(obj);的基础上把现有属性的configurable都调整为false;
//设置对象即使不可扩展又不可配置 var damu = {}; Object.defineProperty(damu,'wife',{ value:'lbb' //此时默认的configurable和writable都为false的。 }); console.log(damu);//{wife: "lbb"} Object.preventExtensions(damu); damu.age = 18; delete damu.wife;//{wife: "lbb"} console.log(damu);//{wife: "lbb"}; //证明不可配置、不可扩展。但是这种设置的过程很麻烦,尝试使用简单的对象方法来设置密封对象。
-
两种有关密封属性的方法
- Object.isSealed 方法:方法判断一个对象是否是密封的(sealed)。
- 语法 :Object.isSealed(obj);
- 参数:obj 将要检测的对象;
- 描述:如果这个对象是密封的,则返回 true,否则返回 false。
//使用Object.preventExtensions设置为不可扩展,再设置不可配置,则成为密封了。 var damu = {}; Object.defineProperty(damu,'wife',{ value:'lbb' //此时默认的configurable和writable都为false的。 }); Object.preventExtensions(damu); console.log(Object.isSealed(damu));//true
-
Object.seal() 方法:可以让一个对象密封,并返回被密封后的对象。
- 语法:Object.seal(obj)
- 参数:obj 将要被密封的对象
var damu = {}; Object.defineProperty(damu,'wife',{ value:'lbb' //此时默认的configurable和writable都为false的。 }); console.log(Object.getOwnPropertyDescriptor(damu,"wife"));//{value: "lbb", writable: false, enumerable: false, configurable: false} Object.seal(damu); console.log(Object.isSealed(damu));//true //静默失败 damu.d = 'd'; delete damu.wife; console.log(damu);//{wife: "lbb"} console.log(Object.getOwnPropertyDescriptor(damu,"wife"))
- 描述:
- 通常情况下,一个对象是可扩展的(可以添加新的属性)。
- 密封一个对象会让这个对象变的不能添加新属性,且所有已有属性会变的不可配置。
- 属性不可配置的效果就是属性变的不可删除,以及一个数据属性不能被重新定义成为访问器属性,或者反之。但属性的值仍然可以修改。
- 尝试删除一个密封对象的属性或者将某个密封对象的属性从数据属性转换成访问器属性,结果会静默失败或抛出TypeError 异常(严格模式)。
- 不会影响从原型链上继承的属性。但 proto ( ) 属性的值也会不能修改。
- Object.isSealed 方法:方法判断一个对象是否是密封的(sealed)。
冻结对象
-
概念:
- 一个对象是冻结的(frozen)是指它不可扩展,所有属性都是不可配置的(non-configurable),且所有数据属性(data properties,指那些没有取值器getter或赋值器setter的属性)都是不可写的(non-writable);
- 或则说 冻结对象是指那些不能添加新的属性,不能修改已有属性的值,不能删除已有属性,以及不能修改已有属性的可枚举性、可配置性、可写性的对象。也就是说,这个对象永远是不可变的;
-
可用方法:在密封对象(Object.seal(obj))的基础上把现有属性的writable都调整为false:
//在密封对象(Object.seal(obj))的基础上把现有属性的writable都调整为false var damu = {}; Object.defineProperty(damu,'wife',{ value:'lbb', //writable:true }); //密封 Object.seal(damu); //防扩展 Object.preventExtensions(damu); damu.age = 18; delete damu.wife; damu.wife = 'zdy'; console.log(damu);//{wife: "lbb"};
-
两种有关密封属性的方法
-
Object.isFrozen 方法:方法判断一个对象是否被冻结(frozen)。
- 语法: Object.isFrozen(obj)
- 参数:obj 被检测的对象
-
Object.freeze() 方法:可以冻结一个对象。
- 语法:Object.freeze(obj);
- 参数:obj 将要被冻结的对象;
var damu = {wife:'lbb'}; console.log(Object.getOwnPropertyDescriptor(damu,"wife")); //{value: "lbb", writable: true, enumerable: true, configurable: true} //冻结对象 Object.freeze(damu); console.log(Object.getOwnPropertyDescriptor(damu,"wife")); //{value: "lbb", writable: false, enumerable: true, configurable: false} damu.age = 18; delete damu.wife; damu.wife = 'zdy'; console.log(damu);//{wife: "lbb"}
- 描述:
- 冻结对象的所有自身属性都不可能以任何方式被修改。
- 任何尝试修改该对象的操作都会失败,可能是静默失败,也可能会抛出异常(严格模式中)。
- 数据属性的值不可更改,访问器属性(有getter和setter)也同样(但由于是函数调用,给人的错觉是还是可以修改这个属性)。
- 如果一个属性的值是个对象,则这个对象中的属性是可以修改的,除非它也是个冻结对象。
//浅不变形 var damu={wifes:{wife1:"fbb",wife2:"lyf",wife3:"zdy"}}; damu.wifes.wife1="lbb"; console.log(damu);//wifes:{wife1: "lbb", wife2: "lyf", wife3: "zdy"} //深层次冻结 var damu={ wifes:{wife1:"fbb",wife2:"lyf",wife3:"zdy"} }; Object.freeze(damu); //遍历调用冻结方法,将对象属性内的对象全部冻结。 for(item in damu){ Object.freeze(damu[item]); } damu.wifes.wife1="lbb"; console.log(damu);//wifes:{wife1: "fbb", wife2: "lyf", wife3: "zdy"}
-
对象属性的遍历
-
三种方式
- obj.propertyIsEnumerable(属性名);
- 判断是否可遍历出指定的对象属性;
- 如果设置的是不被遍历,则直接返回false;
- Object.keys(obj);
- 检索所有的可被检索的对象属性;
- 返回值是所有的属性名组成的数组;
- Object.getOwnPropertyNames(obj);
- 检索所有的对象属性,无论是否可被检索;
- 返回值是所有的属性名组成的数组;
var damu={wifes:{wife1:"1"}}; Object.defineProperty(damu,"a",{enumerable:true}) Object.defineProperty(damu,"b",{enumerable:false}) Object.defineProperty(damu,"c",{enumerable:true}) Object.defineProperty(damu,"d",{enumerable:false}) Object.defineProperty(damu,"e",{enumerable:true}) Object.defineProperty(damu,"f",{enumerable:false}) Object.defineProperty(damu,"g",{enumerable:true}) console.log(damu.propertyIsEnumerable("f"));//false 判断是否可遍历出这个对象属性 console.log(Object.keys(damu));// ["wifes", "a", "c", "e", "g"] 检索所有的可被检索的对象属性名 console.log(Object.getOwnPropertyNames(damu));//["wifes", "a", "b", "c", "d", "e", "f", "g"] 检索所有的属性名,无论是否可被检索
- obj.propertyIsEnumerable(属性名);
对象的设置和获取
伪数组
var wei = {length:3,0:0,1:1,2:2};
var arr =Array.prototype.slice.call(wei);
//Array.prototype.slice()新截取的一个空数组。尽量不要定义新数组,这样可以节省空间。
console.log(Array.prototype.slice());
console.log(Array);//数组函数 ƒ Array() { [native code] }
arr.push(3);
console.log(arr);
//常用定义兼容方法
function test(arr,fn){
arr =arr||Array.prototype;
fn =fn||Function.prototype;
return arr.map(fn).join(" ");
}
console.log(test());