JavaScript函数继承

本文介绍了JavaScript中的两种主要继承方法:类式继承和原型继承。通过示例详细解释了如何使用构造函数和原型链实现继承,以及如何利用extend函数简化类继承的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转载地址: http://www.cnblogs.com/Guazi-JS/articles/1698628.html


JavaScript是一种弱类语言没有像那些强类型的语言那样有一个独一无二的继承方法来完成相关函数之间的继承关系,在JavaScript中如果想达到继承的效果就要采取一系列的措施。JavaScript属于使用原型式继承的少数语言之一。

  不多废话,进入主题。JavaScript继承的方法有很多种,分别是:“类式继承”,“原型式继承”。我目前就知道这些,可能还有其他方法继承就请大家补充一下了。

  一、类式继承

    下面让我们看一下例子:

function Box(name){
    this.name = name;
}
Box.prototype.getName = function(){
    return this.name;
}

我们首先要创建一个构造函数,类名按惯例首字母应该大写。要想创建该类的实例,只需要用关键字new来调用这个构造函数即可:

var smallBox = new Box('Small Box');
smallBox.getName();

这样我们就可以得到Box的name名字了。现在要继承Box的类可能要稍微复杂些:

function BigBox(name, color){
    Box.call(this, name);
    this.color = color;
}
 
BigBox.prototype = new Box();
BigBox.prototype.constructor = BigBox;
BigBox.prototype.getColor = function(){
    return this.color;
}

让一个类继承另一个类需要用许多行代码来完成。首先要像上面的示例一样创建一个构造函数。在构造函数中,调用超类的构造函数,并将参数name传给它。稍微解释一下这行代码,在使用new运算符的时候,系统会为你做一些事。它先创建一个空对象,然后调用构造函数,在此过程中这个空对象处于作用域链的最前端。面在BigBox函数中调用超类的构造函数时,你必须手工完成同样的任务"Box.call(this, name)"这条语句调用了Box构造函数,并且在此过程中让那个空对象(用“this”代表)处于作用域链的最前端,而name则被作为参数传入。

  具体的实现过程如下: 

var bigBox = new BigBox('bigbox', 'red');
  bigBox.getName();
  bigBox.getColor();

二、extend函数

    为了简化声明可以将派生子类的整个过程包装在一个名为extend的函数中。它的作用与其他语言中的extend关键字类似,即基于一个给定的类结构创建一个新的类:

/* Extend function */
 
function extend(subClass, superClass){
    var F = function();
 
    F.prototype = superClass.prototype;  // 只继承了superClass超级类中的方法并不包括属性(如果是定义在构造函数中,不在prototype里)
    subClass.prototype = new F();  // 因为F()函数只继承了超级类中prototype中的方法并没有其相关属性,所以subClass.prototype也只有superClass中的方法。
    subClass.prototype.constructor = subClass;
 
    subClass.superclass = superClass.prototype;
    if(superClass.prototype.constructor == Object.prototype.constructor){
        superClass.prototype.constructor = superClass;
    }
}

那上一个问题用extend()继承就变成如下形式:
/* Box Class */
 
function Box(name){
    this.name = name;
}
 
Box.prototype.getName = function(){
    return this.name;
}
 
 
/* BigBox Class */
 
function BigBox(name, color){
    Box.call(this, name);  // 向父类中传入参数且继承了父类中的相关属性
    this.color = color;
}
 
extend(BigBox, Box);  // 只继承了Box构造函数中的相关方法而不包括属性
 
BigBox.prototype.getColor = function(){
    return this.color;
}

注:其中“Box.call(this, name)”也可以等价为“BigBox.superclass.constructor.call(this, name)”,向构造函数中传入参数。这两种写法是同等的效果。如果在子类中又想调用父类中的某个方法也可以进行如下操作“BigBox.superclass.getName.call(this)”,向构造函数中的方法传入参数。因此有了superclass属性就可以直接调用超类中的方法。

  

  三、原型继承

    原型继承与类式继承截然不同。在我们谈到它的时候,最好忘掉自己关于类和实例的一切知识,只从对象的角度来思考。使用原型式继承时,并不需要用类来定义对象的结构,只需直接创建一个对象即可。这个对象随后可以被新的对象重用,这得得益于原型链查找的工作机制。该对象被称为原型对象(prototype object),这是因为它为其他对象应有的模样提供了一个原型。这正是原型式继承这个名称的由来。

    下面我们仍然用类继承的例子来重新设计一个由原型继承的操作:

/* Box Prototype Ojbect */
 
var Box = {
    name : 'Box Object',
    getName : function(){
        return this.name;
    }
}

我们在这里并没用到一外名为Box的构造函数来定义类的结构,Box现在是一个对象字面量。它是所有创建的其他各种类Box对象的原型。其中也定义了所有类Box对象都要具备的属性和方法,并为它们提供了默认值。方法的默认值可能不会被改变,但属性的默认值一般都会被改变:
var smallBox = clone(Box);
alert(smallBx.getName());        // 输出默认值“Box Object”
smallBox.name = 'Small Box';
alert(smallBox.getName());     // 输出新值“Small Box”

