大发快3_快3诀窍_大发快3诀窍 - 大发快3,快3诀窍,大发快3诀窍是新浪网最重要的频道之一,24小时滚动报道国内、国际及社会新闻。每日编发新闻数以万计。

JavaScript中的类继承

  • 时间:
  • 浏览:0

  JavaScript是有俩个 无class的面向对象语言,它使用原型继承而非类继承。这会让哪此使用传统面向对象语言如C++和Java的tcp连接员们感到困惑。正如让我们所想看 的,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,它都从父类的原型中克隆qq有俩个 成员到新类的原型中。

  JavaScript还都要像class语言一样来使用,但它也具有相当独特的表现力。让我们研究了类的继承,Swiss继承,寄生继承,类的扩充以及对象的扩充。这俩 血块代码的复用模式来自于这俩被认为比Java更小,更简单的语言。

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

  意味JavaScript中的对象非常灵活,有些你都要对类的层次外部进行不同的考虑。宽度次的外部暂且太适用,相反,浅层次的外部更高效,更具有表现力。

我从事编写JavaScript代码意味有14年了,因此我从来越来越发现都要使用uber函数。Super在class模式中十分重要,因此在原型和函数式模式中都不 都要的。现在看来我早期尝试在JavaScript中支持class模式是有俩个 错误。

原文地址:Classical Inheritance in JavaScript

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