【问题标题】:How to use js object as a function AND object with prototype methods如何使用 js 对象作为函数和对象与原型方法
【发布时间】:2015-07-15 10:27:30
【问题描述】:

用例类似于“How can I use an object as a function and an object?

我目前的解决方案:

var newObj = function(_id){
  var obj = function(arg){
    console.log('call', _id, arg);
  }
  obj.test = function(arg){
    console.log('test', _id, arg);
  }
  console.log('new', _id);
  return obj
}

var obj = newObj('1');
obj('2');
obj.test('3');

现在,如果您的对象数量很少,这可以完美运行。

但是,当您获得大量方法和大量对象时,您可能希望将所有方法移至原型。怎么可能?

简单的解决方案,像这样:

var Obj = function(id){
  this.id = id
  console.log('new',id)
}
Obj.prototype = function(arg){
  console.log('call', this.id, arg)
}
Obj.prototype.test = function(arg){
  console.log('test', this.id, arg)
}
var obj = new Obj('1');
obj('2'); // this fails with "TypeError: obj is not a function"
obj.test('3');

不起作用。

编辑: 最终目标是缩短对象最常用方法的语法。

例如:bus 对象有方法post。当您使用bus 做某事时,此方法称为 99.99% 时间。总是写bus.post(...) 是多余的。创建闭包或绑定也不是一种选择,因为有很多总线。

当前的解决方案(没有原型)工作正常,对象数量很少。

【问题讨论】:

  • 但是你为什么要这个?第一种情况仅适用,因为您返回函数而不是对象
  • 请解释您的最终目标。不是你认为你需要做什么才能做你想做的事,而是你真正想做的事。举一个实际使用或您希望使用的机器的例子。
  • 最终目标是缩短对象最常用方法的语法。例如:bus 对象有方法 post。当您使用bus 做某事时,此方法称为 99.99% 时间。
  • 这对我来说听起来像是一个不必要的并发症。我只是保持简单。

标签: javascript prototype


【解决方案1】:

请查看 cmets 中的链接问题。

你能做的最好的事情就是创建一个对象来保存你的可重用函数, 然后将这些属性复制到您想要的每个新函数对象上 创建。

var reusablefuncs = {
    f1: function(){ return 'f1'; },
    f2: function(){ return 'f2'; }
};

var f = function(){
    return 'f';
};

Object.keys(reusablefuncs).forEach(function(prop){
    f[prop] = reusablefuncs[prop];
});

console.log(f(), f.f1(), f.f2());

但是——你为什么要这样做?

【讨论】:

  • 在新的浏览器中你可以使用Object.setPrototypeOf来代替
  • @Grundy 是的。您必须将reusablefuncs 定义为函数本身,以确保callapply 等保留在原型链中。
【解决方案2】:

你不能直接做你想做的事。函数是一个函数并且有一个函数原型。您可以做的是在每个函数上放置一个对象作为属性,并通过它调用您的例程。

这样使用:

var obj = newObj('1');
obj('2');
obj.methods.test('3');
    ^^^^^^^ INVOKE VIA METHODS PROPERTY

您可以将其视为一种手卷原型。

现在我们将安排methods 属性返回正确绑定到此的函数哈希,例如,允许访问id。为了解决这个问题,我们将 methods 作为一个 gettable 属性添加到函数中,返回一个方法的哈希值,每个方法都绑定到正确的 this:

var Obj = function(id){
  this.id = id
  console.log('new',id)
  Object.defineProperty(this, 'methods', {
    get: function() { return methods(this); }
  });
}

现在将methods定义为

function methods(obj) {
  return {
    test: function(arg) {
      console.log('test', this.id, arg);
    }.bind(obj)
};

现在单个函数对象上的唯一足迹是单个 methods 属性。其他一切都是共享的。但是,调用methods 函数会产生每次访问的运行时成本。您不能同时拥有这两种方式:您可以预先绑定并将方法放置在每个对象上,或者您可以在访问 methods 时进行后期绑定。

【讨论】:

  • 有趣的想法。谢谢。
【解决方案3】:

我认为你误解了 javascript 中的原型。

您没有带有原型的对象,您有带有原型的函数/构造函数,可用于创建对象/实例。

您正在定义一个构造函数,然后从中创建一个实例,因此您不能将其用作函数。如果您想要一个具有属性的函数,请这样做:

var newObj = function () {
    // do the funciton logic here
};

newObj.property1 = 'value'; // define the properties you need.

现在您有了一个可以像对象一样使用的函数,但请记住,它只是一个函数,如果您从中创建实例,这些实例将不包含已定义的属性。

【讨论】:

  • 是的,这是当前的解决方案。适用于少量对象。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-01-28
  • 1970-01-01
  • 2020-06-02
  • 1970-01-01
  • 2022-01-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多