Javascript OOP - 通过接口或原型验证对象时的最佳实践

时间:2011-10-18 21:35:57

标签: javascript oop inheritance interface prototype-programming

我正在为来自C#背景的javascript学习更高级的OO策略,并且想知道如何或者如果它甚至是一个好主意来实现基于原型的验证。例如,当一个对象或函数需要其中一个参数来满足某个接口时,您可以像这样检查其接口,

var Interface = function Interface(i) {
   var satisfied = function (t, i) {
      for (var key in i) {
         if (typeof t !== 'object') {
            return false;
         }
         if (!(key in t && typeof t[key] == i[key])) {
            return false;
         }
      }
      return true;
  }
  this.satisfiedBy = function (t) { return satisfied(t, i); }
}

// the interface
var interfacePoint2D = new Interface({
    x: 'number',
    y: 'number'
}); 

// see if it satisfies
var satisfied = interfacePoint2D.satisfiedBy(someObject); 

我想出了这个策略,只通过它的接口验证一个对象,忽略了对象的内部实现。

或者说您正在使用基于原型的继承,您是否应该根据原型函数验证参数?我知道您使用原型来实现默认功能,而接口不指定任何默认功能。有时,您传递给函数的对象可能需要某些默认功能才能使该函数正常工作。是否更好地仅对接口进行验证,或者您是否应该对原型进行验证,如果是,那么最好的方法是什么?

编辑 - 我提供了更多关于我为什么这样问的背景,

比如说在线游戏设计(主要用javascript编写的游戏)。在这种情况下,我有两个主要原因需要验证,

1)如果需要,提供强大的公共API来修改游戏

2)预防(或至少令人沮丧)潜在的骗子

这需要在可定制性和滥用之间取得平衡。具体而言,一种情况是设计物理引擎,其中游戏中的物体对重力做出反应。在现实系统中,用户不应该向系统添加不对重力做出反应的对象。该系统具有在任何给定点表达重力的全局影响的函数:

function getGravityAt(x, y) {
      // return acceleration due to gravity at this point
}

反应的对象有一个使用它来更新加速度的方法:

function update() {
      this.acceleration = getGravity(this.position); 
}

要做的最小事情可能是确保添加到系统中的任何对象都有“更新”方法,但您仍然无法确保update()方法确实是为了对重力作出反应。如果只允许从原型update()方法继承的对象,那么至少在某种程度上你知道系统中的所有内容都会做出真实的反应。

2 个答案:

答案 0 :(得分:2)

这是一个非常主观的问题。我将传递一个问题,即在Javascript中进行基于接口的验证是否是一个好主意(可能有很好的用例,但它不是语言中的标准方法)。但我会说,根据原型验证对象可能

如果您正在通过界面进行验证,那么您可能正在使用其他程序员创建的对象。有很多方法可以创建对象 - 有些方法依赖于原型,有些则不依赖原型,虽然它们各自都有自己的支持者,但它们都是有效且可能接近的。例如:

var Point = function(x,y) {
    return {
        x: function() { return x },
        y: function() { return y }
    };
};

var p = new Point(1,1);

对象p符合与您类似的界面,但xy是函数。但是,通过检查其构造函数(p)或Object(),无法验证Point.prototype是否满足此接口。您所能做的只是测试p具有名为xy的属性,以及它们的类型为"function" - 您在上面做了什么。

你可能会坚持认为p在其原型链中有一个特定的祖先,例如AbstractPoint,其中包含xy函数 - 您可以使用instanceof来检查此问题。但您无法确定x中是否yp尚未重新定义:

var AbstractPoint = function() {};
AbstractPoint.prototype.x = function() {};
AbstractPoint.prototype.y = function() {};

var Point = function(x,y) {
    var p = new AbstractPoint(x,y);
    p.x = "foo";
    return p;
}

var p = new Point(1,1);
p instanceof AbstractPoint; // true
p.x; // "foo"

也许更重要的是,这使得更难以放入同样满足界面但不从类中继承的自定义对象。

所以我认为你目前正在做的事情可能是你所希望的最好的。根据我的经验,Javascript程序员更有可能使用动态鸭子打字,而不是试图模仿静态类型语言的功能:

function doSomethingWithUntrustedPoint(point) {
    if (!(point.x && point.y)) return false; // evasive action!
    // etc.
}

答案 1 :(得分:0)

我会重申,类型检查不是惯用的javascript。

如果您仍想进行类型检查,Google的closure compiler是我推荐的实施方式。类型检查是静态完成的:)它具有接口和(proto)类型检查的约定。