在Javascript中确定对象类型的最佳实践

时间:2011-10-15 00:52:57

标签: javascript types constructor typechecking

如果你在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'

这是不是一个好的方法(优点/缺点是什么?)或者是否有一个我错过的更好的做法?

感谢。

5 个答案:

答案 0 :(得分:5)

首先,我们需要修复你如何构建你的类,因为你正在绊倒一些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的角度来看,类型名称是一种二级黑客,它与实际使用的原型OO方案不太匹配。

由于您可能首先尝试检查类型名称的原因有很多,因此有许多不同的“最佳”解决方案。我能想到的一些:

  1. 如果您只关注“此对象是否实现了特定的点接口”,那么您可以直接进行功能检查:

    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);
    }
    
  2. 如果使用类型名称进行调度,请考虑使用方法。它是天然的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"); };
    
  3. 如果真的需要某种标记,你可以明确地创建一个标记,正如其他一些答案所指出的那样:

    Point2D.prototype.pointType = "2D";
    

    这里的优点是,如果您需要,您可以让多个班级具有相同的“类型”,并且您不必担心任何棘手的instanceoftypeof角落案件。

答案 1 :(得分:3)

我想知道你是否想要更简单的东西:

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"

你没有多说过你想知道一个物体的类型。我建议你可能想重新考虑一下。只要有可能,特定于类型的方法处理应该放在对象之间的常用方法中,这样你就可以在方法调用中请求一个动作,并且该方法在每个特定对象的方法中实现特定于类型的处理。

答案 2 :(得分:1)

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' 

答案 3 :(得分:0)

你没有返回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

答案 4 :(得分:0)

嗯,这很复杂。您可以从这个功能开始:

实际上jQuery中有很多很棒的功能。查看以“是”开头的所有实用程序函数: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);
    }
}