首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使`obj.someMethod()`可作为``obj()‘使用,而不阻止``obj’作为正常实例运行

使`obj.someMethod()`可作为``obj()‘使用,而不阻止``obj’作为正常实例运行
EN

Stack Overflow用户
提问于 2015-10-11 11:50:30
回答 2查看 63关注 0票数 0

为了避免误解,让我们先就某些词的意思达成一致。以下的含义不是普遍接受的,我只是建议它们作为这个问题的背景。

  • 函数 -- Function的一个实例。它有一个与之相关的程序。
  • 对象 --任何其他类的实例。没有与其关联的过程。
  • procedure --可以执行的代码块。在JS中,只能找到与函数相关的过程。
  • 方法 --存储在另一个对象的属性中的函数。方法在其宿主对象的上下文中执行。

在JavaScript中,通常使用属性和方法自定义对象,而函数不定制。换句话说,如果在代码中看到这一点:

代码语言:javascript
复制
foo.bar   // Accessing a property on an instance
foo.baz() // Calling a method on an instance

那么foo几乎肯定是一个对象,而不是一个函数。

但从技术上讲,函数与对象并没有什么不同(实际上,JS中的函数被认为是对象,我只是为了清楚地区分它们)。

如果你这么做

代码语言:javascript
复制
const foo = function () { /*...*/ }
foo()     // Calling the function's procedure
foo.bar   // Accessing a property on the function
foo.baz() // Calling a method on the function

...it会很好的工作。

我想再介绍两个术语,这样你才能理解我的意思。我不是想在这里改变JavaScript的规则,我只是想被理解。

  • function-object --一个用作对象的函数:有它自己的属性和/或方法。
  • main方法 --函数对象本身的过程,而不是存储在函数对象上的属性的方法。

许多JS库提供函数对象,例如jQuery和LoDash。也就是说,你可以同时做$()$.map()

好了,现在谈一谈。

我希望能够创建具有以下要求的自己的函数对象:

  1. 我应该能够使用ES2015 class声明来描述函数对象的类。或者至少描述类的方式应该是足够方便的。将属性和方法强制分配给函数是不方便的。
  2. my function对象的主要方法应该在与其其他方法相同的上下文中执行。
  3. 主方法和其他方法应该绑定到同一个实例。例如,如果我有一个main方法和一个同时执行console.log(this.foo)的普通方法,那么分配给myFunctionObject.foo应该同时修改主mehtod和另一个方法的行为。

换句话说,我希望能够做到这一点:

代码语言:javascript
复制
class Foo {
  constructor   () { this.bar = 'Bar'; }
  mainMethod    () { console.log(this.bar); }
  anotherMethod () { console.log(this.bar); }
}

...but -- Foo的一个实例--应该可以将foo.mainMethod()简单地作为foo()使用。

执行foo.bar = 'Quux'应该同时修改foo()foo.anotherMethod()的行为。

也许有一种方法可以用class Foo extends Function来实现

EN

回答 2

Stack Overflow用户

发布于 2015-10-11 16:23:03

如果不覆盖任何内容,new Foo将返回对象类型,而不是函数类型。你有可能做到

代码语言:javascript
复制
class Foo {
  constructor(){
    const foo = () => foo.mainMethod();
    Object.setPrototypeOf(foo, this);

    foo.bar = 'Bar';

    return foo;
  }
  mainMethod    () { console.log(this.bar); }
  anotherMethod () { console.log(this.bar); }
}

这样,new Foo将返回一个显式设置的函数,以便返回一个具有正确原型链配置的函数。请注意,我正在显式地设置foo.bar而不是this.bar,以便hasOwnProperty在整个代码中仍能按预期工作。

您也可以通过基类设置它来解决这个问题。

代码语言:javascript
复制
class CallableClass {
  constructor(callback){
      const fn = (...args) => callback(...args);
      Object.setPrototypeOf(fn, this);
      return fn;
  }
}

class Foo extends CallableClass {
  constructor(){
    super(() => this.mainMethod());
    this.bar = 'Bar';
  }
  mainMethod    () { console.log(this.bar); }
  anotherMethod () { console.log(this.bar); }
}

我是用真正的ES6编写这篇文章的,但是如果您想让它在Node v4中工作,就必须将其余的/扩展的args更改为正常的函数。例如:

代码语言:javascript
复制
const foo = function(){ callback.apply(undefined, arguments); };

这两种方法的缺点是它们依赖于Object.setPrototypeOf,这在IE<=10中不起作用,因此它将取决于您需要什么支持。一般的理解是,Object.setPrototypeOf也非常慢,所以我不确定您在这里有很多选择。

ES6为这种情况提供的主要选择是代理,但它们还没有得到很好的支持。

票数 2
EN

Stack Overflow用户

发布于 2015-10-11 23:17:48

AFAIK无法将[Call]方法添加到现有对象中。

代理可能看起来是一个潜在的解决方案,但问题是代理对象与[ProxyHandler]是不同的对象,并且是 trap

因此,唯一可行的解决方案是使用所需的[Call]创建一个新函数,替换它的[Prototype],并使构造函数返回该函数而不是“the”实例。

代码语言:javascript
复制
class Foo {
  constructor   () {
    var instance = function(){ return instance.mainMethod(); };
    Object.setPrototypeOf(instance, Foo.prototype);
    return Object.assign(instance, {bar: 'Bar'});
  }
  mainMethod    () { console.log(this.bar); }
  anotherMethod () { console.log(this.bar); }
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/33064625

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档