JavaScript中所有的事物都是对象,字符串,数字,数组,日期,等等,JavaScript对象可以看作是属性的无序集合,每个属性都是一个键值对,JavaScript对象除了可以保持自有属性,还可以从一个称为原型的对象继承属性。对象的方法通常是继承的属性,这种“原型式继承”是JavaScript的核心特征
1,初识对象
对象最常见的用法是:创建,设置,查找,删除,检测和枚举它的属性。属性包括名字和值。属性名可以是包含空字符串在内的任意字符串,属性值可以是任意JavaScript的值。除了名字和值意外,每个属性还有一些与之相关的值,称为:属性特性,
(1) 可写,表明是否可以设置改属性的值
(2) 可枚举,表明是否可以通过for/in循环返回该属性
(3) 可配置,表明是否可以三次或者修改该属性
每个对象还拥有三个相关的对象特性
(1) 对象的原型:指向另外一个对象,本对象的属性继承自它的原型对象
(2) 对象的类:是一个标识对象类型的字符串
(3) 对象的扩展标记:指明了是否可以向该对象添加新的属性
2,对象的创建
(1) 对象直接量
var obj = {x:1,b:2}
(2) 通过new创建
var obj = new Array()
var date = new Date()
(3) 通过Object.create()创建
var obj = Object.create()
复制代码
3,了解原型
每一个JavaScript对象(null除外)都和另一个对象相关联,‘另一个’对象就是我们熟知的原型,每一个对象都从原型继承属性。用对象直接量创建的对象都具有同一个原型对象,通过Object.prototype获得对原型对象的引用。通过new创建的对象,原型就是构造函数的prototype属性的值,比如:Array.prototype,Date.prototype。没有原型对象的:Object.prototype就只其中之一。普通对象都具有原型,Array.prototype的属性继承自:Object.prototye, 因此:new Date()创建的Date对象的属性同时继承Date.prototype,和Object.prototye,这就是原型链
4,属性的查询和设置
可以通过点(.)或者方括号([]),比如:obj.a 或者 obj['a']都可以获得属性值, ECMAScript 3中,点运算符后的标识符不能使用保留字,ES5放宽了限制,常见的两种例外情况:对象属性名是个关键字,那么只有用中括号去访问,如果属性名是个不确定参数,那么也只能用中括号去访问
5,删除属性
delete运算符只能删除自由属性,不能删除继承属性,也不能删除那些不可配置的属性,返回值是true或者false
6,检测属性
判断某个属性是否存在于某个对象中,可以通过in运算符,hasOwnProperty() 和proertyIsEnumerable()方法
(1)in运算符 (检测自有属性和继承属性)
var obj = { x: 1, y: 2}
"x" in obj
// 左侧是属性名,右侧是对象,如果对象的自有属性或继承属性含有这个属性,返回true
复制代码
(2)hasOwnProperty()函数(检测自有属性)
var obj = { x:1, y:2}
obj.hasOwnProperty('x')
// hasOwnProperty()用来检测是否是对象的自有属性,不会查找原型属性的
复制代码
(3)propertyIsEnumerable()是hasOwnProperty()的增强版,只有检测到自有属性且这个属性的可枚举性为true的时候,才返回true
7,枚举属性
枚举属性: for-in 循环。
for-in循环可以在循环体中遍历对象中所有可枚举的属性,包括自有属性和继承属性,把属性名称赋值给循环变量,切记:对象继承的内置方法不可枚举
var obj = { x:1, y:2, z:3}; // 三个都是可枚举的属性
obj.propertyIsEnumerabel('toString') // =>false 不可枚举
for(item in obj) {
console.log(item) // 输出:x,y,z,没有toString
}
// 切记: 对象继承的内置方法是不可枚举的
for(item in obj){
if(!obj.hasOwnProperty('item')
continue; // 跳过继承的属性
}
for(item in obj) {
if(typeof obj[item] === 'function') {
continue; // 跳过方法
}
}
复制代码
除了for-in循环之外,还有两个方法
(1)Object.keys(), 返回一个数组,这个数组有对象中可枚举的自有属性的名称组成
(2)Object.getOwnPropertyNames() 返回数组,只是它返回对象的所有自有属性的名称,而不仅仅是可枚举的属性,还包括不可枚举属性
8,属性getter和setter
对象属性是由名字,值,和一组特性构成。属性值可以用一个或者两个方法替代,这两个方法就是getter,和setter,简称“存取器属性”。
数据属性只有一个简单的值。
和数据属性一样,存取器属性也是可以继承的
9,属性的特性
可以认为一个属性包含:一个名字和4个特性。
- 数据属性4个特性:值(value),可写性(writable),可枚举性,可配置性
- 存取器属性:取(get),写入(set),可枚举性,可配置性
为了实现属性特性的查询和设置操作,ES5定义了‘属性描述符’对象
数据属性的描述符对象属性有:value, writable, enumerable, configurable
存取器属性的描述符对象属性:get, set, enumerable, configurable
通过调用Object.getOwnPropertyDescriptor() 可获取特定属性的属性描述符
var obj = { x:1, y:2, z:3};
console.log(Object.getOwnPropertyDescriptor(obj, 'x'))
// 返回: {value:1, writable:true, enumerable:true, configurable: true}
复制代码
存取器属性:{set: undefined,get:function,enumerable:true,configurable:true} Object.getOwnPropertyDescriptor()只能得到自有属性,
要想获得继承属性的特性,需要遍历原型链:用Object.getPrototypeOf()
想要设置属性特性,或者新建属性具有什么特性:用Object.definePeoperty()
var obj = {};
Object.defineProperty(obj, 'x',{
value: 'zlm',
writable: true, // 可编辑
enumerable: false, //不可枚举
configurable: true
})
console.log(obj.x) // => zlm 属性是存在的
console.log(Object.keys(obj)) // =>[] 不可枚举,所以输出空数组 []
Object.defineProperty(obj,'x', {
writable:false
})
obj.x = 222;
console.log(obj.x) // =>zlm,值没有改变,因为是不可写入
Object.defineProperty(obj, 'x',{
value: 444
})
console.log(obj.x) // =>444 属性依然可配置,所以值可以修改
Object.defineProperty(obj, 'x', {
get: function() {
return 555;
}
})
console.log(obj.x) // =>555 将x从数据属性修改为存取器属性
复制代码
注意:Object.defineProperty()不能修改继承属性,同时要修改或创建多个属性,使用:Object.defineProperties()
// 第一个参数是:要修改的对象
// 第二个参数是:一个映射表,包含新建或者修改的属性名称和属性描述符
var p = Object.defineProperties({},{
x: {value:1,writable:true,enumerable:true,configurable:true},
y: {value:2,writable:true,enumerable:true,configurable:true},
z: {
get: function() { return this.x * this.x + this.y *this.y },
enumerable:true,
configurable: true
}
})
console.log(p.x , p.y , p.z)
复制代码
属性特性的复制
Object.defineProperty(Object.prototype, 'extentd', {
writable:true,
enumerable: false,
configurable:true,
value: function(o) {
//遍历o对象中所有的自有属性
var names = Object.getOwnPropertyNames(o)
for(var i =0; i< names.length; i++) {
if(names[i] in this) continue
// 获取o中的属性的描述符
var desc = Object.getOwnPropertyDescriptor(names[i])
// 给当前对象创建同样的属性描述符
Object.defineProperty(this,names[i],desc)
}
}
})
复制代码
10,对象的是三个属性
- 原型
- 类
- 可扩张性
(1)原型属性是在实例对象创建之初就设置好的,
通过对象直接量创建的对象,原型是:Object.prototype()
通过new创建的对象:原型:构成函数.prototype
通过Object.create()创建的对象,原型是:第一个参数
想要检测一个对象是否是另一个对象的原型,通过:isPrototypeOf()方法
例如:p.isPrototypeOf(o) 检测p是否是o的原型
(2)类的属性
获取对象的类方法:调用对象的toString()方法,提取第8个和倒数第二位的字符
function classof(o) {
if(o === null) return "NULL";
if(p === undefined) return "Undefined";
return Object.prototype.toString.call(o).slice(8, -1)
}
classof({})
classof(null)
classof("")
classof(false)
classof([])
classof(new Date())
classof(/,/)
classof(window)
复制代码
(3)对象的可扩展性表示是否可以给对象添加新属性,所有内置对象和自定义对象都是显示可扩展的
ES5提供了可以用来查询和设置对象的可扩展性函数:Object.esExtensible()
设置对象为不可扩展,封闭的:Object.preventExtensions(),Object.seal()
检测对象是否封闭:Object.isSealed()
更严格的锁定对象,冻结:Object.freeze()
检测对象是否冻结:Object.isFrozen()
11,对象的序列化
对象的序列化是指:将对象的状态转换为字符串,也可将字符串还原为对象 ES5提供了内置函数:JSON.stringify() 用来序列化,JSON.parse()还原对象