转自:http://gaojiewyh.iteye.com/blog/1931968 (原文更易阅读)
在面向对象的Javascript编程中,希望代码优雅有高效是非常重要的。javascript中不存在类的概念,只有对象。要想把Javascript代码写的像java 或者C++一样优雅,就得考虑如何去实现,同时也要考虑性能和高效。定义javascript对象的方式有很多,继承的方式也很多。通过不断地实践,推荐如下的方法:
1.Javascript对象的定义采用混合方式【构造函数 +原型方式(prototype)】
(1)通过构造函数方式定义对象的所有非函数属性
(2)用原型方式定义对象的函数属性
采用这种方式,所有的属性都是单一对象私有的,而方法则是所有对象公有的,对象之间的属性不相互干扰,各个对象间共享同一个方法。
- //使用原型+构造函数方式来定义对象
- //构造函数定义对象的非函数属性<strong>
- function Person()
- {
- this.username = new Array();
- this.password = "123";
- }
- </strong>//通过原型方式定义对象的函数<strong>
- 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();
- </strong>
在现实的开发过程中,我们可能希望开发的各个类(实质是对象)能像java程序中放到一个包中统一管理,统一使用,而各个对象相互独立,同时避免对象重名等等因素,我们需要给每个类有个作用域,此时我们采用将对象放到自定匿名函数的方式来解决,这一点和jQuery开发插件的有点类似。代码如下:
- /**
- * @author jasson
- * @include common.js
- */
- //对象存在就等于对象,对象不存在就创建{}
- var JassonChart = JassonChart || {};
- (function(){
- //构造函数定义对象的非函数属性
- function Person()
- {
- this.username = new Array();
- this.password = "123";
- }
- //通过原型方式定义对象的函数
- Person.prototype.getInfo = function()
- {
- alert(this.username+","+this.password);
- };
- //将该类放到JassonChart中,类似java中的包,或者C++中的
- JassonChart.Person= Person;
- }());
- //调用该类库中的Person类
- var p = new JassonChart.Person();
这样我们可以定义多个类,每个类都采用如上的方式实现,这样各个类相互都有作用域,非常规范。对于我们要用到的一些工具类,我们可以采用简单的对象进行定义,代码如下
- /**
- * @author jasson
- */
- var JassonChart = JassonChart || {};
- JassonChart .util = {
- constants : {
- WIDTH : 'width',
- HEIGHT : 'height',
- SVG : 'SVG',
- CANVAS : 'CANVAS',
- G : 'G', //svg element
- STRING : 'string'
- },
- distance : function(a, b) {
- var dx = a.x - b.x;
- var dy = a.y - b.y;
- return Math.sqrt(dx * dx + dy * dy);
- }
- };
2.Javascript对象的继承采用如下几种方式
2.1 Javascript对象的继承采用混合方式【构造函数 +原型方式(prototype)】
在JavaScript中最好的方式就是用混合方式实现对象间的继承。和定义对象一样,我们可以将属性和方法用不同的方式定义,用call或apply方式定义继承对象的属性,利用原型链的方式实现方法的继承。如下代码所示:
- //使用混合的方式实现对象的继承
- function Parent(hello)
- {
- this.hello = hello;//定义父类的属性
- }
- Parent.prototype.sayHello = function()//定义父类的方法
- {
- alert(this.hello);
- }
- function Child(hello,world)
- {
- Parent.call(this,hello);//继承父类的属性
- //or Parent.apply(this,arguments);//继承父类的属性
- this.world = world;
- }
- Child.prototype = new Parent();//继承父类的方法
- Child.prototype.sayWorld = function()
- {
- alert(this.world);
- }
- var child = new Child("hello","world");
- child.sayHello();
- child.sayWorld();
2.2 深度拷贝方法
所谓"深拷贝",就是能够实现真正意义上的数组和对象的拷贝。它的实现并不难,只要递归调用"浅拷贝"就行了。
- function deepCopy(p, c) {
- var c = c || {};
- for (var i in p) {
- if (typeof p[i] === 'object') {
- c[i] = (p[i].constructor === Array) ? [] : {};
- deepCopy(p[i], c[i]);
- } else {
- c[i] = p[i];
- }
- }
- return c;
- }
使用的时候这样写:
var Doctor = deepCopy(Chinese);
现在,给父对象加一个属性,值为数组。然后,在子对象上修改这个属性:
Chinese.birthPlaces = ['北京','上海','香港'];
Doctor.birthPlaces.push('厦门');
这时,父对象就不会受到影响了。
alert(Doctor.birthPlaces); //北京, 上海, 香港, 厦门
alert(Chinese.birthPlaces); //北京, 上海, 香港
目前,jQuery库使用的就是这种继承方法。