我最近通过编写一些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.
}
到目前为止,我认为这是制作课程Subclass
的标准方式,基本上是Superclass
加上额外内容。我假设每个对象都有一个_init
方法。
我最近尝试应用相同的方法来创建Clutter.Actor
的子类(重要的是它不是GNOME-shell定义的类),并意识到上面的子类化对象的方式是不是标准。首先,并非每个班级都有_init
功能,正如我所假设的那样;这只是GNOME-shell在他们的javascript类中完成的事情。
所以,我的问题是:
Subclass.prototype = new Superclass()
而不是Subclass.prototype = { __proto__:Superclass.prototype, define_prototype_methods_here }
方法,但我的想法是,如果gnome-shell一直使用它,必须有一些方法吗?Superclass.prototype._init.call(this)
中使用确保Subclass._init
获取Subclass.prototype
的所有方法/属性(然后我在Superclass
的定义中添加Subclass.prototype
}),如果Superclass
没有_init
函数(即它是否有一些我调用的等效构造函数)?我真的很困惑这一切所以请原谅我,如果我的问题没有多大意义;这是因为我误解的程度和混乱!
编辑:澄清:
- 我知道不推荐使用__proto__
,因为它是非标准的,但我的代码永远不会在浏览器中运行 - 它只会运行GNOME javascript(基本上是Mozilla javascript引擎),所以我不需要担心交叉兼容性。
答案 0 :(得分:8)
如前所述,请勿使用__proto__
。 这是一个非标准的属性。 (现在浏览器中的JavaScript标准化了。仍然不使用它。)但是
Subclass.prototype = new Superclass(); // Don't do this
也不是一个非常好的方法。如果Superclass
需要参数怎么办?
你有更好的选择。
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();
让Subclass.prototype
仅从Superclass.prototype
继承。例如,可以使用ES5 Object.create
:
Subclass.prototype = Object.create(Superclass.prototype);
Subclass.prototype.constructor = Subclass;
然后在Subclass
中,您使用Superclass
调用this
来引用该对象,以便它有机会初始化:
function Subclass() {
Superclass.call(this); // Pass along any args needed
}
完整示例:
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();
ES3和更早版本没有Object.create
,但您可以轻松地编写一个为您设置原型的函数:
function objectCreate(proto) {
var ctor = function() { };
ctor.prototype = proto;
return new ctor;
}
(注意:您可以通过创建只有一个参数的一个来填充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();
答案 1 :(得分:1)
虽然__proto__
在Web浏览器上使用时已被标准化为JavaScript的必需扩展,但在设置继承层次结构时没有理由使用它。
相反,使用Object.create
(一个ES5函数,如果你真的需要支持过时的浏览器,那么我们这里的关键部分可能会被填充。)
以下是
时的示例var BaseClass = function() {
};
var SubClass = function() {
// Important that SubClass give BaseClass a chance to init here
BaseClass.call(this/*, args, if, necessary, here*/);
// ...
};
// Make `SubClass`'s `prototype` an object that inherits from
// `BaseClass`'s `prototype`:
SubClass.prototype = Object.create(BaseClass.prototype);
// Fix up the `constructor` property
SubClass.prototype.constructor = SubClass;
就是这样。
如果BaseClass
的构造函数需要参数,则将SubClass
中的参数传递给它:
以下是
时的示例var BaseClass = function(arg) {
this.prop = arg;
};
var SubClass = function(baseArg) { // Can accept it, or provide a
BaseClass.call(this, baseArg); // hardcoded one here
// ...
};
SubClass.prototype = Object.create(BaseClass.prototype);
SubClass.prototype.constructor = SubClass;
当然,从ES2015(又名“ES6”)开始,您可以使用class
(并在必要时进行转换)。
class BaseClass {
constructor(arg) {
this.prop = arg;
}
}
class SubClass extends BaseClass {
constructor(baseArg) {
super(baseArg);
}
}
答案 2 :(得分:0)
__proto__
,因为JavaScript Engine实现使用它来引用对象类定义原型。
参考:MDN:__proto__
1>
Subclass.prototype = new Superclass();
是继承超类的正确方法。
2 - ;如果你想在实际执行Superclass _init方法的子类上调用_init,那么就不要在SubClass类上定义它。当你尝试访问subClass上的_init方法(SubClass的实例对象)时,JS引擎会尝试在当前obj上查找它,如果找不到该方法则在SubClass原型链中搜索它(即SuperClass)
如果要在子类方法中调用超类方法,请使用
Superclass.prototype._init.call(this)
在当前对象范围内执行超级函数。这样做可以在SubClass方法中调用super方法