使用.prototype和__proto__创建子类

mat*_*fee 7 javascript

我最近通过编写一些gnome shell扩展来学习javascript,因此我对Javascript的理解已经被我在gnome-shell javascript源中观察到的例子所塑造.我有一种感觉,我一直在理解错误的课程,只是想要一些澄清.

我已经编写了一些自己的子类,并且在每种情况下我只是通过遵循gnome-shell javascript源代码中的类似代码来定义它们:

Subclass = function() {
    this._init.apply(this,arguments);
}
Subclass.prototype = {
    __proto__: Superclass.prototype,
    _init: function() {
        Superclass.prototype._init.call(this);
    },
    // add other methods of Subclass here.
}
Run Code Online (Sandbox Code Playgroud)

到目前为止,我认为这是制作课程的标准方式,Subclass基本上是Superclass额外的.我假设每个对象都有一个_init方法.

我最近尝试应用相同的方法来创建a的子类Clutter.Actor(重要的是它不是GNOME-shell定义的类),并且意识到上面的子类化对象的方式不是标准.首先,并非每个班级都有_init我所假设的功能; 这只是GNOME-shell在他们的javascript类中完成的事情.

所以,我的问题是:

  1. 是否有关于上述创建子类的方法的文档?我见过的所有教程都说设置Subclass.prototype = new Superclass()而不是做Subclass.prototype = { __proto__:Superclass.prototype, define_prototype_methods_here }方法,但我的想法是,如果gnome-shell一直使用它,必须有一些方法吗?
  2. 如果我想留在尽可能靠近到定义类(就这样我就可以保留一些代码相似GNOME-Shell对于它我写扩展)以上的方式,我该怎么更换Superclass.prototype._init.call(this)Subclass._init,以确保在Subclass.prototype得到所有Superclass(我在我的定义中添加的方法/属性Subclass.prototype),如果Superclass没有_init函数(即它是否有一些我调用的等效构造函数)?

我真的很困惑这一切所以请原谅我,如果我的问题没有多大意义; 这是因为我的误解和困惑的程度!

编辑:澄清: - 我知道__proto__不推荐,因为它是非标准的,但我的代码永远不会在浏览器中运行 - 它只会运行GNOME javascript(基本上是Mozilla javascript引擎),所以我不需要担心交叉兼容性.

Fel*_*ing 8

如前所述,不要使用__proto__.这是一个非标准的财产. (它现在已经在浏览器中标准化了JavaScript.仍然不使用它.)但是

Subclass.prototype = new Superclass(); // Don't do this
Run Code Online (Sandbox Code Playgroud)

也不是一个非常好的方法.如果Superclass需要参数怎么办?

你有更好的选择.

ES2015及以上

class为您处理所有这些管道; 完整的例子:

class Superclass {
    constructor(superProperty) {
        this.superProperty = superProperty;
    }
    method() {
        console.log("Superclass's method says: " + this.superProperty);
    }
}
class Subclass extends Superclass {
    constructor(superProperty, subProperty) {
        super(superProperty);
        this.subProperty = subProperty;
    }
    method() {
        super.method(); // Optional, do it if you want super's logic done
        console.log("Subclass's method says: " + this.subProperty);
    }
}

let o = new Subclass("foo", "bar");
console.log("superProperty", o.superProperty);
console.log("subProperty", o.subProperty);
console.log("method():");
o.method();
Run Code Online (Sandbox Code Playgroud)

ES5及更早版本

让我们Subclass.prototype继承Superclass.prototype.这可以通过例如ES5来完成Object.create:

Subclass.prototype = Object.create(Superclass.prototype);
Subclass.prototype.constructor = Subclass;
Run Code Online (Sandbox Code Playgroud)

然后在Subclass,您Superclass通过this引用该对象进行调用,以便它有机会初始化:

function Subclass() {
    Superclass.call(this); // Pass along any args needed
}
Run Code Online (Sandbox Code Playgroud)

完整示例:

function Superclass(superProperty) {
    this.superProperty = superProperty;
}
Superclass.prototype.method = function() {
    console.log("Superclass's method says: " + this.superProperty);
};
function Subclass(superProperty, subProperty) {
    Superclass.call(this, superProperty);
    this.subProperty = subProperty;
}
Subclass.prototype = Object.create(Superclass.prototype);
Subclass.prototype.constructor = Subclass;

Subclass.prototype.method = function() {
    Superclass.prototype.method.call(this); // Optional, do it if you want super's logic done
    console.log("Subclass's method says: " + this.subProperty);
};

var o = new Subclass("foo", "bar");
console.log("superProperty", o.superProperty);
console.log("subProperty", o.subProperty);
console.log("method():");
o.method();
Run Code Online (Sandbox Code Playgroud)

ES3及更早版本

ES3和更早版本没有Object.create,但你可以很容易地编写一个为你设置原型的函数:

function objectCreate(proto) {
    var ctor = function() { };
    ctor.prototype = proto;
    return new ctor;
}
Run Code Online (Sandbox Code Playgroud)

(注意:你可以Object.create通过创建一个只需要一个参数的一半来进行半垫片,但是多参数版本Object.create不能被填充,所以如果它也使用的话,它会给页面上的其他代码提供错误的想法Object.create.)

然后你做我们的ES5例子:

完整示例:

function objectCreate(proto) {
    var ctor = function() { };
    ctor.prototype = proto;
    return new ctor;
}

function Superclass(superProperty) {
    this.superProperty = superProperty;
}
Superclass.prototype.method = function() {
    console.log("Superclass's method says: " + this.superProperty);
};
function Subclass(superProperty, subProperty) {
    Superclass.call(this, superProperty);
    this.subProperty = subProperty;
}
Subclass.prototype = objectCreate(Superclass.prototype);
Subclass.prototype.constructor = Subclass;

Subclass.prototype.method = function() {
    Superclass.prototype.method.call(this); // Optional, do it if you want super's logic done
    console.log("Subclass's method says: " + this.subProperty);
};

var o = new Subclass("foo", "bar");
console.log("superProperty", o.superProperty);
console.log("subProperty", o.subProperty);
console.log("method():");
o.method();
Run Code Online (Sandbox Code Playgroud)