【问题标题】:Advanced JavaScript Inheritance in TypeScriptTypeScript 中的高级 JavaScript 继承
【发布时间】:2018-10-01 17:32:49
【问题描述】:

TypeScript 中的高级 JavaScript 继承

JavaScript 的优点之一是对象可以从其他对象继承封装的多种不同方式。但是,从这个角度来看,TypeScript 对编写模块的可能性施加了很大的限制。

在 JavaScript 中,您可以选择通过使用 Constructor Hijacking 来实现多重继承——更确切地说是 Mixin 功能,这是该语言非常强大的特性:

var Base = function Base() {

    function f() {
        console.log('datum: %s', this.datum);
    }

    function method() {
        this.a();
        this.b();
        this.c();
    }

    // export precepts
    this.datum = true;
    this.f = f;
    this.method = method;

    return this;
};

var A = function A() {

    function a() {
        this.f();
    }

    // export precepts
    this.a = a;

    return this;
};
var B = function B() {

    function b() {
        this.f();
    }

    // export precepts
    this.b = b;

    return this;
};
var C = function C() {

    function c() {
        this.f();
    }

    // export precepts
    this.c = c;

    return this;
};

var Klass = function Klass() {
    var config = { };

    function init() {
        this.method();
    }

    // export precepts
    Base.call(this);
    A.call(this);
    B.call(this);
    C.call(this);
    this.config = config;
    this.init = init;

    return this;
};

var klass = new Klass();
klass.init();
// > datum: true
// > datum: true
// > datum: true

这允许开发人员将他们的代码分解为离散的模块,这些模块只需要遵循某种模式或约定即可扩展另一个模块,同时保持 SOLID 的单一职责原则和开闭原则。

分析

上面的代码应该记录字符串datum: true 3 次。这是因为Klass 装饰(或混入)Base 类,以便类A-C 在调用this.f 时不会引发运行时错误。进程的 CallStack 如下所示:

  • [类]初始化
  • [基础]方法
  • [A] 一个
  • [基础] f
  • [控制台]日志
  • [B] b
  • [基础] f
  • [控制台]日志
  • [C] c
  • [基础] f
  • [控制台]日志

注意事项

CallStack 是相当随意和琐碎的。此外,此代码可以被视为非 SOLID,但假设我们使用的是模板方法模式,如果它有助于避免示例的粗糙性。

此外,毫无疑问,会有一个灵魂说出我们所知道的关于上述示例的所有内容是如何违反 TypeScript 的。请记住,“TypeScript 是 JavaScript 的超集”是简单的、明显的、明显的错误——我什至不会争论为什么,如果你使用 TypeScript,你应该已经知道这一点。

问题:

鉴于上面的代码,如何使用有效的 TypeScript 语法实现这样的功能?如有必要,我也愿意利用设计模式,尽管这仍然不理想。

【问题讨论】:

  • 这不是调用 stack。如果你想显示由谁调用的顺序,你需要调用 tree
  • 您的代码可能违反 TypeScript 设计准则,但几乎不违反 TypeScript 语法 - 每个 JS 程序都是有效的 TypeScript 程序。
  • @Bergi 我同意你评论的前半部分,但“有效”这个词可能会产生误导。原理(不知道有没有小例外)是每个JS程序都是语法上有效的TypeScript程序,编译成和原来等效的JS程序,但是TypeScript程序可能有类型错误。
  • @MattMcCutchen IIIRC,没有任何类型注释,一切都是Any类型,不会有错误?
  • @Bergi 不,文字(原始、数组、对象和函数)仍有一些类型信息,例如,(2).slice() 是类型错误。你的似乎是一个普遍的误解。你知道我们应该在哪里更新文档来反驳它吗?

标签: javascript typescript inheritance design-patterns solid-principles


【解决方案1】:

Mixins 给你大部分你想要的东西。你的例子是:

class Base { 
    datum = true;
    // We can't make these methods abstract because TypeScript currently
    // doesn't support tracking whether mixins implement abstract methods. 
    a() {
        throw new Error("not implemented");
    }
    b() {
        throw new Error("not implemented");
    }
    c() {
        throw new Error("not implemented");
    }
    f() {
        console.log('datum: %s', this.datum);
    }
    method() { 
        this.a();
        this.b();
        this.c();
    }
}

function mixA<Orig extends {new(...args: any[]): Base}>(base: Orig) { 
    return class extends base {
        a() {
            this.f();
        }
    };
}
function mixB<Orig extends {new(...args: any[]): Base}>(base: Orig) { 
    return class extends base {
        b() {
            this.f();
        }
    };
}
function mixC<Orig extends {new(...args: any[]): Base}>(base: Orig) { 
    return class extends base {
        c() {
            this.f();
        }
    };
}

class Klass extends mixA(mixB(mixC(Base))) { 
    config = {};
    init() { 
        this.method();
    }
}

var klass = new Klass();
klass.init();

【讨论】:

    猜你喜欢
    • 2012-08-02
    • 1970-01-01
    • 2021-01-29
    • 2017-05-02
    • 1970-01-01
    • 2016-11-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多