一、Object.defineProperty(obj, prop, descriptor);
定义或修改对象的一个属性,返回被定义的对象
数据描述符和存取描述符不能同时存在,会产生异常
参数:
- obj:需要定义属性的目标对象
- prop:属性名称
- descriptor:被定义或修改的属性描述符
描述符:
configurable 定义该属性的描述符是否可修改以及该属性是否可 delete;
_通过 defineProperty 方法定义时默认为 false,显示声明赋值定义默认为 true;
_若值为 false,除了writable 可以从 true 改为 false, configurable,enumerable,writable,get,set 都不可再修改;
// 默认属性都为 false,此时 configurable 为 false,其他属性都不可修改
var a = {};
Object.defineProperty(a, 'name', { value: 'june' });
Object.defineProperty(a, 'name', { configurable: true }); // TypeError: Cannot redefine property: name
Object.defineProperty(a, 'name', { enumerable: true }); // TypeError: Cannot redefine property: name
Object.defineProperty(a, 'name', { writable: true }); // TypeError: Cannot redefine property: name
Object.defineProperty(a, 'name', { value: 'july' }); // TypeError: Cannot redefine property: name
// configurable 位 false,writable 可从 true 改为 false,但不可改回去
var a = {};
Object.defineProperty(a, 'name', { configurable: false, writable: true, value: 'june' });
console.log(a.name); // june
a.name = 'july';
console.log(a.name); // july
Object.defineProperty(a, 'name', { writable: false });
a.name = 'june';
console.log(a.name); // july
Object.defineProperty(a, 'name', { writable: true }); // TypeError: Cannot redefine property: name
enumerable 定义该属性是否可被枚举;
_通过 defineProperty 方法定义时默认为 false,显示声明赋值定义默认为 true;
_定义为 false 则不可在 for...in
和 Object.keys()
中被枚举;
var a = {};
Object.defineProperty(a, 'name', { enumerable: true, value: 'june' });
Object.defineProperty(a, 'age', { enumerable: false, value: 17 });
console.log(a); // {name: "june", age: 17}
for(var i in a) {
console.log(a[i]);
}
// june
数据描述符(构造器属性)
writable 定义该属性的值是否能被赋值操作改变;
_通过 defineProperty 方法定义时默认为 false,显示声明赋值定义默认为 true;
_定义为 false 后,试图重新复制会被忽略,不会引发错误;
value 定义该属性的值
_默认为 undefined
存取描述符(访问器属性)
get 给属性提供的 getter 方法;
_该方法的返回值被用作属性值;
_默认为 undefined;
set 给属性提供的 setter 方法;
_该方法接收唯一参数,并将改参数处理后的新值分配给该属性;
_默认为 undefined;
function Obj() {
var _age = 17;
Object.defineProperty(this, 'dbAge', {
get: function() {
return _age;
},
set: function(newVal) {
_age = newVal * 2;
}
})
}
var obj = new Obj();
console.log(obj.dbAge); // 17
obj.dbAge = 10;
console.log(obj.dbAge); // 20
二、Object.defineProperties(obj, props);
批量定义一个对象的属性,返回被定义的对象
参数:
- obj:需要定义属性的目标对象
- 定义属性及其描述符的对象
两种描述符的意思同上
三、Object.create(proto[, propertiesObject])
以指定对象为原型,自定义属性,创建一个新对象
返回新创建的对象
参数
- proto:新对象的原型对象
- propertiesObject:添加到新创建对象上的属性及其描述符,写法对应
Object.defineProperties()
的第二个参数;
注意:
若 proto 参数不是一个 null 或 Object,则抛出一个 TypeError 异常
例子:
单式继承:
function Shape() { // 父类
this.x = 0;
this.y = 0;
}
Shape.prototype.move = function(x, y) {
this.x += x;
this.y += y;
console.info('Shape moved.');
};
function Rectangle() { // 子类
Shape.call(this); // 继承父类实例属性
this.z = 0;
}
Rectangle.prototype = Object.create(Shape.prototype, {
// 以父类原型对象为原型,新添加属性,创建对象
// 相当于父类的空实例,再添加自定义属性
// 将新创建的对象作为子类的原型对象
getRectangle: {
value: function() { console.log('i am getRectangle') },
configurable: true,
enumerable: false,
writable: true
}
});
// 修改子类原型对象的构造函数指向
Rectangle.prototype.constructor = Rectangle;
var rect = new Rectangle();
多个继承:
function Sup1() {
this.sup1 = 'sup1';
}
function Sup2() {
this.sup2 = 'sup2';
}
function Sub() {
Sup1.call(this);
Sup2.call(this);
}
Sub.prototype = Object.create(Sup1.prototype);
// 此处是将第二个父类的原型属性拷贝到子类原型对象,因为是浅拷贝,故虽与第一个父类的继承有点区别,但无伤大雅
Object.assign(Sub.prototype, Sup2.prototype);
Sub.prototype.constructor = Sub;
Sub.prototype.myMethod = function() {
// do some thing
}
Polyfill:
if(typeof Object.create !=="function") {
Object.create = function(proto, propertiesObject) {
if (typeof proto !=='object' && typeof proto !== 'function') {
throw new TypeError('Object prototype may only be an Object: ' + proto);
} else if (typeof proto === null) {
throw new Error("This browser's implementation of Object.create is a shim anddoesn't support 'null' as the first argument.")
}
function F() {};
F.prototype = proto;
return new F();
}
}
1