对象属性的特性对象
在ES3.1中,只要对象能被访问,我们就可以任意操作对象。例如: 添加属性、 删除属性、修改值
在ES3.1中, 对象的属性的可访问性永远是true
在ES5中,对象变得更严格了。 利用某种方式设置了对象属性的可访问性。
其中就是利用“特性”来控制对象属性的可访问性。
Object.defineProperty()
作用: 用于设置对象的单个属性特性。
使用方式:Object.defineProperty(obj, property, options)
参数:
obj: 要设置的对象
property: 要设置的属性名
options: 描述特性对象
特性值
ECMAScript 中有两种属性:数据属性 和 访问器属性
1. 数据属性 configurable enumerable writable value
数据属性包含一个数据值的位置。在这个位置可以读取和写入值。数据属性有 4 个描述其行为的特性。
[[Configurable]] :表示能否通过 delete 删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性。像前面例子中那样直接在对象上定义的属性,它们的这个特性默认值为 true 。
注意:
当配置了configurable为false之后,
① 如果同时设置writable为false, 将不可以再次修改writable为true
② 如果同时设置writable为true,将可以再次修改writable为false
③ 不论设不设置enumerable, 都不可以再次修改enumerable
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<script type="text/javascript">
// ES5
var obj = {
color: "blue"
}
// 定义特性
Object.defineProperty(obj, "color", {
//可配置性 false
configurable: false,
// 设置可修改性为false
writable: false
})
//当配置了configurable为false之后,如果同时设置writable为false, 将不可以再次修改writable为true
// 会报错 不能修改 writable特性的值
Object.defineProperty(obj, "color", {
// 设置可修改性为false
writable: true
})
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<script type="text/javascript">
// ES5
var obj = {
color: "blue"
}
// 定义特性
Object.defineProperty(obj, "color", {
//可配置性 false
configurable: false,
// 设置可修改性为false
writable: true
})
//当配置了configurable为false之后,如果同时设置writable为true, 将可以再次修改writable为false
// 不会报错 不能修改 writable特性的值
Object.defineProperty(obj, "color", {
// 设置可修改性为false
writable: false
})
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<script type="text/javascript">
// ES5
var obj = {
color: "blue"
}
// 定义特性
Object.defineProperty(obj, "color", {
//可配置性 false
configurable: false,
// 设置可修改性为false
enumerable: true
})
//当配置了configurable为false之后,不论设不设置enumerable, 都不可以再次修改enumerable
// 会报错 不能修改 enumerable特性的值
Object.defineProperty(obj, "color", {
// 设置可修改性为false
enumerable: false
})
</script>
</body>
</html>
[[Enumerable]] :表示能否通过 for-in 循环返回属性。像前面例子中那样直接在对象上定义的属性,它们的这个特性默认值为 true 。
[[Writable]] :表示能否修改属性的值。像前面例子中那样直接在对象上定义的属性,它们的这个特性默认值为 true 。
[[Value]] :包含这个属性的数据值。读取属性值的时候,从这个位置读;写入属性值的时候,把新值保存在这个位置。这个特性的默认值为 undefined 。
知识点:
在调用 Object.defineProperty() 方法时 或者 使用ES5定义属性的值时,如果不指定,configurable 、 enumerable 和writable 特性的默认值都是 false。
如果使用ES3定义属性的值是,默认所有的特性都true。
2. 访问器属性 set get
访问器属性不包含数据值;它们包含一对儿 getter 和 setter 函数(不过,这两个函数都不是必需的)。在读取访问器属性时,会调用 getter 函数,这个函数负责返回有效的值;在写入访问器属性时,会调用setter 函数并传入新值,这个函数负责决定如何处理数据。访问器属性有如下 4 个特性。
[[Configurable]] :表示能否通过 delete 删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为数据属性。对于直接在对象上定义的属性,这个特性的默认值为true 。
[[Enumerable]] :表示能否通过 for-in 循环返回属性。对于直接在对象上定义的属性,这个特性的默认值为 true 。
[[Get]] :在读取属性时调用的函数。默认值为 undefined 。
[[Set]] :在写入属性时调用的函数。默认值为 undefined
注意:
定义了get set 当我们设置属性obj.属性= "xxx" 会触发set函数,当我们读取属性 obj.属性, 读取的时候会触发get函数。
不一定非要同时指定 getter 和 setter。只指定 getter 意味着属性是不能写,尝试写入属性会被忽略。在严格模式下,尝试写入只指定了 getter 函数的属性会抛出错误。类似地,只指定 setter 函数的属性也不能读,否则在非严格模式下会返回 undefined ,而在严格模式下会抛出错误。
如果要设置和读取 我们要备份属性值即可,前面的下划线是一种常用的记号,用于表示只能通过对象方法访问的属性
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<script type="text/javascript">
// 定义对象
// var obj = {
// color: "red"
// }
// // 一旦定义了get set 当我们obj.color = "xxx" 会触发set函数,
// // 当我们obj.color, 读取的时候会触发get函数。
// Object.defineProperty(obj, "color", {
// get: function() {
// console.log("要获取值了")
// console.log(this === obj);
// return this.color; // 一旦这么干, 就会死循环
// },
// set: function(value) {
// console.log("要设置值了");
// console.log(this === obj);
// return this.color = value; // 一旦这么干, 就会死循环
// }
// })
var obj = {
color: "red"
}
Object.defineProperty(obj, "color", {
get: function() {
// 备份属性值
console.log("读取完成")
return this._color;
},
set: function(value) {
// 设置备份属性值
console.log("设置完成")
return this._color = value; // 一旦这么干, 就会死循环
}
})
</script>
</body>
</html>
定义多个属性 Object.defineProperties()
ECMAScript 5 又定义了一个 Object.defineProperties() 方法。利用这个方法可以通过描述符一次定义多个属性。
这个方法接收两个对象参数:
第一个对象是要添加和修改其属性的对象
第二个对象的属性与第一个对象中要添加或修改的属性一一对应
var obj = {};
Object.defineProperties(obj, {
'property1': {
value: true,
writable: true
},
'property2': {
value: 'Hello',
writable: false
}
});
var book = {};
Object.defineProperties(book, {
_year: {
value: 2004
},
edition: {
value: 1
},
year: {
get: function(){
return this._year;
},
set: function(newValue){
if (newValue > 2004) {
this._year = newValue;
this.edition += newValue - 2004;
}
}
}
}); //以上代码在 book 对象上定义了两个数据属性( _year 和 edition )和一个访问器属性( year )
读取属性的特性
使用 ECMAScript 5 的 Object.getOwnPropertyDescriptor() 方法,可以取得给定属性的描述符。
这个方法接收两个参数:属性所在的对象 和 要读取其描述符的属性名称。
使用方式:Object.getOwnPropertyDescriptor(obj, 属性名)
返回值是一个对象,如果是访问器属性,这个对象的属性有 configurable 、 enumerable 、 get 和 set ;如果是数据属性,这个对象的属性有 configurable 、 enumerable 、 writable 和 value。
var o, d;
o = { get foo() { return 17; } };
d = Object.getOwnPropertyDescriptor(o, "foo");
// d {
// configurable: true,
// enumerable: true,
// get: /*the getter function*/,
// set: undefined
// }
o = { bar: 42 };
d = Object.getOwnPropertyDescriptor(o, "bar");
// d {
// configurable: true,
// enumerable: true,
// value: 42,
// writable: true
// }
o = {};
Object.defineProperty(o, "baz", {
value: 8675309,
writable: false,
enumerable: false
});
d = Object.getOwnPropertyDescriptor(o, "baz");
// d {
// value: 8675309,
// writable: false,
// enumerable: false,
// configurable: false
// }