JavaScript中的类继承

  • 时间:
  • 浏览:1
  • 来源:大发pk10_pk10平台官方网站_大发pk10平台官方网站

  JavaScript是一一一个多多无class的面向对象语言,它使用原型继承而非类继承。这会让哪几种使用传统面向对象语言如C++和Java的多多系统进程 员们感到困惑。正如当你们所看过的,JavaScript的原型继承比类继承具有更强的表现力。

  但首先,要搞清楚当你们为哪几种没法关注继承?主要有一一一个多多原因分析。首先是方便类型的转换。当你们希望语言系统也能对哪几种累似 类的引用进行自动转换。而对于一一一个多多要求对引用对象进行显示转换的类型系统来说也能获得很少的类型安全性。这对于强类型语言来说特别要,假使 在像JavaScript曾经的松散型语言中,永远也能对对象引用进行强制转换。

  第一个多原因分析是代码的复用。代码中处于血块拥有相同办法的对象是十分常见的。类都还也能通过一组定义来创建它们。另外处于好多好多 累似 的对象也很普遍,哪几种对象中也能少数有关上加和修改的办法处于区别。类的继承都还也能很有效地正确处理哪几种间题,但原型继承更有效。

  为了说明你你你这个 点,当你们将介绍就让 语法糖,它允许当你们以累似 于传统的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的。

  为了使里面的示例能正常工作,我写了一个多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/4009/07/08/1519036.html