javascript代码中的三明治模式

javascript代码中的三明治模式,javascript,python,aop,Javascript,Python,Aop,如果问题的标题有误导性,请道歉。实际上,我正在寻找与以下python代码等效的javascript: ## python code def call_with_context(fn, *args): ## code to create context, e.g. profiling, db.connect, or drawing context store stack fn(*args) ## code to close context 这实现了与python中的“with语句

如果问题的标题有误导性,请道歉。实际上,我正在寻找与以下python代码等效的javascript:


## python code
def call_with_context(fn, *args):
  ## code to create context, e.g. profiling, db.connect, or drawing context store stack
  fn(*args)
  ## code to close context 
这实现了与python中的“with语句”类似的功能,后者实现了面向方面的范例

所以我的问题是javascript做这些事情的方式是什么?我见过一些代码使用Array.prototype.slice(arguments,1)来实现这一点,但我不知道这是javascript中的常见模式,还是javascript中支持更好的模式(例如闭包),所以ppl并没有真正做到这一点。如果我使用了错误的关键词,也请纠正我,因为我真的不知道如何用一个比三明治更好的名字来指代我的问题


EDT 1:如果有人能解释如何在包装器调用_中使用_上下文返回fn(*args)的结果,我将不胜感激。谢谢

听起来您想调用具有特定上下文的方法

在js中,您通常会

function someFunction( fn, context ) {
   fn.call( context );
}

var Button = {
   isClicked: false
};
someFunction(function () {
   // this === Button
   this.isClicked = true;
}, Button );
现在,
fn
中的
this
关键字将表示传递到方法
someFunction
中的上下文。这种模式经常出现。尤其是回调。

类似这样的情况

// javascript code
function call_with_context(fn) {
  // code to create context, e.g. profiling, db.connect, or drawing context store stack
  var r = fn.call(Array.prototype.slice.call( arguments, 1)); // remove first arg - fn 
  //code to close context 
  return r; 
}
因此,您将能够做到这一点:

call_with_context(myfun,1,2,3);
那将以电话结束

myfun(1,2,3);

我认为更典型的JS方法可能是装饰函数。因此,如果您想将函数包装在记录计时的内容中,您可以创建这样一个函数(在我的脑海中):

要点是,您可能不会这样称呼:

runTimerAround(test, 3, 4, 5);

虽然这也可以在JS中完成,但我相信这比直接覆盖函数要少见。

这是我搜索后的解决方案。希望对其他人有帮助


function call_with_context(fn) {
  // some beginning code
  console.log('begin');

  r = fn.apply(null, Array.prototype.slice.call(arguments, 1));

  // some ending code
  console.log('end');

  return r;
}

在仔细阅读了每一篇帖子/评论之后,我认为OP是 正在查找
[javascript]
[方法修改]
。回答正确 抛开OP关于术语的问题,改变中的封闭功能 JavaScript与面向方面编程无关,除非 声称是AO的实现提供了抽象和代码重用 至少方面、建议和切入点的级别

对了,一切都好 其他方法可以通过(手动)将功能包装到另一个功能中来实现。在这里 再说一次,我不会把它称为函数组合。为了 如果符合这个条件,至少应该有一些工具集,因为它们已经存在了 存在于
compose
和/或
curry
方法/模式的各种实现中

对于OP将要实现的目标,有一大堆
之前
之后
around
/
wrap
解决方案,不幸的是,大部分都提到了AO(P),而且在 许多情况下,不考虑上下文或
目标
,这是至关重要的 这也是OP要求的

我提供的示例使用了
函数的原型实现。
因为JavaScript已经有了一个标准化的
绑定
,我坚信这一点 这个
函数。prototype
对于其他一些方法修饰符来说也是正确的位置 像

支持以下示例的代码库:

(function (Function) {
  var
    isFunction = function (type) {
      return (
           (typeof type == "function")
        && (typeof type.call == "function")
        && (typeof type.apply == "function")
      );
    },
    getSanitizedTarget = function (target) {
      return ((target != null) && target) || null;
    }
  ;
  Function.prototype.around = function (handler, target) { // [around]
    target  = getSanitizedTarget(target);

    var proceed = this;
    return (isFunction(handler) && isFunction(proceed) && function () {

      return handler.call(target, proceed, handler, arguments);

    }) || proceed;
  };
}(Function));
示例代码,通过在给定的封闭函数之前和之后额外提供行为并提供其上下文来修改该函数


谢谢你,特雷弗。因此,即使fn是与另一个对象(如“console.log”)关联的方法,fn“fn.call”的调用仍将在正确的“this”对象上。我的理解正确吗?或者在js中传递绑定方法是非法的?在我的示例中,如果使用console作为上下文,则会将
isClicked:true
属性添加到console对象中。如果忽略传递上下文,则传入的方法将作为已绑定的方法传入。你可以通过任何你想要的方法。谢谢你的澄清。那么,如果我想从某个函数内部返回fn.call结果,比如直接通过“return fn.call(context);”,那么返回值是什么呢?返回值是
fn
returns.)谢谢我猜“arguments.slice”的意思是“Array.prototype.slice.call”as arguments在js中不是真正的数组?当我在firefox中尝试代码时,结果总是没有返回结果?我认为这个问题可能有点误导。虽然有一些AOP是通过Javascript完成的,但并不常见。对于一流的函数和动态的一切,通常很容易用修饰过的版本覆盖函数,因此没有真正的理由引入任何实质性的AOP工具。是的,它更像python中的注释解决方案。:)
(function (Function) {
  var
    isFunction = function (type) {
      return (
           (typeof type == "function")
        && (typeof type.call == "function")
        && (typeof type.apply == "function")
      );
    },
    getSanitizedTarget = function (target) {
      return ((target != null) && target) || null;
    }
  ;
  Function.prototype.around = function (handler, target) { // [around]
    target  = getSanitizedTarget(target);

    var proceed = this;
    return (isFunction(handler) && isFunction(proceed) && function () {

      return handler.call(target, proceed, handler, arguments);

    }) || proceed;
  };
}(Function));
var loggingDelegate = function () { // closed code that can not be changed for any reason.

  this.log.apply(this, arguments);
};


loggingDelegate.call(console, "log", "some", "arguments");


var interceptedLoggingDelegate = loggingDelegate.around(function (proceed, interceptor, args) {

  // everything that needs to be done before proceeding with the intercepted functionality.


  // [this] in this example refers to [console], the second argument of the [around] modifier.

  this.log("proceed:", proceed);         // the original functionality  - here [loggingDelegate].
  this.log("interceptor:", interceptor); // the modifying functionality - [around]s 1st argument.
  this.log("args:", args);               // the arguments that get passed around.


  proceed.apply(this, args);
  // or:
  //return proceed.apply(this, args);
  // or:
  //var result = proceed.apply(this, args);


  // everything that still needs to be done after invoking the intercepted functionality.

  // if necessary:
  //return result;

}, console); // [console] has to be provided as target to the modified [loggingDelegate].


interceptedLoggingDelegate("intercept", "and", "log", "some", "arguments");