1. 对象属性值
1.1. 所有属性都有名称, 此外它们还有值。
1.2. 值是属性的特性之一。
1.3. 其他特性包括: 可枚举、可配置、可写。
1.4. 在JavaScript中, 所有属性都是可读的, 但是只有属性可写时才可修改的。
2. Object.defineProperty()方法
2.1. Object.defineProperty(obj, prop, descriptor)方法会直接在一个对象上定义一个新属性, 或者修改一个现有属性, 并返回此对象。
2.2. 参数
2.2.1. obj: 要定义属性的对象。
2.2.2. prop: 要定义或修改的属性的名称。
2.2.3. descriptor: 要定义或修改的属性描述符。
2.3. 对象里目前存在的属性描述符有两种主要形式: 数据描述符和存取描述符。一个描述符只能是这两者其中之一, 不能两者同时存在。
2.4. 这两种描述符都是对象。它们共享以下可选键值:
2.4.1. configurable: 属性是否可重新配置。当且仅当该属性的configurable键值为true时, 该属性的描述符才能够被改变, 同时该属性也能从对应的对象上被删除(可以使用delete运算符删除属性从而重新定义属性)。默认为false。
2.4.2. enumerable: 属性可枚举(用到for...in或Object.keys方法)。默认为false。
2.5. 数据描述符具有以下可选键值:
2.5.1. value: 与属性关联的值。默认为undefined。
2.5.2. writable: 属性是否可写。当且仅当该属性的writable键值为true时, 属性的值, 也就是上面的value, 才能被赋值运算符改变。默认为false。
2.6. 存取描述符还具有以下可选键值:
2.6.1. get: 属性的getter函数, 如果没有getter, 则为undefined。当访问该属性时, 会调用此函数。执行时不传入任何参数, 但是会传入this对象(由于继承关系, 这里的this并不一定是定义该属性的对象)。该函数的返回值会被用作属性的值。默认为undefined。
2.6.2. set: 属性的setter函数, 如果没有setter, 则为undefined。当属性值被修改时, 会调用此函数。该方法接受一个参数(也就是被赋予的新值), 会传入赋值时的this对象。默认为undefined。
3. Object.defineProperties()方法
3.1. Object.defineProperties(obj, props)方法直接在一个对象上定义新的属性或修改现有属性(可以是多个属性), 并返回该对象。
3.2. 参数
3.2.1. obj: 要定义属性的对象。
3.2.2. props: 要定义或修改的属性和描述符的集合(更多详情, 请参阅Object.defineProperty())。
4. Object.getOwnPropertyDescriptor()方法
4.1. Object.getOwnPropertyDescriptor(obj, prop)方法返回指定对象上一个自有属性(自有属性指的是直接赋予该对象的属性, 不需要从原型链上进行查找的属性)对应的属性描述符。
4.2. 参数
4.2.1. obj: 需要查找的目标对象。
4.2.2. prop: 目标对象内属性名称。
4.3. 返回值
4.3.1. 如果指定的属性存在于对象上, 则返回其属性描述符对象(property descriptor), 否则返回undefined。
5. Object.getOwnPropertyDescriptors()方法
5.1. Object.getOwnPropertyDescriptors(obj)方法用来获取一个对象的所有自身属性的描述符。
5.2. 参数
5.2.1. obj: 任意对象
5.3. 返回值
5.3.1. 所指定对象的所有自身属性的描述符, 如果没有任何自身属性, 则返回空对象。
5.4. 例子
5.4.1. 代码
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Object.defineProperty()、Object.defineProperties()、Object.getOwnPropertyDescriptor()和Object.getOwnPropertyDescriptors()方法</title>
</head>
<body>
<script type="text/javascript">
var person = {};
Object.defineProperty(person, "_language_", {enumerable: false, configurable: true, value: "en", writable: true});
Object.defineProperties(person, {
"id": {enumerable: true, configurable: false, value: 1001, writable: true},
"name": {enumerable: true, configurable: false, value: 'zhang san', writable: false},
"age": {enumerable: true, configurable: true, value: 18, writable: true},
"address": {enumerable: true, configurable: true, value: "bei jing", writable: false},
"telephone": {enumerable: true, configurable: false, value: 13552460001, writable: true},
"sex": {enumerable: true, configurable: false, value: 'female', writable: true}
});
var descriptorss = Object.getOwnPropertyDescriptors(person);
for(let key in descriptorss) {
document.write(key + ': ');
for(let item in descriptorss[key]) {
document.write(item + ': ' + descriptorss[key][item] + '\t');
}
document.write('<br />');
}
document.write('<hr />');
// writable为true, 才可以通过赋值运算符重新赋值
person.id = 1002; // 赋值成功
person.name = '张三'; // 赋值失败
person.age = 16; // 赋值成功
person.address = '河南'; // 赋值失败
person.telephone = 13552460002; // 赋值成功
person.sex = 'male'; // 赋值成功
for(let item in person) {
document.write(item + ': ' + person[item] + '<br />');
}
document.write('<hr />');
// configurable为true, 才可以修改描述符
Object.defineProperty(person, "address", {enumerable: true, configurable: false, value: "洛阳", writable: true});
Object.defineProperty(person, "Language", {enumerable: false, configurable: false, get: function(){return this._language_;}, set: function(newValue){this._language_ = newValue;}});
document.write(person.Language + '<br />');
person.Language = 'zh';
document.write(person.Language + '<hr />');
var descriptors1 = Object.getOwnPropertyDescriptors(person);
for(let key in descriptors1) {
document.write(key + ': ');
for(let item in descriptors1[key]) {
document.write(item + ': ' + descriptors1[key][item] + '\t');
}
document.write('<br />');
}
document.write('<hr />');
// configurable为false, writable为true, 可以value数据描述符
Object.defineProperty(person, "id", {enumerable: true, configurable: false, value: 1003, writable: true});
// configurable为false, 不能修改enumerable描述符
try {
Object.defineProperty(person, "telephone", {enumerable: false, configurable: false, value: 13552460002, writable: true});
} catch (e) {
document.write(e + '<hr />');
}
// configurable为true, 才可以删除属性
delete person.id; // 删除失败
delete person.name; // 删除失败
delete person.age; // 删除成功
delete person.language; // 删除失败
delete person.address; // 删除失败
delete person.telephone; // 删除失败
delete person.sex; // 删除失败
var descriptors2 = Object.getOwnPropertyDescriptors(person);
for(let key in descriptors2) {
document.write(key + ': ');
for(let item in descriptors2[key]) {
document.write(item + ': ' + descriptors2[key][item] + '\t');
}
document.write('<br />');
}
document.write('<hr />');
var descriptors = Object.getOwnPropertyDescriptor(person, 'name');
for(let item in descriptors) {
document.write(item + ': ' + descriptors[item] + '<br />');
}
</script>
</body>
</html>
5.4.2. 效果图
6. Object.create()方法
6.1. Object.create(proto, [propertiesObject])方法创建一个新对象, 使用现有的对象来提供新创建的对象的__proto__。返回一个新对象, 带着指定的原型对象和属性。
6.2. 参数
6.2.1. proto: 新创建对象的原型对象。
6.2.2. propertiesObject: 可选。需要传入一个对象, 该对象的属性类型参照Object.defineProperties()的第二个参数。如果该参数被指定且不为undefined, 该传入对象的自有可枚举属性(即其自身定义的属性, 而不是其原型链上的枚举属性)将为新创建的对象添加指定的属性值和对应的属性描述符。
6.3. 例子
6.3.1. 代码
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Object.create()方法</title>
</head>
<body>
<script type="text/javascript">
// 创建一个原型为null的空对象
var emptyObj = Object.create(null);
var textObj = {};
// 以文本方式创建的空对象就相当于
var obj = Object.create(Object.prototype);
// 以对象作为新对象的原型
var person = {id: 1001, name: 'zs', print: function(){return '[id: ' + this.id + ', name: ' + this.name + ']';}};
var personObj = Object.create(person);
document.write(personObj.print() + '<br />');
// create实现继承
function Shape(x, y) {
this.x = x;
this.y = y;
}
Shape.prototype.move = function(x, y) {
this.x += x;
this.y += y;
};
function Rectangle(x, y) {
Shape.call(this, x, y);
}
Rectangle.prototype = Object.create(Shape.prototype);
var rect = new Rectangle(7, 8);
document.write('rect对象是Rectangle类的实例: ' + (rect instanceof Rectangle) + '<br />');
document.write('rect对象是Shape类的实例: ' + (rect instanceof Shape) + '<br />');
document.write('Rectangle.prototype对象在rect对象的原型链上: ' + (Rectangle.prototype.isPrototypeOf(rect)) + '<br />');
document.write('Shape.prototype对象在rect对象的原型链上: ' + (Shape.prototype.isPrototypeOf(rect)) + '<br />');
rect.move(1, 1);
document.write('x = ' + rect.x + ', y = ' + rect.y + '<br />');
// 创建一个带属性的对象
var paramObj = Object.create(Object.prototype, {
foo: {
enumerable: true,
writable: true,
configurable: true,
value: "foofoo"
},
bar: {
enumerable: true,
configurable: true,
value: "barbar"
}
});
for(let item in paramObj) {
document.write(item + ': ' + paramObj[item] + '<br />');
}
</script>
</body>
</html>
6.3.2. 效果图
7. Object.getOwnPropertyNames()方法
7.1. Object.getOwnPropertyNames(obj)方法返回一个由指定对象的所有自身属性的属性名(包括不可枚举属性, 不包括原型上的属性)组成的数组。
7.2. 参数
7.2.1. obj: 需要查找的目标对象。
7.3. 返回值
7.3.1. 在给定对象上找到的自身属性对应的字符串数组。
8. Object.keys()方法
8.1. Object.keys(obj)方法会返回一个由给定对象的自身可枚举属性组成的数组, 数组中属性名的排列顺序和正常循环遍历该对象时返回的顺序一致。
8.2. 参数
8.2.1. obj: 需要查找的目标对象。
8.3. 返回值
8.3.1. 一个表示给定对象的所有可枚举属性的字符串数组。
9. Object.getPrototypeOf()方法
9.1. Object.getPrototypeOf(obj)方法返回指定对象的原型。
9.2. 参数
9.2.1. obj: 需要查找的目标对象。
10. Object.setPrototypeOf()方法
10.1. Object.setPrototypeOf(obj, prototype)方法设置一个指定的对象的原型到另一个对象或null。
10.2. 参数
10.2.1. obj: 要设置其原型的对象。
10.2.2. prototype: 该对象的新原型(一个对象或null)。
10.3. 警告: 由于现代JavaScript引擎优化属性访问所带来的特性的关系, 更改对象的[[Prototype]]在各个浏览器和JavaScript引擎上都是一个很慢的操作。其在更改继承的性能上的影响是微妙而又广泛的, 这不仅仅限于 obj.__proto__ = ... 语句上的时间花费, 而且可能会延伸到任何代码, 那些可以访问任何[[Prototype]]已被更改的对象的代码。如果你关心性能, 你应该避免设置一个对象的[[Prototype]]。相反, 你应该使用 Object.create()来创建带有你想要的[[Prototype]]的新对象。
11. Object.preventExtensions()方法
11.1. Object.preventExtensions(obj)方法让一个对象变的不可扩展, 也就是永远不能再添加新的属性。
11.2. 参数
11.2.1. obj: 将要变得不可扩展的对象。
11.3. 返回值
11.3.1. 已经不可扩展的对象。
11.4. 如果一个对象可以添加新的属性, 则这个对象是可扩展的。Object.preventExtensions()将对象标记为不再可扩展, 这样它将永远不会具有它被标记为不可扩展时持有的属性之外的属性。注意, 一般来说, 不可扩展对象的属性可能仍然可被删除。尝试将新属性添加到不可扩展对象将抛出TypeError。
11.5. Object.preventExtensions()仅阻止添加自身的属性。但其对象类型的原型依然可以添加新的属性。
11.6. 该方法使得目标对象的[[prototype]]本身不可变; 任何重新赋值[[prototype]]操作都会抛出TypeError。但原型的属性可以修改。
12. Object.isExtensible(object)方法
12.1. Object.isExtensible(object)方法判断一个对象是否是可扩展的(是否可以在它上面添加新的属性)。
12.2. 参数
12.2.1. obj: 需要查找的目标对象。
12.3. 返回值
12.3.1. 表示给定对象是否可扩展的一个Boolean。
13. Object.seal()方法
13.1. Object.seal(obj)方法封闭一个对象, 阻止添加新属性并将所有现有属性标记为不可配置。当前属性的值只要原来是可写的就可以改变。此外, 封闭一个对象后该对象的原型本身不能被修改, 但原型的属性可以修改。
13.2. 参数
13.2.1. obj: 需要查找的目标对象。
14. Object.isSealed()方法
14.1. Object.isSealed(obj)方法判断一个对象是否被密封。
14.2. 参数
14.2.1. obj: 需要查找的目标对象。
14.3. 返回值
14.3.1. 表示给定对象是否被密封的一个Boolean 。
15. Object.freeze(object)方法
15.1. Object.freeze(object)方法可以冻结一个对象。一个被冻结的对象再也不能被修改。冻结了一个对象则不能向这个对象添加新的属性, 不能删除已有属性, 不能修改该对象已有属性的可枚举性、可配置性、可写性, 以及不能修改已有属性的值。此外, 冻结一个对象后该对象的原型本身不能被修改, 但原型的属性可以修改。如果一个属性的值是个对象, 则这个对象中的属性是可以修改的, 除非它也是个冻结对象(浅冻结)。
15.2. 参数
15.2.1. obj: 要被冻结的对象。
15.3. 返回值
15.3.1. 返回和传入的参数相同的被冻结的对象。
16. Object.isFrozen()方法
16.1. Object.isFrozen(object)方法判断一个对象是否被冻结。
16.2. 参数
16.2.1. obj: 需要查找的目标对象。
16.3. 返回值
16.3.1. 表示给定对象是否被冻结的Boolean。
16.4. 一个空对象, 设置为不可扩展或密封, 也是一个冻结对象。
17. 例子
17.1. 代码
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Object对象方法</title>
</head>
<body>
<script type="text/javascript">
var person = Object.create(Object.prototype);
Object.defineProperty(person, "language", {enumerable: true, configurable: true, value: "en", writable: true});
Object.defineProperties(person, {
"id": {enumerable: true, configurable: true, value: 1001, writable: true},
"name": {enumerable: true, configurable: true, value: 'zhang san', writable: true},
"age": {enumerable: true, configurable: true, value: 18, writable: true},
"address": {enumerable: true, configurable: true, value: "bei jing", writable: true},
"telephone": {enumerable: true, configurable: true, value: 13552460001, writable: true},
"sex": {enumerable: false, configurable: true, value: 'female', writable: true}
});
for(let item in person) {
document.write(item + ': ' + person[item] + '<br />');
}
document.write('<hr />');
// Object.getOwnPropertyNames()方法返回一个由指定对象的所有自身属性的属性名(包括不可枚举属性, 不包括原型上的属性/方法)组成的数组
person.__proto__.run = function(){
document.write('我会跑的.' + '<br />');
};
document.write(Object.getOwnPropertyNames(person) + '<br />');
document.write('<hr />');
// Object.keys()方法会返回一个由给定对象的自身可枚举属性组成的数组
document.write(Object.keys(person) + '<br />');
document.write('<hr />');
// Object.getPrototypeOf()方法返回指定对象的原型
var prototype = Object.getPrototypeOf(person);
prototype.myToString = function(){
return '[id=' + this.id + ',name=' + this.name + ',age=' + this.age + ',address=' + this.address + ',telephone=' + this.telephone + ',sex=' + this.sex + ',language=' + this.language + ']';
};
document.write(person.myToString() + '<br />');
// Object.setPrototypeOf()方法设置一个指定的对象的原型到另一个对象或null
Object.setPrototypeOf(person, null);
Object.setPrototypeOf(person, Object.prototype);
document.write('<hr />');
// Object.preventExtensions()方法让一个对象变的不可扩展, 也就是永远不能再添加新的属性。
document.write('person是否可扩展: ' + Object.isExtensible(person) + '<br />');
Object.preventExtensions(person);
document.write('person是否可扩展: ' + Object.isExtensible(person) + '<br />');
try {
// 对象设置为不可扩展, 添加新属性抛异常
Object.defineProperty(person, "weight", { value: 8675309 });
} catch(e) {
document.write(e + '<br />');
}
// 对象设置为不可扩展, 可以给原型上添加方法
person.__proto__.eat = function(){
document.write('我会吃的.' + '<br />');
};
// 对象设置为不可扩展, 赋值的方式添加新属性, 添加不上, 无异常
person.height = 177;
try {
// 对象设置为不可扩展, 设置新的原型抛异常
Object.setPrototypeOf(person, null);
} catch(e) {
document.write(e + '<br />');
}
// 对象设置为不可扩展, 还可以重新配置属性
Object.defineProperty(person, "language", {writable: false});
// 对象设置为不可扩展, 属性还可以是可写的
person.name = '张三';
// 对象设置为不可扩展, 属性还可以是可删除的(可重新配置)
delete person.sex;
delete person.__proto__.myToString;
document.write('<hr />');
var descriptors1 = Object.getOwnPropertyDescriptors(person);
for(let key in descriptors1) {
document.write(key + ': ');
for(let item in descriptors1[key]) {
document.write(item + ': ' + descriptors1[key][item] + '\t');
}
document.write('<br />');
}
document.write('<hr />');
// Object.seal()方法封闭一个对象, 阻止添加新属性并将所有现有属性标记为不可配置。当前属性的值只要原来是可写的就可以改变
document.write('person是否密封: ' + Object.isSealed(person) + '<br />');
Object.seal(person);
document.write('person是否密封: ' + Object.isSealed(person) + '<br />');
// 对象设置为密封, 不能删除属性
delete person.telephone;
// 原型链上的方法可删除(同时, 原型链上还是可以添加和修改方法的)
delete person.__proto__.run;
// 对象设置为密封, 可以给原型上添加方法
person.__proto__.drank = function(){
document.write('我会喝的.' + '<br />');
};
try {
// 对象设置为密封, 不可以重新配置属性
Object.defineProperty(person, "language", {enumerable: false, configurable: false, writable: false});
} catch(e) {
document.write(e + '<br />');
}
// 对象设置为密封, 属性可写
person.id = '1002';
Object.defineProperty(person, "address", {value: "河北"});
document.write('<hr />');
var descriptors2 = Object.getOwnPropertyDescriptors(person);
for(let key in descriptors2) {
document.write(key + ': ');
for(let item in descriptors2[key]) {
document.write(item + ': ' + descriptors2[key][item] + '\t');
}
document.write('<br />');
}
document.write('<hr />');
// Object.freeze()方法可以冻结一个对象
document.write('person是否冻结: ' + Object.isFrozen(person) + '<br />');
Object.freeze(person);
document.write('person是否冻结: ' + Object.isFrozen(person) + '<br />');
// 一个空对象, 设置为不可扩展或密封, 也是一个冻结对象
var emptyObj1 = {};
document.write('emptyObj1是否冻结: ' + Object.isFrozen(emptyObj1) + '<br />');
Object.preventExtensions(emptyObj1);
document.write('emptyObj1是否冻结: ' + Object.isFrozen(emptyObj1) + '<br />');
var emptyObj2 = {};
document.write('emptyObj2是否冻结: ' + Object.isFrozen(emptyObj2) + '<br />');
Object.seal(emptyObj2);
document.write('emptyObj2是否冻结: ' + Object.isFrozen(emptyObj2) + '<br />');
// 对象设置为冻结, 不能删除属性
delete person.address;
// 原型链上的方法可删除(同时, 原型链上还是可以添加和修改方法的)
delete person.__proto__.eat;
try {
// 对象设置为冻结, 属性不可写
Object.defineProperty(person, "address", {value: "洛阳", writable: true});
} catch(e) {
document.write(e + '<br />');
}
document.write('<hr />');
var descriptors3 = Object.getOwnPropertyDescriptors(person);
for(let key in descriptors3) {
document.write(key + ': ');
for(let item in descriptors3[key]) {
document.write(item + ': ' + descriptors3[key][item] + '\t');
}
document.write('<br />');
}document.write('<br />');
</script>
</body>
</html>
17.2. 效果图