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

我正在为来自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()方法继承的对象,那么至少在某种程度上你知道系统中的所有内容都会做出真实的反应.

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

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

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

var p = new Point(1,1);

除了x和y是函数之外,对象p符合与上面类似的接口.但是没有办法通过检查它的构造函数(Object())或Point.prototype来验证p是否满足此接口.您所能做的就是测试p具有名为x和y的属性,以及它们是“函数”类型 – 您在上面做了什么.

您可能会坚持认为p在其原型链中具有特定的祖先,例如: AbstractPoint,包括x和y函数 – 您可以使用instanceof来检查它.但你不能确定x和y还没有在p中重新定义:

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.
}
点赞