JavaScript中的类继承

  • 时间:
  • 浏览:0
  • 来源:幸运快3_快3高手计划_幸运快3高手计划

  JavaScript是兩个 多无class的面向对象语言,它使用原型继承而非类继承。这会让什么使用传统面向对象语言如C++和Java的任务管理器运行员们感到困惑。正如当当你们 所想看 的,JavaScript的原型继承比类继承具有更强的表现力。

  但首先,要搞清楚当当你们 为甚在么在这样 关注继承?主要有兩个 多原困分析。首先是方便类型的转换。当当你们 希望语言系统也能对什么类似 类的引用进行自动转换。而对于兩个 多要求对引用对象进行显示转换的类型系统来说也能了获得很少的类型安全性。这对于强类型语言来说一阵一阵要,并且我在像JavaScript原来的松散型语言中,永远不都要对对象引用进行强制转换。

  第3个原困分析是代码的复用。代码中趋于稳定几滴 拥有相同土办法的对象是十分常见的。类也后能 了通过一组定义来创建它们。另外趋于稳定并且类似 的对象也很普遍,什么对象中也能了少数有关加进和修改的土办法趋于稳定区别。类的继承也后能 了很有效地解决什么问题报告 ,但原型继承更有效。

  为了说明五种点,当当你们 将介绍一些语法糖,它允许当当你们 以类似 于传统的class的语言来编写代码。并且我当当你们 将介绍一些有用的模式,什么模式不适用于传统的class语言。最后,当当你们 将对语法糖进行解释。

  首先,当当你们 加进了兩个 多Parenizor类,含晒 set和get兩个 多土办法,分别用来设置和获取value,以及兩个 多toString土办法,用来对parens中的value进行包装。

function Parenizor(value) {
    this.setValue(value);
}

Parenizor.method('setValue', function (value) {
    this.value = value;
    return this;
});

Parenizor.method('getValue', function () {
    return this.value;
});

Parenizor.method('toString', function () {
    return '(' + this.getValue() + ')';
});

  语法看起来一阵一阵不太一样,并且愿意很好懂。土办法method接受土办法的名称和兩个 多function,并将五种function作为公共土办法加进到类中。

  并且我当当你们 也后能 了原来写:

myParenizor = new Parenizor(0);
myString = myParenizor.toString();

  正如你所期望的,myString的值为"(0)".

  现在当当你们 创建原来类继承Parenizor,除了toString土办法中对于value为空或0的情况报告会输出"-0-"外其余都和Parenizor相同。

function ZParenizor(value) {
    this.setValue(value);
}

ZParenizor.inherits(Parenizor);

ZParenizor.method('toString', function () {
    if (this.getValue()) {
        return this.uber('toString');
    }
    return "-0-";
});

  这里的inherits土办法与Java中的extends土办法类似 ,uber土办法也与Java中的super土办法类似 。它允许兩个 多土办法调用父类中的土办法(并且我改了名称以避开保留字的限制)。

  并且我当当你们 也后能 了原来写:

myZParenizor = new ZParenizor(0);
myString = myZParenizor.toString();

  五种次,myString的值为"-0-".

  JavaScript这样 类,并且我当当你们 也后能 了通过编程来实现它。

  通过操作兩个 多函数的原型对象,当当你们 也后能 了实现多重继承,从而使当当你们 也后能 了用多个类的土办法来构建兩个 多类。混合多重继承并且我难以实现,并并且我趋于稳定土办法名称的冲突。当当你们 也后能 了在JavaScript中实现混合多重继承,并且我在本例中当当你们 将使用兩个 多更严格的被称之为Swiss继承的形式。

  假设兩个 多多NumberValue类,含晒 兩个 多土办法setValue,该土办法检查value算是为某个特定范围内的数字,必要的随时会抛出异常。当当你们 只都要ZParenizorsetValuesetRange土办法,而不都要toString土办法。这样 当当你们 也后能 了原来写:

ZParenizor.swiss(NumberValue, 'setValue', 'setRange');

  原来只会将当当你们 都要的土办法加进到类中。

  ZParenizor还有另外五种写法。除了从Parenizor类继承,当当你们 还也后能 了在构造函数中调用Parenizor的构造函数,并传递返回的结果。通过五种土办法,当当你们 给构造函数加进特权土办法,而无需再去为其加进公共土办法。

