JavaScript中的继承机制

JS面向对象实践
本文介绍JavaScript如何通过prototype属性实现继承,以及如何通过隐蔽私有属性提高数据安全性,并探讨基于类的继承方法。
相信很多熟悉像c++,java面向对象语言的朋友们在开始接触javascript时都会有种迷失的感觉。都说javascript是基于对象而不是面向对象,那“基于”与“面向”到底有什么不同,这种机制体现在哪些方面,如何采用它所提供的机制建立面向对象的javascript。针对这些问题,本人查阅资料,整理如下,希望对大家有所帮助。(具备且仅具备基本的javascript知识即可)

[b]1. 通过prototype属性建立面向对象的javascript[/b]

每个javascript对象都有一个内置的属性,名为prototype,用它来保存对另一个对象的引用,javascript就是利用这个引用来保存其父对象。所以,javascript通过链接机制来支持继承,这种继承结构更像是一种“has a”而不是“is a”关系。
当通过点记法引用对象的一个函数或属性时,会先从对象本身定义的函数或属性中去找,倘若没有,会从prototype所引用的对象(父对象)中寻找,如果找到则终止,倘若仍然没有找到,再从父对象的父对象中寻找,直到找到,或到达链顶仍然没有,返回undefined。
并且值得注意的是,prototype的引用可以在运行时动态更改,而不需要重新编译(基于文本,解释执行)。虽然对prototype这种继承机制褒贬不一,但其的确可以提供强大并且健壮的多态性。

下面用一个例子简单描述这种继承方式:
基类一:Vehicle

function Vehicle(){}
Vehicle.prototype.wheelCount=4;
Vehicle.prototype.capability=5;
Vehicle.prototype.refuel=function(){
return "refuel every 300 km";
}
Vehicle.prototype.mainTasks=function(){
return "for driving";
}

子类一:Car

function Car(){}
/*extends Vehicle*/
Car.prototype=new Vehicle();
/*overwrite below*/
Car.prototype.capability=4;
Car.prototype.refuel=function(){
return "refuel every 200 km";
}
Car.prototype.mainTasks=function(){
return "for driving to school, work...";
}

子类二:Bus

function Bus(){}
/*extends Vehicle*/
Bus.prototype=new Vehicle();
/*overwrite below*/
Bus.prototype.wheelCount=8;
Bus.prototype.capability=40;
Bus.prototype.mainTasks=function(){
return "for serving citizens";
}

使用(分别调用create*生成对象并予以描述):

function describe(vehicle){
var des="";
des = des + "Number of wheel: " + vehicle.wheelCount;
des = des + "\nCapability: " + vehicle.capability;
des = des + "\nRefuel(): " + vehicle.refuel();
des = des + "\nMainTasks(): " + vehicle.mainTasks();
alert(des);
}
function createVehicle(){
var vehicle = new Vehicle();
describe(vehicle);
}
function createCar(){
var car = new Car();
describe(car);
}
function createBus(){
var bus = new Bus();
describe(bus);
}


[b]2. 隐蔽私有属性,提高安全性[/b]

