代码改变世界

JavaScript中对象的定义和继承的几种方式

2012-05-07 22:37  java线程例子  阅读(204)  评论(0编辑  收藏  举报

前几天看张龙老师讲的JavaScript视频的时候,觉得老师讲的很好,继承和定义对象这很有意思,又查了几本书和一些资料,也慢慢的记住了这几种对象的定义方式和继承,但是日后,我可能会忘,所以写成博客和大家分享一下,并且做一下总结,我本来想看一看javascript高级程序设计这本书是怎么说的,可以图书馆刚上一天这书,就被人给借走了,只好等他换回去我在看了,我会慢慢的对这篇文章进行扩充。

定义对象的几种方式:

1)基于已有对象的扩充其属性和方法

这种方式是创建一个自定义对象的最简单方式,然后可以为他添加属性和方法,如下所示

var person = new Object();
person.name="Nicholas";
person.age = 29;
person.job = "Software Engineer";
person.sayName = function(name)
{
	this.name = name;
	alert(this.name);
}
object.sayName("lisi");


2)通过工厂方式

工厂模式是软件工程领域一种广为人知的模式,这种模式抽象了创建具体对象的过程,通过一种函数,用函数来封装以特定接口创建对象的细节。工厂方式的特点是通过特定的工厂方法创建特定类型的对象。以下是比较典型的实现代码。

//工厂方式创建对象
function createObject()
{
	var object = new Object();
	object.username = username;
	object.password = password;
	object.get = function()
	{
		alert(this.username+","+this.password);
	}	
}
var object1 = createObject();
var object2 = createObject();
object1.get();


 接下来给它加上参数

function createObject(username,password)
{
	var object = new Object();
	object.username = username;
	object.password = password;
	object.get = function()
	{
		alert(this.username+","+password);
	}
	return object;
}
var object = createObject("zhangsan","123");
object.get();


也可以让一个函数对象被多个对象所共享,而不是每一个对象拥有一个函数对象

function get()
{
	alert(this.username+","+this.password);
}
function createObject(username,password)
{
	var object = new Object();
	object.username = username;
	object.password = password;
	object.get = get;
	return object;
}
var object = createObject("zhangsan","123");
var object2 = createObject("lisi","456");
object.get();
object2.get();


3)构造函数方式

构造函数的方式和工厂方式很像,通过构造函数的方式可以创建特定的对象,像Object和Array这样的原生构造函数,在运行时会自动出现在执行环境中,通过创建自定义的构造函数,从而自定义对象类型的属性和方法。

function Person()
{
	this.username = "zhangsan";
	this.password = "123";
	this.getInfo = function()
	{
		alert(this.username+","+this.password);
	}
}
var person = new Person();
person.getInfo();


用的更多的是给他传递参数

function Person(username,password)
{
	this.username = username;
	this.password = password;
	this.getInfo = function()
	{
		alert(this.username+","+this.password);
	}
}
var peron = new Person("zhangsan","123");
person.getInfo();

用构造函数的方式,按照惯例通长首字母大写,如Person中的P,而不是以一个小写的字母开头,这个做法鉴于其他OO语言,主要是为了区别。

 构造函数方式和工厂方式都有一个不可忽略的弊端,就是每个对象被实例化时,都会实例化类中的方法,而这个弊端会造成每个对象都有独立的版本。

 4)原型(“prototype”)方式

通过原型的方式我们可以避免这种弊端。我们创建的每个函数都有一个prototype属性,这个属性就是一个对象,它的用途是包含可以由特定类型的所有实例共享的属性和方法。

//使用原型的方式创建对象
function Person()
{

}
Person.prototype.username = "zhangsan";
Person.prototype.password = "123";
function.prototype.getInfo = functiion()
{
	alert(this.username+","+this.password);
}
var person = new Person();
var person2 = new Person();
person.username = "lisi";
person.getInfo();
person2.getInfo();
 

 

对于原型方式来说,如果使用原型对象,那么生成的所有对象会共享原型中的属性,这样一个对象改变了该属性也会反映到其他对象中。

function Person()
{

}
Person.prototype.username = new Array();
Person.prototype.password = "123";

Person.prototype.getInfo = function()
{
	alert(this.username+","+this.password);
}
var person = new Person();
var person2 = new Person();
person.username.push("zhangsan");
person.username.push("lisi");
person.password = "456";
person.getInfo();
person2.getInfo();


 单纯的使用原型方式定义对象无法再构造函数中为属性赋初值,只能在对象生成后再去改变属性值。

5)混合方式(原型+构造函数

工厂方式、构造方式、原型方式都有一些缺陷,那种方式可以很好的实现对象的创建呢?使用原型+构造函数方式来定义对象,对象之间的属性互不干扰,各个对象间共享同一个方法。通过构造函数方式定义对象的所有非函数属性,用原型方式定义对象的函数属性,所有的属性都是单一对象私有的,而方法则是所有对象公有的。如下所示:

 

//使用原型+构造函数方式来定义对象
function Person()//构造函数定义对象的非函数属性
{
	this.username = new Array();
	this.password = "123";
}
Person.prototype.getInfo = function()//通过原型方式定义对象的函数
{
	alert(this.username+","+this.password);
}
var p = new Person();
var p2 = new Person();
p.username.push("zhangsan");
p2.username.push("lisi");
p.getInfo();
p2.getInfo();


 6)通过动态原型方式