function ZParenizor2(value) {
    var that = new Parenizor(value);
    that.toString = function () {
        if (this.getValue()) {
            return this.uber('toString');
        }
        return "-0-"
    };
    return that;
}

  类的继承是is-a关系(公有继承),而寄生继承是was-a-but-now's-a关系(私有继承与公有继承)。构造函数在对象的构造中发挥了很大的作用。注意ubersuper土办法仍然可用于特权土办法。

  JavaScript的动态性允许当当你们 加进或替换现有类的土办法,method土办法也后能 了随时被调用,原来类的所有实例在现在和将来时会有五种土办法。当当你们 也后能 了在任何并且对兩个 多类进行扩展。继承具有追溯性,当当你们 把五种叫做类的扩充(Class Augmentation),以解决与Java的extends产生混淆。

  在静态面向对象语言中,并且我你愿意兩个 多对象与原来对象略微不同,就都要定义兩个 多新的类。在JavaScript中,你也后能 了将土办法加进到单个的对象中,而不都要在定义额外的类。五种非常强大,并且我你只都要写很少的类,并且我类都也后能 了很简单。回想一下,JavaScript对象就像哈希表,你也后能 了随时加进新的值,并且我值是function,这样 它就成了兩个 多土办法。

  并且我在上方的示例中,我根本不都要ZParenizor类。你也后能 了要简单地修改我的实例。

myParenizor = new Parenizor(0);
myParenizor.toString = function () {
    if (this.getValue()) {
        return this.uber('toString');
    }
    return "-0-";
};
myString = myParenizor.toString();

  我将toString土办法加进到我的myParenizor实例中,而这样 使用任何形式的继承。当当你们 也后能 了修改单个的实例,并且我语言是无class的。

  为了使上方的示例能正常工作,我写了3个sugar土办法。首先是method土办法,它将兩个 多实例土办法加进到类中。

Function.prototype.method = function (name, func) {
    this.prototype[name] = func;
    return this;
};

  它在Function.prototype加进进了兩个 多公共土办法,并且我所有的函数都通过Class Augmentation(类的扩充)获得了该土办法。它接受兩个 多名称和兩个 多函数,并将它们加进到函数的原型对象中。

  它返回this. 当我编写兩个 多不都要返回值的土办法时,我通常时会返回this,原来就具有了兩个 多级联式的编程风格。

  接下来是inherits土办法,它用来表示兩个 多类从原来类继承。应该在兩个 多类都被定义并且再调用五种土办法,并且我在继承类的土办法并且加进该土办法。

Function.method('inherits', function (parent) {
    this.prototype = new parent();
    var d = {}, 
        p = this.prototype;
    this.prototype.constructor = parent; 
    this.method('uber', function uber(name) {
        if (!(name in d)) {
            d[name] = 0;
        }        
        var f, r, t = d[name], v = parent.prototype;
        if (t) {
            while (t) {
                v = v.constructor.prototype;
                t -= 1;
            }
            f = v[name];
        } else {
            f = p[name];
            if (f == this[name]) {
                f = v[name];
            }
        }
        d[name] += 1;
        r = f.apply(this, Array.prototype.slice.apply(arguments, [1]));
        d[name] -= 1;
        return r;
    });
    return this;
});

  当当你们 继续对Function进行扩充。当当你们 创建了兩个 多父类的实例,并将其作为新的原型。当当你们 还修改了构造函数的字段,并将uber土办法加进到原型中。

  Uber土办法在被委托人的原型中查找指定的土办法。这是在寄生继承或对象扩充的情况报告下调用的函数。并且我当当你们 进行类的继承,这样 当当你们 就都要在父类的原型中找到五种函数。Return一句话使用函数的apply土办法来调用function,显示地设置this并传递兩个 多数组参数。参数(并且我有一句话)从arguments数组中获取。可惜arguments数组有的是兩个 多真正的数组,并且当当你们 不得不再次使用apply来调用的slice土办法。

  最后,是swiss土办法。

Function.method('swiss', function (parent) {
    for (var i = 1; i < arguments.length; i += 1) {
        var name = arguments[i];
        this.prototype[name] = parent.prototype[name];
    }
    return this;
});

  Swiss土办法对arguments进行遍历。对每兩个 多name,它都从父类的原型中克隆技术兩个 多成员到新类的原型中。

  JavaScript也后能 了像class语言一样来使用,但它也具有相当独特的表现力。当当你们 研究了类的继承,Swiss继承,寄生继承,类的扩充以及对象的扩充。五种几滴 代码的复用模式来自于五种被认为比Java更小,更简单的语言。

  类的对象非常严格,要将兩个 多新成员加进到对象中,唯一的土办法并且我创建兩个 多新类。而在JavaScript中,对象是松散的,也后能 了通过简单的赋值操作将兩个 多新成员加进到对象中。

  并且我JavaScript中的对象非常灵活,并且你都要对类的层次行态进行不同的考虑。层厚次的行态无需太适用,相反,浅层次的行态更高效,更具有表现力。

我从事编写JavaScript代码并且我有14年了,并且我我从来这样 发现都要使用uber函数。Super在class模式中十分重要,并且我在原型和函数式模式含晒 的是都要的。现在看来我早期尝试在JavaScript中支持class模式是兩个 多错误。

原文地址:Classical Inheritance in JavaScript

相关链接:http://www.cnblogs.com/sanshi/archive/1509/07/08/1519036.html