对象的属性特性 (property attribute)
- 可写 (writable attribute), 表明是否可以设置该属性的值
- 可枚举 (enumerable attribute), 表明是否可以通过for/in循环返回该属性
- 可配置 (configurable attribute),表明是否可以删除或修改该属性
对象特性 (object attribute)
- 对象的原型 (prototype) 指向另外一个对象,本对象的属性继承自它的原型对象
- 对象的类 (class)是一个标识对象类型的字符串
- 对象的扩展标记 (extensible flag)指明了是否可以向该对象添加新属性
1.三种方式
- 对象字面量方式
- 通过new方式创建
- Object.create() ES5
// 这样创造出来的对象是和字面量和new Object()的方式是一样的,都继承自Object.prototype
var o = Object.create(Object.prototype);
Object.getPrototypeOf(o); // 返回 Object.prototype , 包含像 toString(), valueOf等方法
// 创建一个空对象,不继承任何对象
var o1 = object.create(null);
Object.getPrototypeOf(o1); // 返回null
2.原型继承
function inherit(p) {
if(p == null) throw TypeError();
if(Object.create) return Object.create(p);
var t = typeof p;
if(t !== "object" && t !== "function") throw TypeError();
function F(){};
F.prototype = p;
return new F();
}
var o1 = Object.create({x:1})
和 Object.x = 1;var o2 = Object.create(Object.prototype)
的区别??? (注意 __proto__
)
** __proto__
is the actual object that is used in the lookup chain to resolve methods, etc. prototype is the object that is used to build __proto__
when you create an object with new: **
( new Foo ).__proto__ === Foo.prototype
( new Foo ).prototype === undefined
3.对象自有属性和继承属性(继承自原型上的属性) 如果对象自有属性和继承属性同名,会访问自有属性,所以我们可以有选择的覆盖继承属性,而不修改继承属性。
- in运算符
- hasOwnProperty()
- propertyIsEnumerable()
var o = {x:1};
"x" in o; // true: “x”是o的属性
"y"in o; //false: "y"不是o的属性
"toString" in o; //true o继承 toString属性
var o = {x:1};
o.hasOwnProperty("x"); //true: o有一个自有属性x
o.hasOwnProperty("y"); //false: y不是o的自有属性
o.hasOwnProperty("toString") //false toString是继承的属性
propertyIsEnumerable是hasOwnProperty()的增强版,只有检测到是自有属性且这个属性可以被枚举
for/in循环可以遍历对象中所有可以枚举的属性(包括自有属性和继承的属性)
for(p in o){
if(!o.hasOwnProperty(p)) continue; //跳过继承属性
}
for(p in o){
if(typeof o[p] === 'function') continue; //跳过函数
}
P131 用来枚举对象的工具函数 lodash中是否有对应的方法
ES5 Object.keys
返回对象中可枚举的自有属性的名称组成的数组
ES5 Object.getOwnPropertyNames
返回所有自有属性的名称,而不仅仅是可枚举的
数据的4个特性 值(value) 可写性(writable) 可枚举性(enumerable) 可配置性(configurable) 两类属性:
- 数据属性-> 值 可写性 可枚举性 可配置性
- 存取器属性-> get set 可枚举性 可配置性
可以通过 Object.getOwnPropertyDescriptor 查找属性特性的描述符 改方法只能得到自有属性的描述符,如果需要进一步查找继承属性的描述符 需要使用 Object.getPrototypeOf() 方法遍历原型链
Object.getOwnPropertyDescriptor({x:1}, 'x');
//Object {value: 1, writable: true, enumerable: true, configurable: true}
Object.getOwnPropertyDescriptor(Object, 'prototype');
//Object {value: Object, writable: false, enumerable: false, configurable: false}
var o = {
n: 0,
get num(){
return n;
},
set num(value){
this.n = value;
}
}
Object.getOwnPropertyDescriptor(o, 'num');
/*
configurable: true
enumerable: true
get: num()
set: num(value)
__proto__: Object
*/
如果想要修改对象属性的描述符,需要使用Object.defineProperty()方法
var o = {};
Object.defineProperty(o, "x", {value: 1, writable: true, enumerable: false, configurable: true});
o.x
Object.keys(o) //[]
//修改让其变成只读
Object.defineProperty(o, "x", {writable: false});
o.x = 10; //修改失败,但不报错,严格模式下报错
o.x //1
Object.defineProperties()
var p = Object.defineProperties({},{
x: {value: 1, writable: true, enumerable: false, configurable: true},
y: {value: 1, writable: true, enumerable: false, configurable: true},
r: {
get: function(){
return Math.sqrt(this.x*this.x + this.y*this.y);
},
enumerable: false,
configurable: true
}
});
p.r;
Object.defineProperty 和 Object.defineProperties 的规则 违反规则使用会抛出类型错误
- 如果对象是不可扩展的,则可以编辑已有的自有属性,但是不能给它添加新属性
- 如果属性是不可配置的,则不能修改它的可配置性和可枚举性
- 如果存取器属性是不可配置的,则不能修改其getter和setter方法,也不能将它转换为数据属性
- 如果数据属性是不可配置的,则不能将它转换成为存取器属性
- 如果数据属性是不可配置的,则不能将它的可写性从false修改为true,但是可以从true改为false
- 如果数据属性是不可配置的且不可写的,则不能修改它的值。然而可配置但不可写属性值是可以修改的。
复制属性的特性
Object.defineProperty(Object.prototype, "extend", {
writable: true,
enumerable: false,
configurable: true,
value: function(o){
var names = Object.getOwnPropertyNames(o);
for(var i=0; i<names.length; i++){
if(names[i] in this) continue;
var desc = Object.getOwnPropertyDescriptor(o, names[i]);
Object.defineProperty(this, names[i], desc);
}
}
});
Object.seal(obj)
Object.frezz()