javascript 类继承自 Function 类

发布于 2024-12-13 12:30:43 字数 972 浏览 0 评论 0原文

我喜欢在 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) 。不幸的是,

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

I like that in javascript, I can create a function, and then add further methods and attributes to that function

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

I would like to create a class to generate these objects. I assume I have to inherit from the Function base class.

In other words, I would like to:

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

But I don't know how to create the myFunctionClass. I have tried the following, but it does not work:

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

I also tried the more complicated (and more proper?) inheritance method found here: How to "properly" create a custom object in JavaScript?, with no more luck. I have also tried using the util.inherits(myFunctionClass, Function) found in node.js. Still no luck

I have exhausted Google, and therefore feel that I must be missing something fundamental or obvious. Help would be greatly appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

素年丶 2024-12-20 12:30:43

您尝试从 Function 继承。这是正确的做法。我建议您执行以下操作

Live示例

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();

您可以在此处创建工厂,然后创建实例。

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

如果您想要真正的原型面向对象,那么您需要使用 hack。

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

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

Your trying to inherit from Function. This is a right pain to do. I suggest you do the following instead

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
});

You want to create a prototype object that forms the basis of your "class". It has your generic methods/attributes. It also has a constructor that gets invoked on object construction and a call method that gets invoked when you call the function

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;
  }
}

A function factory takes a prototype object and returns a factory for it. The returned function when called will give you a new function object that "inherits" from your prototype object.

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

Here you create your factory and then create your instance.

However this isn't proper prototypical OO. we are just shallow copying properties of a prototype into a new object. So changes to the prototype will not reflect back to the original object.

If you want real prototypical OO then you need to use a hack.

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

Notice how we use the non-standard deprecated .__proto__ and we are mutating the value of [[Prototype]] at run-time which is considered evil.

樱花细雨 2024-12-20 12:30:43

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

虽然你可以执行工厂功能:

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

var func = makeCoolFunc();
var x = func();

JS does not allow a constructor to return a function, even though functions are objects. So you cant have an instantiation of a prototype that is itself executable. (Am I right in this? please correct if I'm not, it's an interesting question).

Though you could do a factory function:

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

var func = makeCoolFunc();
var x = func();
℡寂寞咖啡 2024-12-20 12:30:43

您可以扩展Function并将所需的函数体作为字符串传递给超级构造函数。可以使用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

You can extend Function and pass the wanted function body as String to the super constructor. The context of the function can be accessed with arguments.callee.

Example for an observable Attribute class:

    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 = [];
    }
}

Example usage:

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文