细心的您一定注意到了上面的例子已经涵盖了继承和多态,但铁杆的OO Fans一定不会放过封装,因为这涉及到数据的安全性。针对这一问题,Douglas Crockford(http://www.crockford.com)提出了一种在javascript中创建私有属性的方法,大致如下:
a. 私有属性在构造函数中使用var关键字定义;
b. 私有属性只能由特权函数(privileged function)公用访问,此类函数就是在构造函数中用this关键字定义的函数。外部客户可以通过访问特权函数访问对象的私有属性。(类似于set get方法)

下面同样用例子来描述:
基类二:Vehicle

function Vehicle(){
var wheelCount = 4;
var capability = 5;

this.getWheelCount = function(){
return wheelCount;
}
/*other setter and getter functions omitted*/
……
this.refuel = function(){
return "refuel every 300 km";
}
this.mainTasks=function(){
return "for driving";
}
}

注意这里的两个属性都用var关键字所修饰,它们不再是公有,访问与修改它们必须通过调用相应的公有函数完成。倘若尝试直接使用,如vehicle.wheelCount会返回undefined。

[b]3. javascript中基于类的继承[/b]

如果你不想使用在1中介绍的基于prototype的继承方法,那么你可以采用本节介绍的,通过一个通用脚本从一个对象继承属性和函数的方式达到你的目标。这里所谓的继承其实是将“父”对象的属性和函数简单复制到“子”对象,从而创建这种继承关系。
由Netscape的Bob Clary提出的这个通用函数如下:

function createInheritance(parent, child){
var property;
for(property in parent){
if(!child[property]){
child[property] = parent[property];
}
}
}

上面代码清晰易懂,再配以使用代码,就不用解释了:

var child = new Child();
createInheritance(new Parent(), child);

这样便可以把父对象中有,而子对象中没有的属性和函数复制到子对象中来。

[b]4. 结合信息隐藏与新的继承方式[/b]

这里我们结合使用信息隐藏与3中介绍的新的继承方式重写开头的例子:
基类:同2中“基类二”代码(已实现隐藏)
子类一:Car

function Car(){
this.refuel=function(){
return "refuel every 200 km";
}
this.mainTasks=function(){
return "for driving to school, work...";
}
}

子类二:Bus

function Bus(){
this.mainTasks=function(){
return "for serving citizens";
}
}

注意这里的Car和Bus并没有wheelCount和capability属性,Bus还没有refuel函数。它们需要等待客户端代码赋予这些属性和函数,继承关系由客户端指定。

再来看客户端代码:

function createInheritance(parent, child){
var property;
for(property in parent){
if(!child[property]){
child[property] = parent[property];
}
}
}
function createCar(){
var car = new Car();
createInheritance(new Vehicle(), car);
car.setCapability(5);
describe(car);
}
function createBus(){
var bus = new Bus();
createInheritance(new Vehicle(), bus);
car.setCapability(40);
describe(bus);
}
funfunction describe(vehicle){
var des="";
des = des + "Number of wheel: " + vehicle.wheelCount;
des = des + "\nCapability: " + vehicle.capability;
des = des + "\nRefuel(): " + vehicle.refuel();
des = des + "\nMainTasks(): " + vehicle.mainTasks();
alert(des);
}

读到这里相信你已经有所体会javascript基于对象与面向对象的区别。
本文主要从Foundations of Ajax chapter5 整理而来,由于时间关系代码未经调试运行,目的只在于说明其意,还请海涵!
本研究基于扩展卡尔曼滤波(EKF)方法,构建了一套用于航天器姿态与轨道协同控制的仿真系统。该系统采用参数化编程设计,具备清晰的逻辑结构和详细的代码注释,便于用户根据具体需求调整参数。所提供的案例数据可直接在MATLAB环境中运行,无需额外预处理步骤,适用于计算机科学、电子信息工程及数学等相关专业学生的课程设计、综合实践或毕业课题。 在航天工程实践中,精确的姿态与轨道控制是保障深空探测、卫星组网及空间设施建设等任务成功实施的基础。扩展卡尔曼滤波作为一种适用于非线性动态系统的状态估计算法,能够有效处理系统模型中的不确定性与测量噪声,因此在航天器耦合控制领域具有重要应用价值。本研究实现的系统通过模块化设计,支持用户针对不同航天器平台或任务场景进行灵活配置,例如卫星轨道维持、飞行器交会对接或地外天体定点着陆等控制问题。 为提升系统的易用性与教学适用性,代码中关键算法步骤均附有说明性注释,有助于用户理解滤波器的初始化、状态预测、观测更新等核心流程。同时,系统兼容多个MATLAB版本(包括2014a、2019b及2024b),可适应不同的软件环境。通过实际操作该仿真系统,学生不仅能够深化对航天动力学与控制理论的认识,还可培养工程编程能力与实际问题分析技能,为后续从事相关技术研究或工程开发奠定基础。 资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值