对于习惯了使用Java的人来说,面向对象的“封装”特征并没有体现在上述的代码中,混合方式并没有对对象的属性和方法进行严密封装。在JavaScript中,提供了一种动态原型的方式对对象的属性和方法进行严密的封装,在构造函数中通过一个 标志量让所有对象共享一个方法,而每个对象拥有自己的属性。

function Person()
{
	this.username = "zhangsan";
	this.password = "123";
	if(typeof Person.flag == "undefined")
	{
		Person.prototype.getInfo = function()
		{
			alert(this.username+","+this.password);
		}
	Person.flag = true;
	}
}
var p = new Person();
var p2 = new Person();
p.getInfo();
p2.getInfo();


 JavaScript中的继承

和定义对象一样,在JavaScript中实现继承也有多种方式,javascript是弱类型的语言,有很多的地方没有明确的限制,挺多的时候都掌握在我们的手中。我们可以根据自己的方式来进行各种操作。

1)对象的冒充

使用对象的冒充的时候,必须使用构造函数,否则无法实现继承

//继承的第一种方式,对象的冒充
function Parent(username)
{
	this.username = username;

	this.sayHello = function()
	{
		alert(this.username);
	}
}
function Child(username,password)
{
	//下面的三行代码是最关键的代码
	this.method = Parent;
	this.method(username);
	delete this.method;

	this.password = password;
	this.sayWorld = function()
	{
		alert(this.password);
	}
}
var parent = new Parent("zhangsan");
var child = new Child("lisi","1234");

parent.sayHello();
child.sayHello();
childsayWorld();

使用对象冒充的方式,可以实现多继承,让一个子类有多个父类,与单一的继承方式一样。

2)通过call方法

在Function对象中有两个方法可以实现继承,即call方法和apply方法。也正是因为这个我们所定义的每个函数都有call方法,我们可以通过函数名调用call方法,对于call方法的参数列表来说并不固定,根据实际的情况增加和减少。第一个参数是指调用当前的Function对象,并将它传递给函数中的this,而剩下的所有参数都是当前函数的参数。逐一赋值给函数中的参数。如下代码所示:

//使用call方法实现对象的继承
function Parent(username)
{
	this.username = username;
	this.sayHello = function()
	{
		alert(this.username);
	}
}
function Child(username,password)
{
	Parent.call(this,username);//在这里调用call方法,将Child对象通过this传递给父类的this,父类的this就代表了子类的对象
	this.password = password;
	this.sayWorld = function()
	{
		alert(this.password);
	}
}
var parent = new Parent("zhangsan");
var child = new Child("lisi","123");
parent.sayHello();
child.sayHello();
child.sayWorld():


3)通过apply方法

apply方法也是Function对象里的方法,使用和call方法基本一致。唯一的区别就是apply方法的参数,call的方法的参数是不固定的,apply方法的参数只有两个,第一个是调用当前的Function对象,即this对象,第二个是传入参数的数组。如代码所示:

//使用apply方法实现对象继承
function Parent(username)
{
	this.username = username;
	this.sayHello = function()
	{
		alert(this.username);
	}
}

function Child(username,password)
{
	Parent.apply(this,new Array(username));//通过apply方法将Child对象传递给父类中的this,那么this就变成了子类的对象
	this.password = password;
	this.sayWorld = function()
	{
		alert(this.password);
	}
}
var parent = new Parent("zhangsan");
var child = new Child("lisi","123");
parent.sayHello();
child.sayHello();
child.sayWorld();


4)原型链的方式

在之前的定义对象的时候使用了使用原型的方式创建对象,也可以通过原型的方式进行对象的继承。通常称作原型链。但是这种方式无法给构造函数传递参数。如代码所示:

//使用原型链方式实现对象继承
function Parent()
{

}
Parent.prototype.hello = "hello";
Parent.prototype.sayHello = function()
{
	alert(this.hello);
}
function Child()
{

}
Child.prototype = new Parent();//通过这句话将子类的原型类设为了父类,从而实现了继承
Child.prototype.world = "world";
Child.prototype.sayWorld = function()
{
	alert(this.world);
}
var child = new Child();
child.sayHello();
child.sayWorld();


5)混合方式

在JavaScript中最好的方式就是用混合方式实现对象间的继承。和定义对象一样,我们可以将属性和方法用不同的方式定义,用call或apply方式定义继承对象的属性,利用原型链的方式实现方法的继承。如下代码所示:

//使用混合的方式实现对象的继承
function Parent(hello)
{
	this.hello = hello;//定义父类的属性
}
Parent.prototype.sayHello = function()//定义父类的方法
{
	alert(this.hello);
}
function Child(hello,world)
{
	Parent.call(this,hello);//继承父类的属性
	this.world = world;
}
Child.prototype = new Parent();//继承父类的方法
Child.prototype.sayWorld = function()
{
	alert(this.world);
}
var child = new Child("hello","world");
child.sayHello();
child.sayWorld();


以上的总结仅仅是我简单的总结,等日后学的比较深了会在扩充一下,希望大家理解一下。