【问题标题】:prototyping a closure method in javascript在 javascript 中对闭包方法进行原型设计
【发布时间】:2013-03-17 22:25:44
【问题描述】:

我是 javascript 新手,我的问题可能非常愚蠢。我无法获得正确的参考。

我正在尝试用 javascript 编写一个控制器对象。这里的想法是让它成为一个接口对象,任何人都可以从它的原型继承并覆盖他们存在的方法。

我只想向对象公开一个方法“process()”,该方法将调用所有剩余的方法和属性。我试图通过使用闭包将所有其他方法和属性设为私有来实现这一点。这是我的代码的示例 sn-p

var ViewController = function() {

    var _viewName = null;


  var loadView = function(viewName) {

    console.log("now loading view : "+viewName+ " ...");
  };

    return {
        process : function(viewName){
            _viewName = viewName;
            loadView(_viewName);
        }
    };

};


var vController = ViewController();
vController.process("alphaView");

现在这工作得很好。但是,如果我想使用原型覆盖方法 PreProcess、loadView、initView 和 PostProcess,它就不起作用。我尝试使用 Object.create 覆盖

var vController2 = Object.create(ViewController, {

  LoadView : function(viewName) {
    //some custom implementation
  },
  //and so forth
});

如果我更改实现以使用原型定义外部方法也不起作用。喜欢

 var ViewController = function() {

      var _viewName = null;

      return {
        process : function(viewName){
          _viewName = viewName;
          loadView(_viewName);
        }
      };

    };

    ViewController.prototype.loadView = function(viewName) {

        console.log("now loading view : "+viewName+ " ...");
    };

我的问题的要点是我想要 (a) 控制器的接口对象,用户可以在其中覆盖一个基本方法(LoadView,) (b) 所有这些成员都是控制器对象私有的,可以通过“Process()”方法访问

请指教!

编辑:编辑代码使其变得简单。

【问题讨论】:

  • 请将您的代码缩减为您正在尝试做的最小(或至少更短)示例。
  • 如果你想从实现外部覆盖方法,那么不要将它们设为私有的本地函数。相反,将它们添加到实际的对象原型中。目前尚不清楚您真正想通过仅使用一种实际方法process() 来解决什么问题。这听起来像是您避开了普通的 javascript 功能。
  • 我想要的是开发者实际上可以创建一个继承的 ViewController 对象并实现它自己的 LoadView 方法。例如。应用程序可以有多个控制器,比如controller1、controller2 等,每个控制器对其LoadView 执行不同的操作。但是控制器对象,无论何时何地实例化都只能调用 process(),即调用 LoadView 的唯一方法是通过 process()。我可能搞错了,这就是我需要建议的原因。
  • 我认为这里的主要混淆来源(在 jfriend00 说过之后)是如果你从使用new 调用的构造函数返回一个 Object,它会丢弃构造函数自己的实例支持返回的对象,它不会(必然/默认)继承与构造函数相同的 prototype。您可能会发现 this answer 很有帮助。
  • @curioussam - 好的,现在我更好地理解了你想要做什么,我在我的答案中添加了另一个选项。

标签: javascript oop interface closures


【解决方案1】:

将您希望人们能够覆盖的方法放在原型上,使它们成为真正的方法,并被process() 称为真正的方法。然后,一旦您创建了这种类型的对象,您就可以为任何方法创建新的覆盖定义,process() 将自动调用它们而不是原始方法。一种方法是这样的:

function ViewController() {
}

ViewController.prototype = {
    loadView: function(viewName) {
        console.log("now loading view : "+viewName+ " ...");
    },
    preProcess: function(viewName) {
        console.log("now Pre Processing view : "+viewName+ " ...");
    },
    // other methods here ...
    process: function(viewNmae) {
        this.viewName = viewName;
        console.log(_viewName);
        this.preProcess(_viewName);
        this.loadView(_viewName);
        this.initView(_viewName);
        this.postProcess(_viewName);
    }
}

var controller = new ViewController();
controller.loadView = function(viewName) {
    // override function for loadView
}
controller.process(viewName);

如果你真的想禁止调用override方法,那么你就放弃使用javascript的内置原型机制(因为它是公共的,任何方法都可以调用)。因此,您可以使用自己的方案,只需添加新的公共方法来设置覆盖函数。在您现有的代码中,更改以下内容:

return {
    process : function(viewName){
        _viewName = viewName;
        loadView(_viewName);
    }
};

到这里:

return {
    process : function(viewName){
        _viewName = viewName;
        loadView(_viewName);
    },
    setLoadViewFn: function(fn) {
        loadView = fn;
    }
    // add other override setting functions here
};


// create controller object
var controller = new ViewController();
// set override function for loadView
controller.setLoadViewFn(function(viewName) {
    // override function for loadView
});
controller.process(viewName);

【讨论】:

  • 所以看起来在这里使用闭包使这些成员“私有”不是一个好的选择。这对我来说是一个范式转变,因为我来自经典的 OO 语言
  • 如果您想使用 javascript 的内置对象/原型功能,这不是一个好的选择。您可以使用您的方案,但您必须创建公共方法来设置覆盖函数并将它们存储在您自己的私有实例数据中。这是我所知道的允许设置方法的唯一方法,但无法在 process() 之外调用它们。
  • @curioussam - 现在你已经更好地描述了你想要做什么,我已经使用你现有的代码隐私机制添加了另一个选项。
  • 这是有道理的,我可以在这里看到一些抽象和封装!这可能会奏效。谢谢:)
  • 这种方法似乎不起作用,因为它返回一个错误,“SyntaxError: Expected an identifier but found 'function' instead”
猜你喜欢
  • 2011-03-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-10
相关资源
最近更新 更多