我正在将我在Flash / AS3.0中设计的游戏重写为javascript,并且在学习课程时难以绕过原型。我已经阅读了大量有关它的信息,我仍然不太确定如何将其应用于这种情况。
所以...在我的AS3.0项目中,我有一个关卡类,它具有游戏各个层面发生的内容,Enter_Frame功能等。然后我将每个级别的类扩展为特定级别项目放置,地形细节等细节...所以我的问题是如何最有效和“正确”的方式来做到这一点。
现在我有两个功能:
function level() {
//generic level functionality
}
function level1() {
//level1 specific functionality
}
然后,正如我读过的那样,我应该设置
level1.prototype = new level();
但我发现这会在运行时执行level函数中的所有内容,这是我不想要的。理想情况下,我想要一个开始按钮来实例化level1,而level1则拥有level的属性和方法 - 如果可能的话,在发生这种情况时执行level1和level的构造函数中的所有内容......是否可能?
我确定这很明显,但我似乎无法点击,抱歉,如果我问一个愚蠢的问题。 非常感谢任何提前帮助。
答案 0 :(得分:2)
为避免在建立继承时执行构造函数,可以使用Object.create()
:
level1.prototype = Object.create(level.prototype);
但是,对于“ chain ”构造函数调用,您还需要level
中的call
level1
:
function level1() {
level.call(this);
// ...
}
使用call
可以传递上下文(this
),这样两个构造函数都可以使用相同的对象。
答案 1 :(得分:0)
您要实现的是JavaScript中的某种面向对象解决方案。看看at this blog post,它详细描述了它,并给出了一个很好的例子。 : - )
答案 2 :(得分:0)
可以使用Obj.call(this,args)
调用父构造函数。代码还应保留level1
的原型level1.prototype = new level()
的赋值,因为这将创建两个对象之间关系的继承。
function level(config) {
if(config){
this.someProperty = config.prop;
alert("Level constructor");
alert("Level property " + this.someProperty);
}
}
function level1(config) {
level.call(this, config);
this.someProperty2 = config.prop2;
alert("Level1 Construtor");
alert("Leve1 property " + this.someProperty2);
alert("Level1 using prop from level " + this.someProperty);
}
level1.prototype = new level();
var myLevel = new level1({
prop: "Test prop",
prop2: "Test prop2"
});
答案 3 :(得分:0)
用户JonathanLonowski已经回答了您在设置inheritanc时如何避免调用构造的问题。但我也把你的问题看成是一个关于如何在JavaScript中使用inhertance的一般性问题。所以我试图解释这个话题:
当涉及到继承时,你基本上想要做的是增强原型链。
那么,原型链是什么?
当您使用obj.prop
请求对象的属性时,如果对象obj
具有此类属性,则JavaScript首先检查。如果没有,它会检查该对象的原型是否具有这样的属性。如果没有,它会检查原型的原型是否具有这样的属性等等。
当您通过编写obj = new B()
创建具有构造函数的新对象时,原型链看起来如下:
obj -> B.prototype -> Object -> null
继承如何与原型链一起使用
如果您希望B
个对象从A
类型的对象继承,您希望原型链看起来像这样:
obj -> B.prototype -> A.prototype -> Object -> null
为实现这一目标,您需要在B.prototype
之后“打破”原型链,然后插入A
的完整原型链。或者换句话说,您希望将B.prototype
设置为指向A.prototype
。
你可以像以前一样做到这一点:
B.prototype = new A();
现在为什么这样做? new A()
创建的对象具有以下原型链:
objA -> B.prototype -> Object -> null
如果使用此对象覆盖B.prototype
,则类型为B
的对象的原型链如下所示:
objB -> objA -> A.prototype -> Object -> null
如你所见,它有效。只需覆盖B.prototype
,您就会丢失一些属性,例如constructor
属性。因此,如果您尝试使用constructor
获取B
类型的对象objB.constructor
,它首先查找对象本身但找不到它,然后查看{{1}并且找不到它,然后查看objA
并查找A.prototype
,这是错误的。虽然您经常不需要A
属性,但在覆盖constructor
之后再次设置它是一种良好的做法:
B.prototype
现在,您的方式只是实现原型链链接的一种方式。 JonathanLonowski的解决方案是另一个,确实是更好的解决方案,因为它不会调用函数B.prototype = new A();
B.prototype.constructor = B;
。它创建一个空对象,其原型链与A
类型的对象相同:
A
另一种解决方案是不覆盖(empty object) -> A.prototype -> Object -> null
,但修改它只是指向B.prototype
而不是A.prototype
。并非每个浏览器都支持此功能,但在某些浏览器中,您可以通过设置Object
属性来实现此目的:
__proto__
这将产生以下原型链:
B.prototype.__proto__ = A.prototype;
请注意,我在这里和那里简单地说它,但我认为这应该让你知道它是如何工作的。最基本的事情是原型设计。现在,从技术上讲,只有一个真正的原型属性,每个对象都具有内部obj -> B.prototype -> A.prototype -> Object -> null
属性。您无法直接在JavaScript中访问它,但是您可以[[prototype]]
和.prototype
设置它并在特定条件下对其进行操作。