初识js面向对象

前言

基于类的对象:我们都知道面向对象的语言中有一个明显的标志,就是都有类的概念,通过类这个类似模板的东西我们可以创建许多个具有相同的属性和方法的对象。然而在ECMAScript中并没有类的概念,自然它与基于类的语言中的对象也会有所不同。

js中的对象:**无序**的属性的集合,属性可以包含基本值、对象、函数。即js中的对象是一组没有特定顺序的值,对象的每个属性或者方法都有一个自己的名字,而每个名字都与一个值相对应。

理解对象

创建对象的方式

1 创建一个对象的最简单的方式是创建一个Object实例,之后为其添加属性和方法。

例如

1
2
3
4
5
6
7
var person = new Object();
person.name = '谦龙';
person.sex = '男';
person.sayNameAndSex = function(){
console.log(this.name, this.sex);
}
person.sayNameAndSex(); // 谦龙 男

2 使用对象字面量形式

例如

1
2
3
4
5
6
7
8
9
var person = {
name:'谦龙',
sex:'男',
sayNameAndSex:function(){
console.log(this.name, this.sex)
}
}
person.sayNameAndSex(); // 谦龙 男

属性的类型

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

数据属性

数据属性包含一个数据值的位置。在这个位置可以读取和写入值。共有四个描述其行为的特性。

1.[[Configurable]]:表示能否通过delete删除属性从而重新定义属性…默认值为true
2.[[Enumerable]]:表示能否通过for in 循环返回属性…默认为true
3.[[Writable]]:表示能否修改属性的值…默认为true
4.[[Value]]:表示这个属性的值.默认为undefined

要修改属性默认的特性,必须使用ES5的Object.defineProperty()方法,而该方法接收三个参数:属性所在的对象、属性的名称、还有一个描述属性特性的对象(configurable、enumerable、writable、value),设置其中的一个或者多个值可以修改对应的特性

DEMO

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var person = {};
Object.defineProperty(person, 'name',{
configurable:false,//表示不允许通过delete删除属性
writable:false,//表示不允许重写
ennumerable:false,//表示不允许通过for in遍历
value:'谦龙'//设置该对象中属性的值
})
person.name = '谦龙2';//尝试重新设置 结果不生效
delete person.name;//尝试删除 结果不生效
for(var attr in person){
console.log(person[attr]);// false
}
console.log(person.name);//谦龙

注意:configurable设置为false后 不允许再次修改为true,另外在调用Object.defineProperty()方法的时候,configurable、ennumerable、writable默认值为false。

访问器属性

访问器属性不包含数据值,它们包含一对getter、setter函数(但是这两个函数并不是必须的)在读取访问器属性的时候,会调用getter函数,这个函数是负责返回有效的值,在写入访问器属性的时候会调用setter函数并传入新值,这个函数负责如何处理数据。

访问器属性具有如下的特性

  1. [[configurable]] 表示能否通过delete来删除属性从而定义新的属性
  2. [[enumerable]] 表示能否通过for in循环来遍历返回属性
  3. [[get]] 在读取属性时候调用的函数,默认为undefined
  4. [[set]] 在写入函数的时候调用的函数,默认的值为undefined

注意:访问器属性不能直接定义,必须通过Object.defineProterty()定义
DEMO

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var book={
_year:2015, //这里的下划线是常见的记号,表示只能通过对象的方法才能访问的属性
edition:1
}
Object.defineProperty(book, 'year',{
get:function(){
return this._year; //即默认通过 book.year获取值的时候 返回的是 boot._year的值
},
set: function (value) {//在对 boot.year设置值的时候 默认调用的方法 对数据进行处理
var _year = this._year;
if(value > _year){
this._year = value;
this.edition += value - _year;
}
}
})
book.year = 2016;
console.log(book.year,book.edition); // 2016 2

定义多个属性

我们可以通过ES5中的Object.defineProperties()方法来给对象添加多个属性,该方法接受两个对象参数,第一个参数是要添加和修改其属性的对象,第二个对象的属性和第一个对象中要添加和修改的属性一一对应。

DEMO

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
var book = {};
Object.defineProperties(book,{
_year:{
value:2015,
writable:true //注意这里设置成true 才可以 "写" 默认是false
},
edition:{
value:1,
writable:true //注意这里设置成true 才可以 "写" 默认是false
},
year:{
get:function(){
return this._year;
},
set: function (value) {
var _year=this._year;
if(value > _year){
this._year=value;
this.edition+=value-_year;
}
}
}
})
book.year = 2016;
console.log(book.year,book.edition); // 2016 2

读取对象属性的特性

使用ES5中的Object.getOwnPropertyDescriptor()方法,可以去的给定的属性的描述符。
该方法接收两个参数:属性所在的对象和要读取描述符的属性名称。返回的是一个对象,如果是数据属性,则返回的属性有 configurable,enumerable,writable,value.如果是访问器属性则返回的属性有 configurable,enumerable,get,set

DEMO

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
31
32
33
34
35
36
var book={};
Object.defineProperties(book,{
_year:{
value:2015,
writable:true
},
edition:{
value:1,
writable:true
},
year:{
get:function(){
return this._year;
},
set: function (value) {
var _year = this._year;
if(value > _year){
this._year = value;
this.edition += value - _year;
}
}
}
})
//对象遍历函数
function showAllProperties(obj){
for(var attr in obj){
console.log(attr+':'+obj[attr]);
}
}
var descriptor= Object.getOwnPropertyDescriptor(book,'_year');//数据属性
var descriptor2= Object.getOwnPropertyDescriptor(book,'year');//访问器属性
showAllProperties(descriptor);
console.log('============================');
showAllProperties(descriptor2);

测试

获取属性的特性