clone函数我稍后再隆重推出,先卖个官司!clone函数可以用来创建新的类Box对象。它会创建一个空对象,而该对象的原型对象被设置成为Box。这意味着在这个新对象中查找某个属性时,如果找不到,那么查找过程会在其原型对象中继续进行。

  你不必为创建BigBox而定义一个Box的子类,只要执行一次克隆即可:

/* BigBox Prototype Object */
 
var BigBox = clone(Box);
BigBox.colors = [];
Bigbox.getColors = function(){
    retrun this.colors;
}

然后你可以重新定义该克隆中的方法和属性。可以修改在Box中提供的默认值,也可以添加新的属性和方法。这样一来就伊娃了一个新的原型对象,你可以将其用于创建新的类BigBox对象。
var bigBox = [];
 
bigBox[0] = clone(BigBox);
bigBox[0].name = 'Big box 1';
bigBox[0].colors = ['red'];
 
bigBox[1] = clone(BigBox);
bigBox[1].name = 'Big box 2';
bigBox[1].colors = ['green'];
 
bigBox[1].getName();
bigBox[1].getColors();

现在我们就来看看在这原型继承中起到关键性作用的clone函数:

/* Clone function */
 
function clone(object){
    var F = function(){};
 
    F.prototype = object;  // 相当于如下定义:F.prototype = {name : 'Box Object', getName : function(){return this.name}}
    return new F;
}

clone函数首先是创建了一个新的空函数F,然后将F的prototype属性设置为作为参数object传入的原型对象。prototype属性就是用来指向原型对象的,通过原型链接机制,它提供了到所有继承而来的成员的链接。该函数最后通过把new运算符作用于F创建出一个新对象,然后把这个新对象作为返回值返回。函数所返回的这个克隆结果是一个以给定对象为原型对象的空对象。

  继承的主要好处表现在代码的重用方面。通过建立类或对象之间的继承关系,有些方法我们只需要定义一次即可。各种继承都有自己的优缺点。在内存效率比较重要的场合原型式继承(及clone函数)是最佳选择。如果与对象打交道的都是些只熟悉其他面向对象语言中的继承机制的程序员,那么最好使用类式继承(及extend函数)。这两种方法都适合球类 间差异较小的类层次体系。



内容概要:本文深入探讨了Kotlin语言在函数式编程和跨平台开发方面的特性和优势,结合详细的代码案例,展示了Kotlin的核心技巧和应用场景。文章首先介绍了高阶函数和Lambda表达式的使用,解释了它们如何简化集合操作和回调函数处理。接着,详细讲解了Kotlin Multiplatform(KMP)的实现方式,包括共享模块的创建和平台特定模块的配置,展示了如何通过共享业务逻辑代码提高开发效率。最后,文章总结了Kotlin在Android开发、跨平台移动开发、后端开发和Web开发中的应用场景,并展望了其未来发展趋势,指出Kotlin将继续在函数式编程和跨平台开发领域不断完善和发展。; 适合人群:对函数式编程和跨平台开发感兴趣的开发者,尤其是有一定编程基础的Kotlin初学者和中级开发者。; 使用场景及目标:①理解Kotlin中高阶函数和Lambda表达式的使用方法及其在实际开发中的应用场景;②掌握Kotlin Multiplatform的实现方式,能够在多个平台上共享业务逻辑代码,提高开发效率;③了解Kotlin在不同开发领域的应用场景,为选择合适的技术栈提供参考。; 其他说明:本文不仅提供了理论知识,还结合了大量代码案例,帮助读者更好地理解和实践Kotlin的函数式编程特性和跨平台开发能力。建议读者在学习过程中动手实践代码案例,以加深理解和掌握。
内容概要:本文深入探讨了利用历史速度命令(HVC)增强仿射编队机动控制性能的方法。论文提出了HVC在仿射编队控制中的潜在价值,通过全面评估HVC对系统的影响,提出了易于测试的稳定性条件,并给出了延迟参数与跟踪误差关系的显式不等式。研究为两轮差动机器人(TWDRs)群提供了系统的协调编队机动控制方案,并通过9台TWDRs的仿真和实验验证了稳定性和综合性能改进。此外,文中还提供了详细的Python代码实现,涵盖仿射编队控制类、HVC增强、稳定性条件检查以及仿真实验。代码不仅实现了论文的核心思想,还扩展了邻居历史信息利用、动态拓扑优化和自适应控制等性能提升策略,更全面地反映了群体智能协作和性能优化思想。 适用人群:具备一定编程基础,对群体智能、机器人编队控制、时滞系统稳定性分析感兴趣的科研人员和工程师。 使用场景及目标:①理解HVC在仿射编队控制中的应用及其对系统性能的提升;②掌握仿射编队控制的具体实现方法,包括控制器设计、稳定性分析和仿真实验;③学习如何通过引入历史信息(如HVC)来优化群体智能系统的性能;④探索中性型时滞系统的稳定性条件及其在实际系统中的应用。 其他说明:此资源不仅提供了理论分析,还包括完整的Python代码实现,帮助读者从理论到实践全面掌握仿射编队控制技术。代码结构清晰,涵盖了从初始化配置、控制律设计到性能评估的各个环节,并提供了丰富的可视化工具,便于理解和分析系统性能。通过阅读和实践,读者可以深入了解HVC增强仿射编队控制的工作原理及其实际应用效果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值