在 Javascript 中实现 isInstance
我定义了两个函数如何相互继承,如下所示:
Function.prototype.inherit = function(parent){
function proto() {}
proto.prototype = parent.prototype;
this.prototype = new proto();
this.prototype.constructor = this;
this.prototype.parent = parent;
}
然后,我需要定义一个 isInstance 函数,其行为类似于 Java 的 instanceOf 或 PHP 的 instanceof。本质上,isInstance 可用于确定变量是否是从父函数继承的函数的实例化对象。
这就是我写的:
Function.prototype.isInstance = function(func){
if(this == func){
return true;
} else{
if (this.prototype.parent == undefined || this.prototype.parent == null) {
return false;
} else {
return this.prototype.parent.isInstance(func);
}
}
}
在比较两个函数时效果很好,但在比较实例化变量时效果不佳。
Object2.inherit(Object1);
Object2.isInstance(Object1); //returns true
var obj2 = new Object2();
obj2.isInstance(Object1);// obj2.isInstance is not a function
上面的最后一个案例是我想要开始工作的。如何将 isInstance 添加到实例,而不仅仅是函数?对于所有 javascript 专家来说,我的代码是否有任何改进(也许是继承方法)?
谢谢。
I define how two functions can inherit from each other as follows:
Function.prototype.inherit = function(parent){
function proto() {}
proto.prototype = parent.prototype;
this.prototype = new proto();
this.prototype.constructor = this;
this.prototype.parent = parent;
}
I then need to define an isInstance function that would behave like Java's instanceOf or PHP's instanceof. In essence, isInstance could be used to determine whether a variable is an instantiated object of a function that inherits from a parent function.
This is what I wrote:
Function.prototype.isInstance = function(func){
if(this == func){
return true;
} else{
if (this.prototype.parent == undefined || this.prototype.parent == null) {
return false;
} else {
return this.prototype.parent.isInstance(func);
}
}
}
Which works fine when comparing two functions, but not when comparing instantiated variables.
Object2.inherit(Object1);
Object2.isInstance(Object1); //returns true
var obj2 = new Object2();
obj2.isInstance(Object1);// obj2.isInstance is not a function
The last case above is what I want to get working. How can I add isInstance to instances, not just functions? And to all javascript gurus out there, are there any improvements to my code (the inherit method, maybe)?
Thanks.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
JavaScript 自己的
instanceof
有什么问题?给定您的继承函数,
instanceof
通过检查给定构造函数的prototype
属性是否在实例的原型链中来工作。所以例如。这就是为什么即使
Square.prototype
不是使用new Shape
创建的,instanceof Shape
仍然可以工作;相反,它是由new proto()
创建的,但由于proto
和Shape
共享相同的prototype
属性, JavaScript 无法区分。通常你看不到原型链(尽管 Firefox 和 WebKit 通过 __proto__ 属性提供它),但这是 JS 中实际处理继承的方式;可见的 Function.prototype 属性仅用于在
new
时设置原型链的初始状态。但我不确定这是否真的能让你受益匪浅!对对象进行原型设计通常被认为是很糟糕的,因为它实际上会影响每个对象,并且可能会混淆使用对象进行查找映射的其他脚本。
我喜欢你的继承方法,它是制作对象系统的更轻量级和 JavaScript 的方法之一。
使用
instanceof
您可能会丢失parent
和constructor
属性,除非您出于其他方便目的需要它们。我会将parent
放在构造函数上(所以它就像一个知道其基类的子类),并且我会调用constructor
其他东西(已经有属性在 Firefox 中称为构造函数
,但它不会按照您的想法执行,通常最好避免)。我看到的唯一缺点是你不能继承构造函数,所以每次你创建一个新的子类时,你都必须编写一个调用基构造函数的构造函数,即使你的子类的构造函数什么也不做:
What is wrong with JavaScript's own
instanceof
?Given your inherit function,
instanceof
works by checking whether the given constructor'sprototype
property is in the instance's prototype chain. So eg.This is why
instanceof Shape
works even thoughSquare.prototype
was not created usingnew Shape
; instead it was created bynew proto()
, but since bothproto
andShape
share the sameprototype
property, JavaScript can't tell the difference.You can't normally see the prototype chain (although Firefox and WebKit make it available through the
__proto__
property), but it is the way inheritance is actually handled in JS; the visible Function.prototype property is only used to set up the initial state of the prototype chain atnew
-time.I'm not sure this really gets you much though! And prototyping into Object is often considered in poor taste, as it affects literally every object and can confuse other scripts using Object for a lookup mapping.
I like your inherit method, it's one of the more lightweight and JavaScripty ways of making an object system.
With
instanceof
you could lose theparent
andconstructor
properties, unless you wanted them for other convenience purposes. I'd put theparent
on the constructor function though (so it's like a subclass knowing its base class), and I'd callconstructor
something else (there is already property calledconstructor
in Firefox but it doesn't do what you think and is generally best avoided).The only drawback I see is that you can't inherit the constructor function, so every time you make a new subclass you must write a constructor that calls the base constructor, even if your subclass's constructor does nothing at all:
为什么需要这样做? JavaScript 没有严格的类层次结构的概念是有原因的:它确实无法做到。您可能可以找到一个在大多数情况下都有效的解决方案,但我不确定您是否可以涵盖所有边缘情况。此外,由于 JavaScript 没有任何接口概念,因此测试显式继承会导致高耦合,并且似乎违反了 坚实的原则。
解决这个问题的一个更好(也更惯用)的方法是使用鸭子打字。只需测试您需要的方法是否存在,然后调用它。只要准备好在必要时捕获异常(无论如何你都应该这样做)。
Why do you need to do this? JavaScript doesn't have a notion of a strict class hierarchy for a reason: it really can't be done. You can probably get to a solution that works most of the time, but I'm not sure you can cover all the edge cases. Additionally, since JavaScript doesn't have any notion of interfaces, testing for explicit inheritance leads to high coupling, and would seem to violate the SOLID principles.
A much better (and more idiomatic) way of approaching this problem is to use duck typing. Simply test for the existence of the method you need, and then call it. Just be prepared to catch an exception if necessary (which you should be doing anyway).
暂时将良好的设计论点放在一边并专注于您的问题,问题在于您将
isInstance()
设置为Function
原型上的方法。这意味着属于函数
的对象将具有它,而不是函数的对象(例如示例中的Object1
和Object2
)则不会。我建议不要尝试将其实现为方法,而是将其作为静态函数:
然后可以将其调用为
To leave the good design argument aside for a second and focus on your problem, the issue is that you set
isInstance()
to be a method onFunction
's prototype. This means Objects that areFunction
s will have it, while Objects that are not (such asObject1
andObject2
in your example) will not.I suggest that instead of trying to implement it as a method, you have it be a static function:
You can then invoke it as