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

Sea*_*man 15 javascript constructor types 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'
Run Code Online (Sandbox Code Playgroud)

我找到的一种方法是将对象作为自己的原型,然后通过调用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'
Run Code Online (Sandbox Code Playgroud)

这是不是一个好的方法(优点/缺点是什么?)还是我错过了更好的做法?

谢谢.

hug*_*omg 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();
Run Code Online (Sandbox Code Playgroud)

现在我们可以解决有关获取类型名称的部分.您缺少的更好的做法是不首先检查类型.从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);
    }
    
    Run Code Online (Sandbox Code Playgroud)
  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"); }
    }
    
    Run Code Online (Sandbox Code Playgroud)

    Cat.prototype.speak = function(){ console.log("meow"); };
    Dog.prototype.speak = function(){ console.log("woof"); };
    
    Run Code Online (Sandbox Code Playgroud)
  3. 如果你真的需要某种标记,你可以明确地创建一个标记,正如其他一些答案所指出的那样:

    Point2D.prototype.pointType = "2D";
    
    Run Code Online (Sandbox Code Playgroud)

    这里的优点是,如果需要,您可以让多个类具有相同的"类型",并且您不必担心任何棘手instanceoftypeof极端情况.