浅谈JavaScript的面向对象程序设计(一)
面向对象的语言有一个标志,他们都有类的概念,通过类可以创建多个具有相同属性和方法的对象。但是JavaScript中没有类的概念,因此JavaScript与其他的面向对象语言还是有一定区别的。JavaScript把对象定义为无序属性的集合,其属性可以包含基本值、对象或者函数。对象的每个属性或者方法都有一个名字,而每个名字都映射到一个值。所有我把JavaScript的对象看成一组无序的键值对。
对象是什么
以前曾介绍过对象的创建,建立对象最简单的方式就是建立Object对象的一个实例,再为他添加属性和方法。
1 var obj = new Object(); 2 obj.name="test"; 3 obj.getName=function(){ 4 return this.name; 5 } 6 console.log(obj.getName());
上面的代码第一行创建了一个对象obj,第二行给obj添加了属性name,第三行给obj添加了方法getName。通过getName方法能够获取obj属性name的值。第六行输出字符串test。
1 var obj = {}; 2 obj.name="test"; 3 obj.getName=function(){ 4 return this.name; 5 } 6 console.log(obj.getName());
上面的代码通过字面量创建了对象obj。其他与通过Object创建的完全一样。
对象的属性
JavaScript有两种属性:数据属性和访问器属性。
- 数据属性
数据属性包含一个数据值的位置。在这个位置可以读取和写入值。数据属性有4个描述其行为的特性。
Configurable:表示能否通过delete关键字删除属性或者把属性修改为访问器属性。configurable默认是true。
Enumerable:表示能否通过for-in循环,默认值为true。
Writable:表示能够修改属性的值,默认为true。
Value:包含这个数据的属性值。读取属性值时,从这个位置读。写入属性值的时候,把新值保存在这个位置。默认为undefined。
对于像前面那样定义对象,他的configurable、enumerable和writable默认都是true,value是指定给它的值。
1 var obj={ 2 name:"test"; 3 }
这创建的对象obj拥有一个属性,并设置value值为test。要修改默认属性必须使用Object.defineProperty()方法。这个方法接收三个参数:属性所在的对象、属性的名字和描述符。描述符对象的属性必须是configurable、enumerable、writable和value中的一个或者多个。
1 var obj={ 2 }; 3 Object.defineProperty(obj,"name",{ 4 configurable:true, 5 value:"hehe", 6 enumerable:true, 7 writable:false 8 }); 9 obj.name="test"; 10 console.log(obj.name);//输出hehe
这个例子创建了一个属性name,并设置wriable为false,也就是说name属性的value将无法写入。所在我在第九行修改name的值,并没有效果。name的值依然为test。
把configurable设置为false之后,该属性就将无法通过delete删除,同时也不能通过Object.defineProperty()方法设置除writable之后的值。在严格模式下,如果调用该方法将会报错。
当通过Object.defineProperty方法定义属性的时候,configurable、enumerable和writable特性的默认值是false。所以,最好不要通过该方法定义属性。
- 访问器属性
访问器属性不包含value,但是包含一对getter和setter函数。在读取访问器属性时,会调用getter函数。在写入访问器属性时,会调用setter函数。访问器属性有以下四个特性:
Configurable:表示能否通过delete关键字删除属性或者把属性修改为访问器属性。configurable默认是true。
Enumerable:表示能否通过for-in循环,默认值为true。
get:在读取属性的时候调用的函数,默认值为undefined。
set:在写入属性的值时调用的函数,默认是undefined。
1 var person={"_name":"hehe","age":18} 2 Object.defineProperty(person,"name",{ 3 get:function(){ 4 return this._name; 5 }, 6 set:function(str){ 7 8 if(this._name!="haha"){ 9 this._name=str; 10 this.age="19"; 11 } 12 } 13 }); 14 person.name="haha"; 15 console.log(person.name+":"+person.age);//haha:19
上面的代码创建了一个对象person,并定义了两个属性_name和age。_name表示内部属性,一般由对象本身去访问。定义了属性name,有get和set方法。不一定要同时定义get和set方法。只有get方法,则尝试写入属性的时候报报错。只有set方法,则获取属性的时候会报错。通过Object的defineProperties能够同时定义多个属性。
1 var obj={}; 2 Object.defineProperties(obj,{ 3 name:{ 4 value:"hehe" 5 }, 6 age:{ 7 value:"18" 8 } 9 }); 10 console.log(obj.name+":"+obj.age);//hehe:18
上面的代码,通过Object的defineProperties方法同时定义了两个属性name和age。该方法的第一个参数是对象,第二个参数是由需要定义的属性组成的对象。
- 读取属性的特性
JavaScript提供了Object.getOwnPropertyDescriptor方法,可以获取属性的描述符。这个方法需要两个参数:第一个参数是对象,第二个参数是描述符属性的名称。返回值是一个对象,如果是访问器属性则有configurable、enumerable、writable、get和set。如果是数据属性,这个对象有属性configurable、enumerable、writable和value。
1 var obj={}; 2 Object.defineProperties(obj,{ 3 name:{ 4 value:"hehe" 5 }, 6 age:{ 7 value:"18" 8 }, 9 _sex:{ 10 value:"man" 11 }, 12 sex:{ 13 get:function(){ 14 return this._sex; 15 }, 16 set:function(str){ 17 this._sex=str; 18 } 19 } 20 }); 21 var descriptor1=Object.getOwnPropertyDescriptor(obj,"name"); 22 var descriptor2=Object.getOwnPropertyDescriptor(obj,"sex"); 23 console.log(descriptor1.writable);//false 24 console.log(descriptor2.get);//function 25 console.log(obj.name+":"+obj.age+","+obj.sex);//hehe:18,man
上面的代码,通过Object.getOwnPropertyDescriptor()方法获取属性的描述吗,分别获取了数据属性以及访问器属性。