理解JavaScript的对象

一本JavaScript高级程序设计的书放在窗边,上次下雨没关窗,回来的时候,已经湿了.

前言

最简单的创建一个对象的方法即new一个Object的实例,再为它设置属性和方法即可.接着,出现了字面量定义一个对象的方法:

1
2
3
4
5
6
7
8
9

var person = {
name = "qyy";
age="23";

sayName = function(){
alert('I am qyy.')
};
}

属性的类型

ECMA5定义了内部的特性(attribute),描述了属性的特征(property),属性有四个特征,用中括号[[Enumerable]]表示等等.

ECMAScript有两种属性:数据属性和访问器属性

  1. 据属性

    • [[Configurable]]:是否可改动
    • [[Enumerable]]:是否可遍历
    • [[Writable]]:是否可写入
    • [[Value]]:默认undefined,包含数据的值.

前三皆默认为true.

要修改对象默认的数据属性,需要用Object.defineProperty()方法.举个栗子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var person = {}
Object.defineProperty(person, "name",{
writable: false,
value: "qyy"
});

alert(person.name); // "qyy"
person.name = "Who"; // 不会报错,除非是严格模式
alert(person.name); // "qyy" 不可改,Writable为false


Object.defineProperty(person, "name",{
configurable: false, // 表示,不能通过delete删除此对象的属性
value: "qyy"
});


Object.defineProperty(person, "name",{
configurable: true,
value: "qyy"
}); // 出错,Configurable一旦设置为false,再次修改立即报错.

// 另外,此方法默认四个配置都设定为false,除非开发者指定为true

针对默认配置设定为false的理解,需要了解的是:如果在调用此方法时,参数中的属性未定义,才默认false
如果定义了name: “qyy”,再调用此方法,则默认值为true

我自己测试过,踩了这个坑,于是Google搜索到这里

  1. 访问器属性

访问器属性不包含数据值,包含的是getter()和setter()函数,但是并非必须的,存在默认实现的方法.

读取访问器属性的时候,调用getter函数,设置访问器属性的时候,调用setter函数,传入新的值.

访问器属性有如下 4 个特性:

  • [[Configurable]]:表示能否通过 delete 删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为数据属性。
  • [[Enumerable]]:表示能否通过 for-in 循环返回属性。
  • [[Get]]:在读取属性时调用的函数。默认值为 undefined。
  • [[Set]]:在写入属性时调用的函数。默认值为 undefined。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var book = {
_year: 2018,
edition:3
};

Object.defineProperty(book, "year",{
get: function(){
return this._year;
},
set: function(value){
if (value > 2018){
this._year = value;
this.edition = value - 2018 + 3;
}
};
});

alert(book.year); // 2018
book.year = 2020;
alert(book.edition); // 针对的set属性为year,会修改_year和edition,set方法根据传入的值,修改属性,输出5

默认是同时实现了两个方法,但是如果开发者只定义了一个方法,例如get,则此属性为不可写,只能读取值,同理,只有set为可写不可读
非严格模式不会报错,并且无提示,严格模式会报错

当然,可以同时修改多个属性的定义:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var obj = {};
Object.defineProperties(obj, {
property1: {
value: true,
writable: true
},
property2: {
value: 'Hello',
writable: false,
get: function(){
return this.value;
},
set: function(value){
this.value = value;
}
}
// 等等.
});

console.log(obj); // Object {property1: true, property2: "Hello"}
  1. 读取属性的properties

ECMA5提供了Object.getOwnPropertyDescriptor()方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

var girl = { name: 'zyj' };
console.log(Object.getOwnPropertyDescriptor(girl, 'name'));
// Object {value: "zyj", writable: true, enumerable: true, configurable: true}
// 默认这些属性都是true的

Object.defineProperties(girl, {
name: {
writable: false
},
age: {
writable: true,
value: 22
}
});

console.log(Object.getOwnPropertyDescriptor(girl, 'name'));
// Object {value: "zyj", writable: false, enumerable: true, configurable: true}
console.log(Object.getOwnPropertyDescriptor(girl, 'age'));
// Object {value: 22, writable: true, enumerable: false, configurable: false}

// 声明一个描述符变量来保存这个函数的返回值
var descriptor = Object.getOwnPropertyDescriptor(girl, 'age');

//即可通过该描述符去取值
console.log(descriptor.value); // 22
console.log(descriptor.configurable); // false
console.log(descriptor.writable); // true
console.log(descriptor.get); // undefined 默认是undefined
console.log(descriptor.set); // undefined

有一点很重要,为什么set和get默认是undefined呢,要这样看待,针对不存在的对象属性
默认undefined,而针对已经初始化的例如_year的属性,则默认实现了这两个方法

总之,访问器属性一般用于实现JavaScript解析器本身的引擎,我先了解一下即可.告辞,2018年09月11日00:06:21.睡觉.