【问题标题】:Prototyping with Javascript Constructors使用 Javascript 构造函数进行原型设计
【发布时间】:2013-04-14 00:06:46
【问题描述】:

考虑以下示例

var Foo = function(){
    this.identity = 'Foo';
};
Foo.prototype.bar = function(){
    this.identity = 'bar';
};
var fooInstance = new Foo(),
    bar = new fooInstance.bar();

问题

bar 内,如何获取fooInstance 变量? Foo 的孩子有没有办法将其父母识别为fooInstance?例如,我如何在bar 中创建一个返回fooInstance 的函数。需要注意的是,bar 必须使用 prototype 命令创建,并且不能简单地嵌套在 Foo 中以通过这种方式访问​​任何 Foo 实例。

我的想法以及它们为什么行不通

这样重写函数是可能的

var Foo = function(){
    this.identity = 'Foo';
};
Foo.prototype.createBar = function(){
    var parent = this;
    function bar(){
        this.parent = parent;
        this.identity = 'bar';
    };
    return new bar();
};
var fooInstance = new Foo(),
    bar = fooInstance.createBar();

然而,为了创建易于阅读的代码,如果不需要,我宁愿不使用这种方法。

进一步说明

让我把这个问题放在上下文中。我在 CanvasRenderingContext2D 上进行原型设计,以便画布元素的所有上下文都包含我的新方法。让我们调用该方法 foo 并假设 context 是创建的画布上下文。如何创建像“new context.foo()”这样的变量,以便 foo 函数可以使用上下文变量?

【问题讨论】:

  • 什么是fooInstanceFoo的“孩子”和“父母”是什么?您正在调用但未定义的 bar 方法是什么? “原型命令”是什么意思?
  • 顺便说一句,this answer 可能会帮助您了解变量和属性之间的区别。
  • 让我把这个问题放在上下文中。我在 CanvasRenderingContext2D 上进行原型设计,以便画布元素的所有上下文都包含我的新方法。让我们调用该方法 foo 并假设 context 是创建的画布上下文。如何创建像“new context.foo()”这样的变量,以便 foo 函数可以使用上下文变量?
  • 好的,我现在看到你的问题了。只是在寻找一个骗子,如果我找不到它,我会回答你的问题
  • Prototype for private sub-methods 的可能重复项,也可参见 this

标签: javascript function constructor prototype


【解决方案1】:

如果你需要从bar 对象中引用fooInstance 对象,你可以像这样使用依赖注入:

Foo.prototype.bar = function(fooInstance) {
    this.identity = 'bar';
    this.fooInstance = fooInstance;
};

var fooInstance = new Foo(),
    bar = new foo.bar(fooInstance);

您可以通过在Foo 上实现工厂函数来简化创建过程。

Foo.prototype.createBar = (function() {
    function Bar(parent){
        this.parent = parent;
        this.identity = 'bar';
    };

    return function () {
        return new Bar(this);
    };
})();

var fooInstance = new Foo(),
    bar = fooInstance.createBar();

【讨论】:

  • 这也正是我的想法,但我正在设计一个 API,发现作为用户使用起来很麻烦。然而,虽然工厂方法消除了传递参数的烦人需要,但在我的程序中,使用新前缀在逻辑上更有意义,我宁愿为用户保持逻辑。子方法是否可以动态获取原始对象?通常绑定和使用 this 可以做到这一点,但由于构造函数的性质不适用于此处......还有其他方法吗?
【解决方案2】:

如何在 bar 中创建一个返回 fooInstance 的函数

如果该函数被调用为构造函数(使用new),您就无法真正做到这一点。 this keyword,对“父”(您调用该方法的对象)的唯一引用在构造函数调用中设置为新实例。您只能使用闭包来获取引用,例如通过在父构造函数中创建构造函数(这对您不起作用)或通过从原型上的闭包返回构造函数(您在第二个示例中几乎得到了):

Foo.prototype.getBarCoonstructor = function() {
    var parentFoo = this;
    return function Bar() {
        // constructor things
        // using "parentFoo" reference
    };
};
// Usage:
var bar = new (foo.getBarConstructor()) (); // ugly.

与其为每次调用getBarConstructor 创建新的构造函数,不如将它放在方法之外并将parentFoo 作为参数。你的想法已经很不错了。

function Bar(parent) {
    // constructor things, referring "parent"
}
Bar.prototype.… = …;

Foo.prototype.createBar = function() {
    return new Bar(this); // passing the Foo instance
};

(@plalx 有相同的解决方案,但包裹在模块闭包中)

【讨论】:

  • 谢谢,我想问题是“this”是函数之间唯一的向上关系,使用构造函数可以有效地删除它。这是 javascript 让我感到沮丧的时刻之一。
【解决方案3】:

Foo.prototype.bar 只是 Foo 原型对象上的一个函数。除非您在其作用域链中明确定义它,否则该函数无法知道其“父级”。

即如果你愿意的话

var Foo = function(){
    this.identity = 'Foo';
};
var fooInstance = new Foo();

Foo.prototype.bar = function(){
    console.log(fooInstance); // retrieve from scope
    this.identity = 'bar';
};
bar = new foo.bar();

这会起作用。

【讨论】:

  • 是的,但是一旦我创建了多个 fooInstance,该方法就会中断。代码需要是动态的。每个 fooInstance 都是唯一的,每个 bar 实例必须能够获得它的唯一父级。
猜你喜欢
  • 2012-06-19
  • 2017-08-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-12
  • 1970-01-01
  • 2015-10-10
  • 1970-01-01
相关资源
最近更新 更多