13

我喜欢在 javascript 中这样做,我可以创建一个函数,然后向该函数添加更多方法和属性

myInstance = function() {return 5}
myInstance.attr = 10

我想创建一个类来生成这些对象。我假设我必须从 Function 基类继承。

换句话说,我想:

var myInstance = new myFunctionClass()
var x = myInstance()
// x == 5

但我不知道如何创建 myFunctionClass。我尝试了以下方法,但它不起作用:

var myFunctionClass = function() {Function.call(this, "return 5")}
myFunctionClass.prototype = new Function()
myInstance = new myFunctionClass()
myInstance()
// I would hope this would return 5, but instead I get
// TypeError: Property 'myInstance' of object #<Object> is not a function

我还尝试了这里找到的更复杂(也更合适?)的继承方法:如何“正确”在 JavaScript 中创建自定义对象?,没有更多的运气。我还尝试使用 node.js 中的 util.inherits(myFunctionClass, Function)。仍然没有运气

我已经用尽了谷歌,因此觉得我一定遗漏了一些基本的或明显的东西。帮助将不胜感激。

4

3 回答 3

14

你试图继承自Function. 这是正确的痛苦。我建议您改为执行以下操作

现场示例

var Proto = Object.create(Function.prototype);
Object.extend(Proto, {
  constructor: function (d) {
    console.log("construct, argument : ", d);
    this.d = d; 
    // this is your constructor logic
  },
  call: function () {
    console.log("call", this.d);
    // this get's called when you invoke the "function" that is the instance
    return "from call";
  },
  method: function () {
    console.log("method");
    // some method
    return "return from method";
  },
  // some attr
  attr: 42
});

您想创建一个原型对象,该对象构成您的“类”的基础。它有你的通用方法/属性。它还具有在对象构造时调用的构造函数和在调用函数时调用的调用方法

var functionFactory = function (proto) {
  return function () {
    var f = function () {
      return f.call.apply(f, arguments);      
    };
    Object.keys(proto).forEach(function (key) {
      f[key] = proto[key];
    });
    f.constructor.apply(f, arguments);
    return f;
  }
}

函数工厂接受一个原型对象并为其返回一个工厂。调用时返回的函数将为您提供一个从原型对象“继承”的新函数对象。

var protoFactory = functionFactory(proto);
var instance = protoFactory();

在这里,您创建您的工厂,然后创建您的实例。

然而,这不是正确的原型 OO。我们只是将原型的属性浅拷贝到新对象中。因此对原型的更改不会反映回原始对象。

如果您想要真正的原型 OO,那么您需要使用 hack。

var f = function () {
  // your logic here
};
f.__proto__ = Proto;

请注意我们如何使用非标准 deprecated.__proto__ 并且我们[[Prototype]]在运行时改变了被认为是邪恶的值。

于 2011-11-02T23:33:08.243 回答
1

JS 不允许构造函数返回函数,即使函数是对象。因此,您不能拥有本身可执行的原型的实例化。(我是对的吗?如果我不是,请纠正,这是一个有趣的问题)。

虽然你可以做一个工厂功能:

var makeCoolFunc = function() {
  var f = function() { return 5 };
  f.a = 123;
  f.b = 'hell yes!'
  return f;
};

var func = makeCoolFunc();
var x = func();
于 2011-11-02T23:35:15.447 回答
0

您可以扩展Function所需的函数体并将其作为 String 传递给超级构造函数。可以使用 访问函数的上下文arguments.callee

可观察的 Attribute 类的示例:

    export default class Attribute extends Function  {

    constructor(defaultValue){
        super("value", "return arguments.callee.apply(arguments);");
        this.value = defaultValue;
        this.defaultValue = defaultValue;
        this.changeListeners = [];
    }

    apply([value]){
        if(value!==undefined){
           if(value!==this.value){
               var oldValue = this.value;
               this.value=value;
               this.changeListeners.every((changeListener)=>changeListener(oldValue, value));
           }
        }
        return this.value;
    }

    clear(){
        this.value=undefined;
    }

    reset(){
        this.value=this.defaultValue;
    }

    addChangeListener(listener){
        this.changeListeners.push(listener);
    }

    removeChangeListener(listener){
        this.changeListeners.remove(listener);
    }

    clearChangeListeners(){
        this.changeListeners = [];
    }
}

示例用法:

import Attribute from './attribute.js';

var name= new Attribute();
name('foo'); //set value of name to 'foo'

name.addChangeListener((oldValue, newValue)=>{
    alert('value changed from ' +oldValue+ ' to ' +newValue);
});
alert(name()); //show value of name: 'foo'

name('baa'); //set value of name to new value 'baa' and trigger change listener
于 2018-02-23T14:58:54.463 回答