javascript类继承自Function类

时间:2011-11-02 23:26:56

标签: javascript inheritance prototypal-inheritance function-object

我喜欢在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

我还尝试了更复杂(也更合适?)的继承方法:How to "properly" create a custom object in JavaScript?,没有更多的运气。我也尝试使用node.js中的util.inherits(myFunctionClass,Function)。仍然没有运气

我已经筋疲力尽了谷歌,因此我觉得我必须遗漏一些基本或明显的东西。非常感谢帮助。

3 个答案:

答案 0 :(得分:14)

您尝试继承Function。这是一个正确的痛苦。我建议你做以下事情

Live Example

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,那么你需要使用黑客。

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

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

答案 1 :(得分: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();

答案 2 :(得分:0)

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

可观察属性类的示例:

    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
相关问题