在 Javascript 中确定对象类型的最佳实践
Posted
技术标签:
【中文标题】在 Javascript 中确定对象类型的最佳实践【英文标题】:Best practice for determining objects type in Javascript 【发布时间】:2011-12-08 04:02:18 【问题描述】:如果你在 javascript 中有一个对象的实例,似乎很难找到它的实际类型,即
var Point2D = function Point2D(x, y)
return
X: x,
Y: y
var p = new Point2D(1,1);
typeof p // yields just 'Object' not 'Point2D'
我发现的一种解决方法是让对象成为自己的原型,然后你可以通过调用prototype.constructor.name来有效地获取它的名字,
var Point2D = function Point2D(x, y)
return
X: x,
Y: y,
prototype: this
new Point2D(1,1).prototype.constructor.name // yields 'Point2D'
这是一种可行的方法吗(优点/缺点是什么?)还是我错过了更好的做法?
谢谢。
【问题讨论】:
Point2D(1,1).name 在 FF 或 chrome 中似乎不起作用。 它在 Chrome 中适用于我,但我不知道这是否是最好的方法。 它依赖于函数签名吗?即 var Point2d = function Point2D() ? @SeanThomanFunction.prototype.name
不是标准的,因此在某些浏览器中将无法正确实现或根本无法实现。
看我的编辑,我想这就是你想要的。
【参考方案1】:
首先,我们需要解决您构建课程的方式,因为您会陷入一些 JS 陷阱并做一些非常奇怪的事情:
function Point2D(x, y)
//Our constructor/initialization function
//when run, the 'this object will have
//Point2D.prototype as its prototype
this.x = x;
this.y = y;
//Don't return a value here! Doing so overrides
//the default "return this" that we actually want.
//You can put things in the Point2D prototype in order to have them
//be shared by all Point2D objects. Normally you want the methods to be shared.
Point2D.prototype.getX = function()
return this.x;
;
//Note that there is nothing magical about the "prototype" property.
//It is just where the `new` syntax expects the prototype it will use to be.
//The actual magic property is __proto__ (don't depend on it though
// __proto__ is browser specific and unsafe/evil)
//We now can create points!
var p = new Point2D(17.0, 42.0);
p.getX();
现在我们可以处理有关获取类型名称的部分了。您缺少的更好的做法是首先不检查类型。从 OO 的角度来看,对象是如何实现的(ts 类)并不重要,重要的是它的行为方式以及它的接口是什么(公开的方法和属性)。此外,从 Javascript 的角度来看,类型名称是一种二等 hack,与实际使用的原型 OO 方案不太吻合。
由于您可能首先尝试检查类型名称的原因有很多,因此有许多不同的“最佳”解决方案。我能想到的一些:
如果您只关心“这个对象是否实现了特定的点接口”,那么您可以直接进行特征检查:
function isPoint(p)
//check if p has all the methods I expect a point to have:
//(note that functions are truthy in a boolean context)
return (p.getX && p.getY);
如果您使用类型名称进行调度,请考虑使用方法。它是自然的 OO 方式。
function speak(obj)
//fake pseudo-syntax:
if(obj is of type Cat) console.log("meow");
if(obj is of type Dog) console.log("woof");
变成
Cat.prototype.speak = function() console.log("meow"); ;
Dog.prototype.speak = function() console.log("woof"); ;
如果你真的需要某种标签,你可以明确地制作一个,正如其他一些答案已经指出的那样:
Point2D.prototype.pointType = "2D";
这里的优点是,如果需要,您可以让多个类具有相同的“类型”,并且您不必担心任何棘手的instanceof
或typeof
极端情况。
【讨论】:
谢谢你,非常有帮助和详尽,尤其是关于查看界面而不是类型的观点。干杯!【参考方案2】:我想知道你是否想要像这样更简单的东西:
function Point2D(x, y)
this.X = x;
this.Y = y;
var p = new Point2D(1,1);
alert(p instanceof Point2D); // true
编辑:
您可以添加自己的类型属性:
function Point2D(x, y)
this.X = x;
this.Y = y;
this.type = "Point2D";
var p = new Point2D(1,1);
alert(p.type); // "Point2D"
关于为什么要知道对象的类型,您没有说太多。我建议您可能要重新考虑这一点。只要有可能,特定类型的方法处理应该放在对象之间的公共方法中,这样您只需在方法调用中请求一个操作,并且该方法在每个特定对象的方法中实现特定类型的处理。
【讨论】:
我的情况希望函数返回一个匿名对象。否则这会很好..但是我可以将它变成一个解决方案。 如果函数返回一个匿名对象,那么它的类型就是一个匿名对象。你不能在这里两者兼得。如果您希望它成为 Point2D 的实例,它实际上必须是 Point2D 的实例,而不是匿名对象。选择你真正想要的。为什么它需要是一个匿名对象?我的 Point2D 函数对象和您的匿名对象都具有相同的属性.X
和 .Y
。 Point2D 的不同之处在于您可以修改它的原型,以便新实例具有自定义方法。而且,您可以使用instanceof
来识别它。
您还可以添加自己的属性来标识类型。我在答案中添加了一个示例来说明这一点。
@jfriend00,我想使用一个匿名对象,以便返回的对象可以具有关闭外部函数中的变量的函数。因此,是的,必须向匿名对象添加一些东西以指示其类型,除非还有其他我不知道的技巧。将所述指标添加到匿名对象的那个或更好的做法。
@jfriend00,我也可以将内部函数命名为与外部函数相同的名称,这可能会起作用..【参考方案3】:
Typeof
仅告诉您 var x 是否为:
现在variable.constructor
告诉您哪个函数实际创建了当前对象。
也有区别:
var foo = function Test()
;
var x = new foo();
// Here, x.constructor == function Test();
// and x.constructor.name == 'Test'
function Bar()
var y = new Bar();
// But here, y.constrcutor == 'Bar'
【讨论】:
这也不起作用。您确定这不是针对不同类型的函数签名或不返回 或形成闭包的函数吗?【参考方案4】:您不会返回 Point2D,而是这样:
X: x,
Y: y
这显然是一个对象。
顺便说一句,您要查找的是p instanceof Point2D
。
编辑:
你不会碰巧在寻找这种模式吧?
function Point2D(x, y)
var self = this;
this.X = x;
this.Y = y;
this.getX = function()
alert(this.X);
var p = new Point2D(1,1);
p.getX();
alert(p instanceof Point2D); // true
【讨论】:
你确定这真的一直有效吗?对我不起作用。关于返回问题,我明白你的意思,但是我需要返回的对象具有执行闭包的函数。【参考方案5】:嗯,这很复杂。你可以从这个函数开始:
其实jQuery中有很多很棒的功能。查看所有以“is”开头的实用函数:http://api.jquery.com/category/utilities/
如果这些还不够好,请在此处查找他们的源代码并编写您自己的变体:http://james.padolsey.com/jquery/#v=1.6.2
你也可以使用这个功能:
function listProps (obj)
console.log("constructor: "+obj.constructor);
console.log("prototype "+obj.prototype);
for (var prop in obj)
console.log(prop+": "+obj.prop);
【讨论】:
以上是关于在 Javascript 中确定对象类型的最佳实践的主要内容,如果未能解决你的问题,请参考以下文章