当前位置: 代码迷 >> JavaScript >> javascript种机制
  详细解决方案

javascript种机制

热度:235   发布时间:2012-09-16 17:33:17.0
javascript类机制

?

JavaScript是一种功能强大的语言,起初它只是用于在浏览器中完成一定的Dom操作和特殊效果。随着AJAXRIA技术的广泛普及,JavaScript发挥了越来越重要的作用,JavaScript的代码量越来越大,对可维护性的要求也越来越高。JavaScript提供了特有的类机制,但是在语法习惯上与传统面向对象的语言有很大的不同,这使得不少的JavaScript开发人员感到困惑,本文将会对JavaScript常见的类功能进行介绍

1.JavaScript定义类及实例化

JavaScript的语法中,并没有类似于Class的类定义关键字,而是使用与普通方法一样的function来定义类,所以定义普通的方法与定义类有着类似的语法(这使得刚接触JavaScript的开发人员会感到很难理解,关于如何判断function是要作为类的定义,可以查看这篇文章。)

?

//定义一个普通方法
function testSimpleFunction(){
    alert("This is a simple function!");
}
testSimpleFunction();//调用方法
//定义一个类
function Person(name,age){
  this.name = name;
  this.age = age;
  this.aboutMe = function(){
    alert("I’m  a person!My name is "+this.name+",My age is "+this.age+"!")
}
}
var personObject =  new Person("levin",30);//实例化该类,得到一个对象
personObject. aboutMe();//调用对象的方法

?

?JavaScript是基于原型的语言,每个类(即构造函数)都有一个prototype属性指向该类对应的原型对象,而实例化得到的对象会拥有该类原型中的属性和方法。常用的定义类的方式如下:

?

function Person(name,age){
		this.name = name;
		this.age = age;
	}
	Person.prototype.sayHello = function(){
		alert(this.name);
	}
	var person = new Person("levin",30);
person.sayHello();//调用原型中的方法

?

?对象在进行属性和方法访问时,首先会在对象内部查找,如果找不到,会在其构造函数原型中进行进一步的查找。基于这样的机制,对象从原型得到的属性和方法可以进行重写覆盖,对象就拥有与原型同名的属性和方法,而对于通过此类实例化的其它对象,则不会受其影响:

?

person.sayHello = function(){
		alert("My own name is "+this.name);
	}
person.sayHello();
var anotherPerson = new Person("zhangwb",30);
anotherPerson.sayHello();

?在本例中,person对象和anotherPerson对象尽管都是通过Person类实例化而来,但是他们在调用sayHello方法时会有不同的结果。这就是因为person对象重写了从构造函数原型中继承而来的sayHello方法。

?

2.继承

JavaScript中没有直接实现继承的关键字,因此关于继承有多种的实现方式,代表性的是类式继承原型式继承,对于这两种继承方式,我们都会进行简单的介绍。

首先看一下类式继承。如果我们有一个名为Employee类想要继承Person类,一般的写法如下:

?

function Employee(name,age,workExperience){
	Person.call(this,name,age)
	    this.workExperience = workExperience;
}
Employee.prototype = new Person();
Employee.prototype.constructor=Employee
Employee.prototype.getInput = function(){
	return 5000;
}
var employee =new  Employee("employee levin",30,4);
employee.sayHello();
alert(employee.getInput());

?在这个例子中,我们定义名为Employee的类,要求继承Person类,该类有三个初始化参数,其中前两个与Person类一致,而第三个参数workExperience是该类特有的,Employee除了要继承Person类的属性和方法,还要求定义名为getInput的方法。

?

在本例中,我们在Employee的构造函数中,调用了Person的构造函数,并传递了适当的参数,从而实现了属性的继承。对于Person方法的继承,我们是通过调整Employee原型链的方式来达到的,首先将Employee类的prototype所指向的对象设置为一个Person实例,这样就使得Employee能够使用Person原型中定义的方法,但是这也把Employee原型中的构造函数指向了Person,因此我们需要将其进行重新置为Employee。通过以上的操作,Employee实现了对Person的继承,而Employee要定义新的方法,只需要在其prototype属性中继续追加即可。

