本文详解JavaScript中对象的定义与继承方法。推荐采用构造函数结合原型方式的混合模式来定义对象,以实现属性私有与方法共享。针对继承,介绍了利用call或apply结合原型链的混合继承,以及通过递归实现数组和对象真正拷贝的深拷贝方法,旨在提供优雅且高效的代码实现方案。
本文通过具体实例,详细解析JavaScript面向对象程序设计中的对象定义与继承机制,供读者参考学习。
在JavaScript面向对象编程中,追求代码的优雅与高效至关重要。尽管JavaScript没有类的概念,仅存在对象,但通过合理的设计,可以实现类似Java或C++的优雅风格,同时兼顾性能。JavaScript提供了多种对象定义与继承方式,经过实践验证,以下方法值得推荐。
1. JavaScript对象的定义:采用混合模式【构造函数 + 原型方式(prototype)】
(1)利用构造函数定义对象的所有非函数属性
(2)利用原型方式定义对象的函数属性
采用该模式,所有属性均为单一对象私有,而方法则为所有对象共有。这样既保证了对象间属性互不干扰,又实现了各个对象间对同一方法的共享。
//使用原型+构造函数方式来定义对象
//构造函数定义对象的非函数属性<strong>
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();
在实际开发中,若希望将各个类(实质为对象)像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); //北京, 上海, 香港
感兴趣的朋友可以使用在线HTML/CSS/JavaScript代码运行工具:http://tools.jb51.net/code/HtmlJsRun测试上述代码的运行效果。
更多关于JavaScript相关内容感兴趣的读者可查看本站专题:《javascript面向对象入门教程》、《JavaScript错误与调试技巧总结》、《JavaScript数据结构与算法技巧总结》、《JavaScript遍历算法与技巧总结》及《JavaScript数学运算用法总结》
希望本文所述对大家JavaScript程序设计有所帮助。