Object对象是JavaScript中的复杂数据类型,在JavaScript很常用到,除了基本数据类型以外,其他的值都是对象。
对象创建
创建对象有3中方式:
1、对象直接量:
var obj={name:'obj'}
2、通过关键词new创建
var obj=new Object({name:'obj'})
3、通过Object.create()
var obj=Object.create({name:'obj'})
Object.create(proto[,propertiesObject])包含两个参数,
-
第一个就是要继承的原型
-
第二个可选,为新创建的对象指定属性对象
propertiesObject中的属性
属性 | 说明 |
---|---|
configurable | 对象的属性是否可以被删除或修改,默认false |
enumerable | 对象属性是否可枚举的,默认false |
writable | 对象是否添加新属性,默认false |
get | 对象getter函数,默认undefined |
set | 对象setter函数,默认undefined |
上面的代码实际上并不是创建了一个新对象,而是让obj对象继承了某个对象的原型。
console.log(obj.__proto__) //{name:'obj'}
如果想创建一个新的对象就应该将参数proto设置为null,这样就不继承任何原型了
var obj=Object.create(null)
obj.name='obj'
console.log(obj) //obj没有_proto__属性
而1、2这两种对象创建方法是有_proto__属性的,指向了Object的原型,所以要这样改写,同时还为对象指定了name属性
var obj=Object.create(Object.prototype,{name:{value:'obj',writable:true}})
对象的属性
var obj={name:'obj'}
想访问对象中的属性,可以通过 . 和 [ ] 来实现,同时也可以使用这两种方法来增加属性
console.log(obj.name) //obj
console.log(obj['name']) //obj 字符串索引
obj.name2='obj2'
obj['name3']='obj3'
console.log(obj) //{name: "obj", name2: "obj2", name3: "obj3"}
通过delete可以删除属性
delete obj.name
delete obj.name1
自有和继承
自有就是在对象内部定义的属性或者方法,而继承则是通过原型继承获得的属性和方法。
var obj={name:'obj'} //name是obj的自有属性
obj.toString() //toString()这个方法则是继承自Object原型
通过hasOwnProperty()可以对对象的属性进行判断,true为自有属性,false则不是。
Object.prototype.name1='object' //给Object原型添加了name1属性
console.log(obj.name1) //object
console.log(obj.hasOwnProperty('name')) //true 自有
console.log(obj.hasOwnProperty('name1')) //false 继承
obj.__proto__name1='change' //改变了继承而来的属性的值
如果不想被继承对象改变自己的属性的话,则需要对自身的属性进行配置
采用Object.defineProperty()方法来设置。
Object.defineProperty(obj, prop, desc)接受三个参数
- obj 需要定义属性的当前对象
- prop 当前需要定义的属性名
- desc 属性描述符(与Object.create()方法中的propertiesObject中的属性一样)
Object.defineProperty(Object.prototype,'name1',{value:'object',writable:false,enumerable:true})
var obj={name:'obj'}
obj.__proto__.name1='change'
console.log(obj.name1) //object 不会被改变
除了检测对象的属性是否存在以外,还可以通过for/in循环来遍历对象的所有可枚举属性.
for(value in obj){
console.log(value)
}
//输出 name name1
通过propertyIsEnumerable()方法可以判断对象中某个属性是否可枚举
console.log(obj.propertyIsEnumerable('name')) //true
getter和setter属性
根据上面的create和defineProperty方法中可以知道,对象是由名字、值和一组特性构成的,属性值可以用一些方法来替代,这些方法就是getter和setter,由getter和setter定义的属性称为“存储器属性”。getter就是只读属性,setter是只写属性,如果只具有这两种方法中的其中一种,那么就只能进行只读或者只写操作。
定义存储器属性最简单的方法就是使用对象直接量语法的一种扩展写法:
var o={
data_prop:value,
get accessor_prop(){}, 函数定义不使用function,而是get 和 set
set accessor_prop(value){}
}
例子:
var p={
x:1,
get r(){return this.x+32}
}
console.log(p.r) //33
还有其他写法,比如在Object.defineProperty()方法中
var o={a:1}
Object.defineProperty(o,'b',{get:function(){return this.a+3}}) //这里就需要用使用function来定义函数
console.log(o.b) //4
存储器属性(即没有设置setter和getter)不具备value(值),writable(可写)这两个属性,如果设置了的话会报Uncaught TypeError,因为它的可写性是通过setter方法决定的,
属性名 | 数据属性 | 存储器属性 |
---|---|---|
value | 可设置 | 不可 |
writable | 可设置 | 不可 |
enumerable | 可设置 | 可设置 |
configurable | 可设置 | 可设置 |
set | / | 可设置 |
get | / | 可设置 |
通过Object.getOwnPropertyDescriptor(对象,属性)可以夺取某个对象特定属性的属性描述符:
var o={a:1}
Object.defineProperty(o,'b',{get:function(){return this.a+3}})
console.log(Object.getOwnPropertyDescriptor(o,'b'))
//{get: ƒ, set: undefined, enumerable: false, configurable: false}
console.log(Object.getOwnPropertyDescriptor(o,'a'))
//{value: 1, writable: true, enumerable: true, configurable: true}
通过使用getter、setter实现数据双向绑定
对象的原型和可扩展性
对象的原型属性是用来继承的属性。
原型属性在实例对象创建时就设置好了,就比如之前的3种对象创建方法:
- 通过对象直接量使用Object.prototype作为对象的原型
- 通过new创建了以构造函数的prototype属性作为原型的对象
- 通过Object.create()创建的对象使用第一个参数作为原型
使用isPrototypeOf()来检验一个对象是否是另一个对象的原型。
var a={}
console.log(Object.prototype.isPrototypeOf(a))//true
console.log(a instanceof Object) //true
该方法与instanceof()类似.
可扩展性
对象的可扩展性表示是否可以给对象添加新属性。所有的内置对象和自定义对象都是显示可扩展的。
Object.preventExtensions()使得对象变得不可扩展,将对象变得不可扩展后无法转回可扩展。Object.isExtensible()判断对象是否可扩展。
var o={a:0}
Object.preventExtensions(o)
Object.isExtensible(o)
Object.defineProperty(o,'b', {get:function(){return 3}}) //Uncaught TypeError 不可扩展
Object.seal()与preventExtensions()类似,除了设置成不可扩展外,还将对象的所有自由属性设置为不可配置(即不能添加新属性和删除已有的属性),同样不可逆转。Object.isSealed()检测是否关闭。
Object.freeze()则更加严格,在seal的基础上将对象的所有自有属性设置为只读,不能更改
Object.isFrozen()判断是否冻结
var o={a:0}
Object.freeze(o)
o.a=2
console.log(o) //{a:0}
对象方法
在上面已经提及了hasOwnProperty(),propertyIsEnumerable(),isPrototypeOf(),Object.create()这些方法,就不在介绍了
toString()
当该对象被表示为一个文本值时,或者一个对象以预期的字符串方式引用时自动调用。默认情况下,toString() 方法被每个 Object 对象继承,返回的就是对象本身的字符串。如果此方法在自定义对象中未被覆盖,toString() 返回 “[object type]”,其中 type 是对象的类型。
使用toString()来检测对象类型
Object.prototype.toString.call()
console.log(Object.prototype.toString.call(new Date)) //[object Date]
console.log(Object.prototype.toString.call(Function(){})) //[object Function]
console.log(Object.prototype.toString.call(null)) //[object Null]
toLocaleString()
返回对象的本地化字符串。不同的对象有不同的转换。
Object中默认的toLocaleString()仅调用toString()方法并返回对应值。
Date和Number对象则是对日期、数字做本地化的转换
Array对象中和toString()类似,不同的是是每个数组元素都会调用toLocaleString()转换成字符串
valueOf()
与toString()方法类似,将对象转换成对象的原始值而非字符串,尤其是转换成数字的时候。