JavaScript中的类继承

  • 时间:
  • 浏览:29
  • 来源:5分时时彩官网_5分时时彩玩法_5分时时彩技巧

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

  但首先,要搞清楚亲戚朋友为哪几种这样 关注继承?主要有一个 原因分析分析。首先是方便类型的转换。亲戚朋友希望语言系统也能对哪几种同类类的引用进行自动转换。而对于一一个 要求对引用对象进行显示转换的类型系统来说这样 获得很少的类型安全性。这对于强类型语言来说很重要,以后 在像JavaScript可是我 的松散型语言中,永远不时需对对象引用进行强制转换。

  第5个原因分析分析是代码的复用。代码中所处少许拥有相同法子的对象是十分常见的。类还都还可不可以通过一组定义来创建它们。另外所处太满同类的对象也很普遍,哪几种对象中这样 少数有关加进去去和修改的法子所处区别。类的继承还都还可不可以很有效地出理 哪几种问题,但原型继承更有效。

  为了说明你这种 点,亲戚朋友将介绍以后 语法糖,它允许亲戚朋友以同类于传统的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的。

  为了使上方的示例能正常工作,我写了5个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,它都从父类的原型中克隆qq一一个 成员到新类的原型中。

  JavaScript还都还可不可以像class语言一样来使用,但它也具有相当独特的表现力。亲戚朋友研究了类的继承,Swiss继承,寄生继承,类的扩充以及对象的扩充。你这种 少许代码的复用模式来自于本身被认为比Java更小,更简单的语言。

  类的对象非常严格,要将一一个 新成员加进去去到对象中,唯一的法子可是我创建一一个 新类。而在JavaScript中,对象是松散的,还都还可不可以通过简单的赋值操作将一一个 新成员加进去去到对象中。

  以后 JavaScript中的对象非常灵活,太满你时需对类的层次外部进行不同的考虑。层厚次的外部并不太适用,相反,浅层次的外部更高效,更具有表现力。

我从事编写JavaScript代码以后 有14年了,以后 我从来这样 发现时需使用uber函数。Super在class模式中十分重要,以后 在原型和函数式模式中全部都是 时需的。现在看来我早期尝试在JavaScript中支持class模式是一一个 错误。

原文地址:Classical Inheritance in JavaScript

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