2012年3月21日星期三

JavaScript面向对象

对函数的初步理解:
1、JavaScript中的任何一个函数都是一个Function类型的一个实例,也是一个Object类型的实例,定义了一个function函数,那么它就是一个实例对象,实例对象的内部属性__proto__指向了Object构造函数的原型prototype属性,因此实例继承了Object对象的默认属性和方法;
2、普通函数默认返回undefined,构造函数返回一个实例对象。

面向对象模式:

1、创建对象,使用一个特定接口new Object()
缺点:使用同一个接口创建很多对象,会产生大量重复的代码

2、使用工厂模式,用函数来封装,以特定接口创建对象
如:
function createObj(name,age){	var o = new Object();	o.name = name;	o.age = age;	return o;}var o1 = createObj("yjh",23)
优点:解决了使用一个接口创建多个相似对象产生大量重复代码的问题
缺点:没有解决对象识别的问题,即o1是怎么样的一个对象类型

3、构造函数模式,JavaScript没有类概念
如:
function CreateObj(name,age){	this.name = name;	this.age = age;	this.sayName = function(){		alert("hi" + this.name);		}}var obj1 = new CreateObj("yjh1",23);var obj2 = new CreateObj("yjh2",23);
优点:解决了实例对象类型识别的问题,obj1,obj2对象为CreateObj类型
缺点:构造函数定义的属性和方法不是所有实例所共享的,各实例调用的方法是两个不同Function类型的实例(obj1.sayName != obj2)

4、原型模式
如:
function CreateObj(){}CreateObj.prototype = {	constructor: CreateObj,	name: "yjh",	age: 23,	colors: ["a","b"],	sayName: function(){		alert(this.name);		}}var obj1 = new CreateObj();var obj2 = new CreateObj();alert(obj1.sayName == obj2.sayName);//trueobj1.colors.push("c");alert(obj2.colors);//a,b,c
说明:调用obj1,obj2实例的属性和方法,首先会搜索实例自身定义的属性和方法,如果没有,由于实例的__proto__内部属性指向原型,
因此会继续搜索原型中定义的属性和方法

优点:原型中定义的属性和方法是所有实例对象所共享的,解决了多个函数实现同一功能的问题
缺点:如果在原型中定义的属性包含的是引用类型的值,那么通过修改一个实例属性值会影响到另一个实例属性值,这正是由于原型的共享本质所导致的

5、组合模式(构造函数模式与原型模式)
如:
function CreateObj(name,age){	console.log(this.name);//yjhyjh	this.name = name;	this.age = age;	this.colors = ["a","b"];}CreateObj.prototype = {	constructor: CreateObj,	name: "yjhyjh",	sayName: function(){		return this.name;	}}var obj1 = new CreateObj("yjh1",23);var obj2 = new CreateObj("yjh2",23);alert(obj1.sayName == obj2.sayName);//truealert(obj1.sayName());//yjh1alert(obj2.sayName());//yjh2obj1.colors.push("c");alert(obj2.colors);//a,b
说明:把所有实例不需要共享的属性定义在构造函数中,把需要共享的属性,方法定义在原型中,互补构造函数模式和原型模式的优缺点,
原型是所有实例化对象的原型对象,实例与原型之间是通过实例内部属性__proto__连接到原型,所有实例共享原型中的属性和方法,而原型内部又包含
一个constructor属性(指向构造函数),由于作用域链的关系,构造函数中的this对象也指向了原型对象,因此在构造函数中定义的this.name,this.age等属性
和方法会覆盖原型中定义的属性和方法

6、继承(实现继承,原型链)
就是把一个构造函数的原型作为另一个构造函数的实例化对象,那么这个实例化原型对象就会继承另一个构造函数的原型属性和方法,这就是所谓的原型链
如:
function Fun1(){	this.name = ["yjh1","yjh2"];}Fun1.prototype = {	constructor: Fun1,	sayName: function(){		alert(this.name)		}}function Fun2(){}Fun2.prototype = new Fun1();var fun2 = new Fun2();fun2.sayName();//yjh1,yjh2fun2.name.push("yjh3"); //fun2.name = ["yjh1","yjh2","yjh3"];var fun3 = new Fun2();alert(fun3.name);//yjh1,yjh2,yjh3
缺点:来自包含引用类型值的原型,原型中定义的属性,方法是所有实例所共享的,Fun2.prototype原型对象是Fun1类型的一个实例,
因此原型对象中有包含引用类型值的name属性,当实例化多个Fun2类型对象时,所有的实例对象都共享这个原型name属性,通过修改实例中的name属性值,
会直接修改原型中定义的name属性值

7、组合继承(继承与借用构造函数)
如:
function Fun1(){	this.name = ["yjh1","yjh2"];}Fun1.prototype = {	constructor: Fun1,	sayName: function(){		alert(this.name)		}}function Fun2(){	Fun1.call(this);	}Fun2.prototype = new Fun1();var fun2 = new Fun2();fun2.sayName();//yjh1,yjh2fun2.name.push("yjh3"); //fun2.name = ["yjh1","yjh2","yjh3"];var fun3 = new Fun2();alert(fun2.name);//yjh1,yjh2,yjh3alert(fun3.name);//yjh1,yjh2
说明:由于构造函数中定义的属性,方法不是所有实例共享的,而且会覆盖原型中定义的属性与方法,所以它不会由于实例化原型对象(Fun2.prototype)中包含了引用类型值的属性而
存在的问题





JavaScript面向对象

TAG: