【问题标题】:Best way to create a new constructor that relies on an old one using prototypes使用原型创建依赖于旧构造函数的新构造函数的最佳方法
【发布时间】:2013-06-12 23:42:20
【问题描述】:

所以,假设我有以下构造函数,我已经修改了它的原型:

function foo(options) {
  this.propA_ = 'whatever';
  this.propB_ = 'something';
  this.propC_ = options.stuff;
  this.randomMethod = function omg() {
    /*code etc etc etc*/
  }
}

foo.prototype.p1 = 1;
foo.prototype.p2 = 2;

创建 foo 后,我想创建一个新的构造函数 bar(),它就像一个超级 foo:它具有 foo 的所有属性、原型信息和方法,但它还有一些额外的属性和方法洒在上面。下面的代码会是最优雅的方式吗?

function foo(options) {
  this.propA_ = 'whatever';
  this.propB_ = 'something';
  this.propC_ = options.stuff;
  this.randomMethod = function omg() {
    /*code etc etc etc*/
  }
}

foo.prototype.p1 = 1;
foo.prototype.p2 = 2;

function bar(options) {
  this = foo(options);
  this.propD_ = 'yet another thing';
  this.propE_ = options.moreStuff;
}

bar.prototype.p3 = 3;
foo.prototype.testing = 'A test';

smallObj = foo()'
bigObj = bar();

运行该代码后,这是我期望得到的结果

console.log(a.p3); //3

bigObj.p2 = 100;
console.log(bigObj.p2); //100
console.log(foo.prototype.p2); //2

console.log(bigObj.randomMethod()); //Will work
console.log(smallObj.p3); //undefined
console.log(smallObj.propA_); //'whatever'
console.log(bigObj.propA_); //'whatever'

foo.prototype.propA_ = 'something totally different'
console.log(bigObj.propA_); //'something totally different'

这是“扩展”某些现有构造函数的功能的正确方法,以制作一种“Foo Plus”。基本上,我希望 foo 继续像 bar() 出现之前一样继续工作,但是 bar 是添加在 foo 之上的一组属性和方法。我这样做对吗?

【问题讨论】:

  • 正确吗?不,运行它。这将失败。 this = foo(options); 看来你只是在猜测。网上有很多关于继承的信息供你学习。
  • 是的,我知道我的理解力很差。我在这里研究了几个线程,但我仍然不太清楚发生了什么。我试图使我自己的例子合理化。是的,我知道它失败了,我的问题是为什么。
  • 好的,所以我对你的小提琴做了一些更改:jsfiddle.net/8QCE2 我可以整理一下为什么this = new foo(opts); 是错误的:这是指由 bar() 构造的对象,显然我不能随便重新定义那个对象;我可以设置它的属性,我可以添加方法等等,但我不能只是重新定义它。我想做的是让bar()中的“this”继承foo的原型......
  • 好的,我差不多有了。链接到最新的小提琴:jsfiddle.net/kZTe2 所以基本上原型复制过来就好了,所以我认为我有这个权利。进一步的,foo的原型的变化体现在bar的原型上,也很棒。我的问题是在 foo() 本身中构造的属性没有被转移到 bar()。我小提琴中的第 45 行没有产生应有的结果。为什么是这样?如何在构造函数中设置属性以转移到继承它的新对象?
  • 最好用原型声明你的方法属性,因为它们不会在每个实例中改变,但是你可以用this.something="my instance value"声明的值属性。关于原型和this 行为的示例代码的简单解释在这里:stackoverflow.com/questions/16063394/… 您可以在 chrome 中按 F12,在控制台中运行代码并使用它来更好地理解它。

标签: javascript constructor clone prototype


【解决方案1】:

好的,我终于完成了我在评论线程中针对问题进行的讨论,this 是我想出的答案。我将在此处重新发布代码 - 感谢所有帮助我解决此问题的人!

function foo(options) {
    this.propA_ = 'whatever';
    this.propB_ = 'something';
    this.propC_ = options.stuff;
    this.randomMethod = function omg() {
        /*code etc etc etc*/
    };
}
foo.prototype.p1 = 1;
foo.prototype.p2 = 2;

function bar(options) {
    //this = new foo(options);
    var parent = new foo(options);
    this.prototype = parent.prototype;

    for (var x in parent) {
        if (parent.hasOwnProperty(x)) {
            console.log('iterating past'+x);
            this[x] = parent[x];
        }
    }

    this.propD_ = 'yet another thing';
    this.propE_ = options.moreStuff;
}
// Make `bar` inherit from an instance of `foo`
bar.prototype = Object.create(foo.prototype);

// Add properties to the bar prototype
bar.prototype.p3 = 3;

// Not sure what you were doing here
//foo.prototype.testing = 'A test';

var myOpts = {
    stuff: 'a cat',
    moreStuff: 'many dogs'
};

var smallObj = new foo(myOpts);
var bigObj = new bar(myOpts);


console.log(smallObj.p2); //2

console.log(bigObj.p2); //2
bigObj.p2 = 100;
console.log(bigObj.p2); //100
console.log(foo.prototype.p2); //2

//console.log(bigObj.randomMethod()); //Will work
console.log(smallObj.p3); //undefined
console.log(smallObj.propA_); //'whatever'
console.log(bigObj.propA_); //'whatever'

foo.prototype.propA_ = 'something totally different';
console.log(bigObj.propA_); //'whatever'

【讨论】:

    【解决方案2】:

    不知道为什么你有这么多代码来继承原型。您可以使用closure library 中的goog.inherit(如果您打算使用闭包编译器进行编译,还可以使用 goog.base)。

    这里是一些使用 goog.inherit 的示例代码:

    var goog = {};
    /**
     * Inherit the prototype methods from one constructor into another.
     * @param {Function} childCtor Child class.
     * @param {Function} parentCtor Parent class.
     */
    goog.inherits = function (childCtor, parentCtor) {
        /** @constructor */
        function tempCtor() { };
        tempCtor.prototype = parentCtor.prototype;
        childCtor.superClass_ = parentCtor.prototype;
        childCtor.prototype = new tempCtor();
        childCtor.prototype.constructor = childCtor;
    };
    /** @constructor */
    var GrandParent = function (arg1) {
        window['console'].log("grandparent constructor called with arg1:", arg1);
    }
    GrandParent.prototype.doSomething = function () {
        return "From GrandParent";
    }
    /** @constructor */
    var Parent = function (arg1, arg2) {
        GrandParent.call(this, arg1);
        window['console'].log("parent constructor called with arg1:", arg1);
        window['console'].log("parent constructor called with arg2:", arg2);
    }
    goog.inherits(Parent, GrandParent);
    /** @override */
    Parent.prototype.doSomething = function () {
        return Parent.superClass_.doSomething() + " From Parent";
    }
    /** @constructor 
    * @extends Parent */
    var Child = function (arg1, arg2, arg3) {
        Parent.call(this, arg1, arg2);
        window['console'].log("child constructor called with arg1:", arg1);
        window['console'].log("child constructor called with arg2:", arg2);
        window['console'].log("child constructor called with arg3:", arg3);
    }
    goog.inherits(Child, Parent);
    /** @override */
    Child.prototype.doSomething = function () {
        return Child.superClass_.doSomething() + " From Child";
    }
    
    var c = new Child("arg1", "arg2", "arg3");
    console.log(c.doSomething());
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-03-24
      • 1970-01-01
      • 2017-09-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多