JavaScript是一种功能强大的语言,起初它只是用于在浏览器中完成一定的Dom操作和特殊效果。随着AJAX和RIA技术的广泛普及,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的属性,指向了父类的原型,从而可以通过子类调用到父类的方法。此时要实现Employee和Person的继承关系就容易许多了:
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
Harmes、Dustin
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/
分享到:
相关推荐
JavaScript事件机制详细研究
javascript运行机制1
在使用一些 Javascript 框架时,或许会看到类似的代码 代码如下: var ...这是一种典型的面向对象的类机制应用,与原生的 Javascript 类机制相比,显得更为清晰和自然。并且,在此基础上,实现类的继承也较为方便。
Javascript继承机制原理 可以参考下
一篇很好的JavaScript运行机制介绍文章,与大家一起分享!
JavaScript继承机制研究.pdf
自己整理的 JavaScript 内存分析,祝你一臂之力!
浅析javascript原型继承机制,浅析javascript原型继承机制
JavaScript继承机制探讨及其应用.pdf
1.关于javascript 2.javascript事件循环 4.又恨又爱的setInterval 5.Promise与process.nextTick(ca
javascript运行机制之this详细介绍.docx
夯实基础上篇-图解 JavaScript 执行机制.doc
javaScript大事机制兼容(具体整理)_.docx
本文实例讲述了JavaScript运行机制。分享给大家供大家参考,具体如下: 第一次写博客 目前研一第二学期,大二开始入门前端,然而长久以来都是对于框架的简单调用,并未对其进行深入研究,因此,这个博客是作为自我...
笔者历经多年javascript的开发,痛彻体会javascript面向对象编程的不便性,精心制作了一个类的定义与继承功能的js,实现了在javascript中对类的定义、继承、封装机制,主要功能特征包括: 一、 统一了类定义的语法...
动态语言与动态类型语言 ECMAScript与JavaScript,JavaScript与BOM、DOM JavaScript基础语法 JavaScript对象机制、类与继承 JavaScript执行机制、作用域链和闭包 JavaScript编程建议
javascript原型继承机制参考.pdf
javascript原型继承机制借鉴.pdf
javascript原型继承机制归类.pdf
本文着重解析javascript类继承机制,让你从底层了解javascript是怎样实现“继承”这一概念的。