这样的继承方式缺乏通用性,对于每个实现的继承的地方都写很多的类似代码,另外在调整原型链的时候,需要实例化一个父类的实例,而这是没有必要的,因为我们想要的仅仅是父类的原型链。因此我们可以写一个通用的方法:

?

function extend(subClass,superClass){
	    var F = function(){};
	F.prototype = superClass.prototype;
	subClass.prototype = new F();
	subClass.prototype.constructor = subClass;
	subClass.superClass = superClass.prototype;
	    if(superClass.prototype.constructor == Object.prototype.constructor){
		 superClass.prototype.constructor = superClass;
}
}

?

?在这个方法中,传入两个参数,分别为子类和父类,我们首先定义了一个新的构造函数,让该函数的prototype设置为父类的prototype,然后子类的prototype属性指向了一个F的实例,这样就能够在不实例化父类的情况下完成原型链的调整,另外我们在子类中定义了一个名为superClass的属性,指向了父类的原型,从而可以通过子类调用到父类的方法。此时要实现EmployeePerson的继承关系就容易许多了:

?

function Employee(name,age,workExperience){
		Employee.superClass.constructor.call(this,name,age)
		this.workExperience = workExperience;
	}
	extend(Employee,Person);
	Employee.prototype.getInput = function(){
		return 5000;
}

?

?其次,我们来看一下原型式继承。原型式继承与类式继承以及其它语言的继承方式都有着很大的差异。在原型式继承中,不会再使用类来定义对象结构,而是直接使用字面量,以后创建的对象都以此为原型。如有以下的Person原型对象:

?

	var Person={
		name:"levin",
		age:30,
		getName:function(){
			alert(this.name);
		}
	}

?

?要创建新对象时,需要调用以下的方法:

?

	function  object(o) {
        function F() {}
        F.prototype = o;
        return new F();
    }

?

?在这个方法中,我们定义了一个空的构造函数,将传入对象作为构造函数的prototype属性,从而生成的新对象能够访问到原型提供的属性和方法。如我们要创建一个Person的实例:

?

	var person = object(Person); //得到Person的实例
	person.getName();

?

?而继承的实现也有赖于object方法,如要实现和前面介绍相同功能的Employee类,只需执行以下的代码即可:

?

var Employee = object(Person);
	Employee.workExperience = 4;
	Employee.getInput = function(){
		alert(5000)
	}
	var employee = object(Employee);//得到Employee的实例
	employee.getInput()

?以上简要介绍了JavaScript两种常见的继承方式,无论哪种方式与传统的面向对象语言都有很大的差异,这需要开发人员对JavaScript有较为深入的了解,而一些常用的框架都对JavaScript的类机制进行了封装,这样我们就能够更方便的定义和使用JavaScript类。

?

?

在其它面向对象语言中,发挥重要功能的接口功能,在JavaScript中没有对应的关键字实现,但是有很多的替代方案进行了模拟,《JavaScript设计模式》一书对此有所介绍,感兴趣的读者可以参考。

?

根据以上的介绍,我们了解到在JavaScript中实现类机制需要对该语言有更为深入的掌握,而JavaScript作为一种动态语言,也提供了其它静态面向对象语言所难以实现的功能,这也许正是其有趣和吸引人的地方吧。

?

参考资料:

JavaScript权威指南》 David Flanagan 张铭泽译

JavaScript设计模式》 Ross HarmesDustin Diaz 谢廷晟译

http://javascript.crockford.com/prototypal.html

http://javascript.crockford.com/inheritance.html

http://docs.dojocampus.org/

http://blog.csdn.net/dojotoolkit/

http://dojotoolkit.org/

?

?

  相关解决方案