js中的对象有一些内部才用的特性,这些特性是为了实现javascript引擎用的,因此在javascript中不能直接访问它们。
有两种属性:数据属性 && 访问器属性
数据属性
- [[ configurable ]]: 表示能否通过 delete 删除属性然后重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性。直接在对象上定义的属性,它们这个特性的默认值为 true;
- [[ enumerable ]]: 表示能否通过 for-in 循环返回属性。直接在对象上定义的属性,它们这个特性的默认值为 true;
- [[ writable ]]: 表示能否修改属性的值。直接在对象上定义的属性,它们这个特性的默认值为 true;
- [[ value ]]: 包含这个属性的数据值。读取属性值的时候,从这个位置读;写入属性的时候,把新值保存在这个位置。这个特性的默认值为 undefined ;
要修改属性的特性,必须使用 ES5 的 Object.definePrototype()
方法。这个方法接受三个参数:
1、属性所在的对象。
2、属性的名字。
3、描述符对象。属性必须是:configurable
、enumerable
、writable
、value
中的一个或多个。
var obj = {};
Object.defineProperty(obj, 'name', {
writable: false, // 不能修改值
value: '张三'
})
console.log(obj.name); // 张三
obj.name = '李四';
console.log(obj.name); // 张三, writable设为 false 后,值就没法修改了。
var person = {
name: '李四',
age: 24
}
delete person.name;
console.log(person); // {age: 24}
Object.defineProperty(person, 'age', {
configurable: false
})
delete person.age;
console.log(person);// {age: 24} configurable特性设为 false 后,就没法使用 delete 删除了。
复制代码
把 configurable 设置为 false 后,就不能用 delete 删除属性,而且,也不能修改 除 writable 外的特性。
var obj = {};
Object.defineProperty(obj, "name", {
configurable: false,
value: '张三'
})
// 会抛出错误
Object.defineProperty(obj, "name", {
configurable: true,
value: '张三'
})
复制代码
Object.defineProperty()
方法修改同一个属性,但在把 configurable
特性设置为 false 后就有限制了。
在调用Object.defineProperty()
方法创建一个新的属性时,如果不指定,configurable
、enumerable
、writable
特性的默认值都是 false,如果是修改已存在的属性,就不会有这个限制。
访问器属性
访问器属性没有数据值,有get
、 set
函数。读取访问器属性时,会调用 get
函数,在写入值时会调用set
函数。
访问器属性有如下四个特性:
- [[ configurable ]]: 表示能否通过 delete 删除属性,从而重新定义属性。能否修改属性的特性,或者能否把属性修改为数据属性。直接在对象上定义的属性,它们这个特性的默认值为 true;
- [[ enumerable ]]: 表示能否通过 for-in 循环返回属性。直接在对象上定义的属性,它们这个特性的默认值为 true;
- [[ get ]]: 读取属性时,调用的函数。默认值为 undefined;
- [[ set ]]: 写入属性时,调用的函数。默认值为 undefined;
访问器属性不能直接定义,必须通过Object.defintProperty()
来定义。
"use strict"
let person = {
name: '张三',
age: 25
}
Object.defineProperty(person, 'oldAge', {
get: function () {
return this.age + 1;
},
set: function (newValue) {
if (newValue > this.age) {
this.age = newValue - 1;
this.name = '李四'
} else {
this.age = newValue + 1;
this.name = "王五"
}
}
})
person.oldAge = 28;
console.log(person); // {name: '李四', age: 27};
复制代码
上面定义了一个 person 对象。默认有两个属性, "name"、"age"。新增了一个访问器属性 "oldAge"。它包含了两个函数。 get
函数用来返回值。set
函数,当为 "oldAge"写入值的时候,会调用。把 oldAge 设置为 27 后,调用 set 函数,改变了 person 对象的 "name" 和 "age" 属性值。
不一定非要同时指定 set
、get
函数。只指定 get
函数,意味着属性不能写,严格模式会报错。只指定了set
函数,属性就不能读取,严格模式同样会报错。
定义多个属性
ES5 定义了一个 Object.defineProperties()
方法,可以通过描述符一次定义多个属性。这个方法,接受两个对象参数:第一个是要添加和修改其属性的对象,第二个就是要设置的属性的对象。
let car = {};
Object.defineProperties(car, {
createYear: {
writable: false,
value: 2010
},
color: {
writable: true,
value: 'block'
},
severalYear: {
get: function () {
return parseInt(new Date().getFullYear()) - this.createYear
},
set: function (newValue) {
if (newValue > 2010) {
this.color = 'red';
}
}
}
})
console.log(car.createYear); // 2010
console.log(car.color); // 'block'
console.log(car.severalYear); // 8
car.severalYear = 2015;
console.log(car.createYear); // 2010
console.log(car.color); // 'red'
console.log(car.severalYear); // 8
复制代码
需要注意的是:虽然我们设置 car.severalYear = 2015. 但是car.severalYear的值并没有改变。因为为访问器属性写入值的时候,只是会去执行 set
函数,而真实的值只能是通过get
函数返回。
读取属性的特性
使用 ES5 的 Object.getOwnPropertyDescriptor()
方法,可以取得给定属性的描述符。这个方法接受两个参数:
1、属性所在的对象。
2、属性名称。
返回值是一个对象,如果是数据属性,这个对象的属性有:configurable
、enumerable
、writable
、value
。 如果是一个访问器属性,对象的属性有:configurable
、enumerable
、get
、set
。
let car = {};
Object.defineProperties(car, {
createYear: {
writable: false,
value: 2010
},
color: {
writable: true,
value: 'block'
},
severalYear: {
get: function () {
return parseInt(new Date().getFullYear()) - this.createYear
},
set: function (newValue) {
if (newValue > 2010) {
this.color = 'red';
}
}
}
})
let descriptpor = Object.getOwnPropertyDescriptor(car, "createYear");
console.log(descriptpor);
// { value: 2010,
// writable: false,
// enumerable: false,
// configurable: false }
let fangdescriptpor = Object.getOwnPropertyDescriptor(car, "severalYear");
console.log(fangdescriptpor); // 看下图
复制代码
在 JavaScript 中可以针对任何对象-----包括 DOM 和 BOM 对象使用 Object.getOwnPropertyDescriptor()方法。