JavaScript 继承和提升
JavaScript Inheritance and Hoisting
在我当前的 Web 项目中,我正在处理多个 JavaScript 文件,每个文件都包含从其他类型继承的类型定义。所以在任何给定的文件中,我可以有类似...
function Type(){
ParentType.call(this);
}
Type.prototype = Object.create( ParentType.prototype );
Type.prototype.constructor = Type;
... 与 ParentType
在另一个文件中类似地声明:
function ParentType(){
this.data = "";
}
由于在 <head>
标签中处理许多 JavaScript 文件变得很麻烦,我写了一个 bash 脚本来将文件连接成一个文件(称为 master.js
).这样,我可以 link 我的 HTML.
中的单个文件
对于只有一个 child 的类型,原型链构建正确,无论我的文件的串联顺序如何。换句话说,这个片段 ...
function ParentType(){
this.data = "";
}
function Type(){
ParentType.call(this);
}
Type.prototype = Object.create( ParentType.prototype );
Type.prototype.constructor = Type;
... 与此代码段的行为相同:
function Type(){
ParentType.call(this);
}
Type.prototype = Object.create( ParentType.prototype );
Type.prototype.constructor = Type;
function ParentType(){
this.data = "";
}
当我在任一场景中创建 Type
的实例时,ParentType.prototype.isPrototypeOf(typeobj)
returns 为真(其中 typeobj
是我的 Type
实例)。
但是,当我将另一种类型添加到 "prototype chain" 的末尾时,它仅在文件按顺序连接时有效,即:
function ParentType(){
this.data = "";
}
function Type(){
ParentType.call(this);
}
Type.prototype = Object.create( ParentType.prototype );
Type.prototype.constructor = Type;
function ChildType(){
Type.call(this);
}
ChildType.prototype = Object.create( Type.prototype );
ChildType.prototype.constructor = ChildType;
... 否则,链 "breaks"。我猜测为什么这在 single-child 场景中是可以的,因为两种类型定义都被提升了,并且只有一组 statements 需要担心原型链。但是对于multi-link个原型链,如果语句乱了,链就无法正常连接。
所以我真正想问的是,有没有一种方法可以在 JavaScript 中实现继承 "works" 而不管我的文件的连接顺序如何? 虽然我的第一个想法是 class
和 extends
做事的方式,但后来我了解到甚至 class
定义都没有提升!
注意:"works",我的意思是子类型从(全部)它们的 parents 继承 functions/values,并且 isPrototypeOf
returns 对任何 [=65] 都是正确的=] 当检查它的任何 parents' 原型时。
函数被提升了,所以它们可能是乱序的,但是链接原型的调用必须是有序的。
如果它们乱序,托管后您的代码将如下所示。
function ParentType(){
this.data = "";
}
function Type(){
ParentType.call(this);
}
function ChildType(){
Type.call(this);
}
ChildType.prototype = Object.create( Type.prototype );
ChildType.prototype.constructor = ChildType;
Type.prototype = Object.create( ParentType.prototype );
Type.prototype.constructor = Type;
也就是说,您将 ChildType.prototype
链接到 Type.prototype
,然后覆盖 Type.prototype
以将其链接到 ParentType.prototype
。
没有办法让这项工作乱序,JavaScript继承取决于按顺序调用的那些代码行。
一种方法是为每种类型声明一个静态初始值设定项。
然而,这只能在运行时执行(通过 Object.crate
或通过赋值),因此我们又回到了起点。如果你的文件确实是按随机顺序连接的,那么你应该使用更复杂的机制和一种 "factory" 函数来创建它们出现的类型并放置子类型 "on hold" 直到它们的父类被创建。
简化示例仅供说明:
function factory(precondition, callback)
{
if( !this.registry ) this.registy = [];
if( !precondition || this.registry[precondition] )
this.registry[callback()] = true;
else setTimeout(function(){factory(precondition, callback);}, 100);
}
factory('Type', function()
{
Window.ChildType = function(){}
return 'ChildType';
});
factory(null, function()
{
Window.Type= function(){}
return 'Type';
});
For multi-link prototype chains, if the statements are out of order, the chain fails to connect properly.
是的。在使用它创建 ChildType.prototype
之前,您需要设置 Type.prototype
。这与提升函数声明无关。
Is there a way to implement inheritance in JavaScript that "works" regardless of the order in which my files are concatenated?
嗯,你 可以 可以使用 Object.setPrototypeOf
:
function ChildType(){
Type.call(this);
}
Object.setPrototypeOf(ChildType.prototype, Type.prototype);
function Type(){
ParentType.call(this);
}
Object.setPrototypeOf(Type.prototype, ParentType.prototype);
function ParentType(){
this.data = "";
}
但是,您真的很想避免这种方法,并且像这样依赖提升是一种非常糟糕的做法,所以您真的应该修复您的串联脚本以使用正确的方法命令。或者使用模块系统为您计算依赖关系。
My first though was the class
and extends
way of doing things, but then I learned that even class
definitions aren't hoisted!
。只需将它们视为纯糖 - 您始终需要按照层次结构以正确的顺序设置它们。
在我当前的 Web 项目中,我正在处理多个 JavaScript 文件,每个文件都包含从其他类型继承的类型定义。所以在任何给定的文件中,我可以有类似...
function Type(){
ParentType.call(this);
}
Type.prototype = Object.create( ParentType.prototype );
Type.prototype.constructor = Type;
... 与 ParentType
在另一个文件中类似地声明:
function ParentType(){
this.data = "";
}
由于在 <head>
标签中处理许多 JavaScript 文件变得很麻烦,我写了一个 bash 脚本来将文件连接成一个文件(称为 master.js
).这样,我可以 link 我的 HTML.
对于只有一个 child 的类型,原型链构建正确,无论我的文件的串联顺序如何。换句话说,这个片段 ...
function ParentType(){
this.data = "";
}
function Type(){
ParentType.call(this);
}
Type.prototype = Object.create( ParentType.prototype );
Type.prototype.constructor = Type;
... 与此代码段的行为相同:
function Type(){
ParentType.call(this);
}
Type.prototype = Object.create( ParentType.prototype );
Type.prototype.constructor = Type;
function ParentType(){
this.data = "";
}
当我在任一场景中创建 Type
的实例时,ParentType.prototype.isPrototypeOf(typeobj)
returns 为真(其中 typeobj
是我的 Type
实例)。
但是,当我将另一种类型添加到 "prototype chain" 的末尾时,它仅在文件按顺序连接时有效,即:
function ParentType(){
this.data = "";
}
function Type(){
ParentType.call(this);
}
Type.prototype = Object.create( ParentType.prototype );
Type.prototype.constructor = Type;
function ChildType(){
Type.call(this);
}
ChildType.prototype = Object.create( Type.prototype );
ChildType.prototype.constructor = ChildType;
... 否则,链 "breaks"。我猜测为什么这在 single-child 场景中是可以的,因为两种类型定义都被提升了,并且只有一组 statements 需要担心原型链。但是对于multi-link个原型链,如果语句乱了,链就无法正常连接。
所以我真正想问的是,有没有一种方法可以在 JavaScript 中实现继承 "works" 而不管我的文件的连接顺序如何? 虽然我的第一个想法是 class
和 extends
做事的方式,但后来我了解到甚至 class
定义都没有提升!
注意:"works",我的意思是子类型从(全部)它们的 parents 继承 functions/values,并且 isPrototypeOf
returns 对任何 [=65] 都是正确的=] 当检查它的任何 parents' 原型时。
函数被提升了,所以它们可能是乱序的,但是链接原型的调用必须是有序的。
如果它们乱序,托管后您的代码将如下所示。
function ParentType(){
this.data = "";
}
function Type(){
ParentType.call(this);
}
function ChildType(){
Type.call(this);
}
ChildType.prototype = Object.create( Type.prototype );
ChildType.prototype.constructor = ChildType;
Type.prototype = Object.create( ParentType.prototype );
Type.prototype.constructor = Type;
也就是说,您将 ChildType.prototype
链接到 Type.prototype
,然后覆盖 Type.prototype
以将其链接到 ParentType.prototype
。
没有办法让这项工作乱序,JavaScript继承取决于按顺序调用的那些代码行。
一种方法是为每种类型声明一个静态初始值设定项。
然而,这只能在运行时执行(通过 Object.crate
或通过赋值),因此我们又回到了起点。如果你的文件确实是按随机顺序连接的,那么你应该使用更复杂的机制和一种 "factory" 函数来创建它们出现的类型并放置子类型 "on hold" 直到它们的父类被创建。
简化示例仅供说明:
function factory(precondition, callback)
{
if( !this.registry ) this.registy = [];
if( !precondition || this.registry[precondition] )
this.registry[callback()] = true;
else setTimeout(function(){factory(precondition, callback);}, 100);
}
factory('Type', function()
{
Window.ChildType = function(){}
return 'ChildType';
});
factory(null, function()
{
Window.Type= function(){}
return 'Type';
});
For multi-link prototype chains, if the statements are out of order, the chain fails to connect properly.
是的。在使用它创建 ChildType.prototype
之前,您需要设置 Type.prototype
。这与提升函数声明无关。
Is there a way to implement inheritance in JavaScript that "works" regardless of the order in which my files are concatenated?
嗯,你 可以 可以使用 Object.setPrototypeOf
:
function ChildType(){
Type.call(this);
}
Object.setPrototypeOf(ChildType.prototype, Type.prototype);
function Type(){
ParentType.call(this);
}
Object.setPrototypeOf(Type.prototype, ParentType.prototype);
function ParentType(){
this.data = "";
}
但是,您真的很想避免这种方法,并且像这样依赖提升是一种非常糟糕的做法,所以您真的应该修复您的串联脚本以使用正确的方法命令。或者使用模块系统为您计算依赖关系。
My first though was the
class
andextends
way of doing things, but then I learned that evenclass
definitions aren't hoisted!