我可以在Javascript / Typescript中的函数内以编程方式调用另一个具有相同名称的函数吗?

时间:2017-05-12 01:58:20

标签: javascript typescript

我实际上是在打字稿中处理这个,但我会用Javascript写这个问题。两者的答案都很棒。

我有两个基本上具有相同界面的对象。我想创建一个具有相同接口的第三个对象,每个函数只调用contains中两个对象的方法。有没有办法以编程方式创建所有功能,所以我不必全部输入它们?

c = console.log;  // shorthand
obj1 = function() {}
obj1.prototype = {
  foo: (x) => { c("1" + x) },
  bar: (x, y) => { c("1" + x + y) }
}
obj2 = function() {}
obj2.prototype = {
  foo: (x) => { c("2" + x) },
  bar: (x, y) => { c("2" + x + y) }
}

obj3 = function() {
  this.o1 = new obj1()
  this.o2 = new obj2()
}
obj3.prototype = {
  foo: function(x) {
    this.o1.foo(x);
    this.o2.foo(x);
  },
  bar: function(x, y) {
    this.o1.bar(x, y);
    this.o2.bar(x, y);
  }
}

我正在寻找一种方法来编写obj3,而不必手动写出每个成员函数,因为我有很多成员函数。

4 个答案:

答案 0 :(得分:2)

您可以使用Proxy对象:

function multiproxy(objects) {
    return new Proxy(objects[0], {
        get: function(target, name) {
            var that = this;

            return function() {
                var result;

                for (let obj of objects) {
                    result = obj[name].apply(that, arguments);
                }

                return result;
            };
        }
    });
}

所以在你的情况下,你会这样做:

var instance3 = multiproxy([new obj1(), new obj2()]);

现在,instance3的行为与obj1相似,但在obj2上调用相同的方法。

这不会处理对象的非功能属性,但添加起来并不困难。

答案 1 :(得分:0)

您需要复制以下对象:

// Shallow copy
this.o1 = jQuery.extend({}, obj1);

// Deep copy
this.o1 = jQuery.extend(true, {}, obj1);

Difference between shallow copy and deep copy

或者,纯JavaScript版本:

this.o1 = Object.assign({}, obj1);

您需要阅读Object.assign()来研究细节。如果你没有进行深层复制而是浅层复制对象,可能会产生意想不到的影响。

一小时后:

经过多次实验后,我意识到obj3构造函数函数无法创建新对象,所以我决定移出克隆部分。根据我的观察,这段代码按预期工作:

c = console.log;  // shorthand
obj1 = function() {}
obj1.prototype = {
  foo: (x) => { c("1" + x) },
  bar: (x, y) => { c("1" + x + y) }
}
obj2 = function() {}
obj2.prototype = {
  foo: (x) => { c("2" + x) },
  bar: (x, y) => { c("2" + x + y) }
}

obj3 = function() {
  this.o1;
  this.o2;
}
obj3.prototype = {
  foo: (x) => {
    obj3.o1.foo(x);
    obj3.o2.foo(x);
  },
  bar: (x, y) => {
    obj3.o1.bar(x, y);
    obj3.o2.bar(x, y);
  }
}

obj3.o1 = $.extend(true, {}, obj1.prototype); // jQuery or
obj3.o2 = Object.assign({}, obj2.prototype); // Pure JavaScript
obj3.prototype.foo(5);
obj3.prototype.bar(3,4);

答案 2 :(得分:0)

您可以使用字典语法访问方法:

var a = "Hello world";
a.toUpperString(); // returns "HELLO WORLD"
a["toUpperString"](); // same as above

所以一般方法是先实现一个较低级别的方法:

假设您有对象a,其中包含对bc的引用

function callMethod(a, methodName) {
    // You might want to add some error checking
    a.b[methodName]()
    a.c[methodName]()
}

现在,您可以致电callMethod(a, "something"),然后致电a.b.something()a.c.something()

这不是一个完整的答案,但我认为它应该足以让你开始。

由于原型本身就是简单的词典,因此您可以轻松地在一个对象的原型中列出方法,并将方法添加到另一个对象的原型中。

答案 3 :(得分:0)

Blender展示了如何通过代理服务器完成这项工作,但是我有兴趣在没有大量额外工作/投射的情况下获得可用的打字。

这是一个以几乎相同的方式执行的解决方案,可以避免在IE / iOS 9中支持代理问题。

function ClassMerger<T extends Object>(...classes: T[]): Partial<T> {
    // Helper to create a function that calls a method on all passed instances
    let call = (method: keyof T) => (...args: any[]) => {
        for (let instance of classes) {
            if (typeof instance[method] == 'function') {
                // Typescript's type checking fails here for some reason.
                (instance[method] as Function).apply(instance, args);
            }
        }
    }

    let merged: Partial<T> = {};

    // Loop through each class, adding all methods to the merged object
    for (let instance of classes) {
        for (let method in instance) {
            if (typeof instance[method] == 'function' && !merged[method]) {
                merged[method] = call(method);
            }
        }
    }

    return merged;
}

// Usage (with your example objects):
let merged = ClassMerger<{foo: (a: string) => void}>(new obj1(), new obj2());
if (merged.foo) {
    merged.foo('Test'); // No complaints
}
// Property 'bar' does not exist on type 'Partial<{foo: (a: string) => void}>'.
merged.bar('A', 'B');

注意:

该函数返回Partial<T>,因为如果您的界面中有属性,它们将不会添加到合并对象中。如果您的接口没有任何属性,则可以将返回的对象强制转换为T的实例。

此方法要求您传递类的实例,而不是为您创建类。这允许一个更简单的方法,并允许您提供容易接受不同构造函数参数的类。