0

如果问题的标题具有误导性,请道歉。实际上我正在寻找以下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:如果有人能解释如何从包装器 call_with_context 中返回 fn(*args) 的结果,我将不胜感激。谢谢!

4

5 回答 5

1

我认为更典型的 JS 方法可能是装饰函数。所以如果你想把你的函数包装在记录时间的东西中,你可以创建一个像这样的函数(在我的脑海中):

var createTimer = function(fn) {
    return function() {
        var start = new Date();
        var result = fn.apply(this, arguments);
        console.log("Took " + (new Date() - start) + " ms.");
        return result;
    }
};

var test = function(a, b, c) {
    return a * b + c;
}

test = createTimer(test);

console.log(test(3, 4, 5));

// Took 0 ms.
// 17

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

runTimerAround(test, 3, 4, 5);

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

于 2012-07-07T04:14:10.893 回答
1

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

在 js 中,你通常会做...

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

var Button = {
   isClicked: false
};
someFunction(function () {
   // this === Button
   this.isClicked = true;
}, Button );

现在this里面的关键字fn将代表传递给方法的上下文someFunction。这种模式经常出现。尤其是回调。

于 2012-07-07T03:32:46.067 回答
0

像这样的东西

// 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);
于 2012-07-07T03:47:03.723 回答
0

在仔细阅读每篇文章/评论后,我认为 OP 正在寻找[javascript][method-modification]. 并立即回答 OP 关于术语的问题,更改 JavaScript 中的封闭功能与面向方面的编程无关,除非声称是AO的实现至少为AspectAdvicePointcut提供抽象和代码重用级别。

正如Scott Sauyet已经评论 过的那样,其他所有事情都可以通过(手动)将功能相互包装来完成。再说一次,我不会走那么远并将其称为function-composition。为了符合条件,至少应该有一些工具集,因为它们已经存在于各种实现compose和/或curry方法/模式中。

对于 OP 将要实现的目标,有一大堆before, after around/wrap解决方案,不幸的是提到AO(P),并且在很多情况下没有考虑上下文或者target这是必不可少的,并且也被 OP 要求.

我提供的示例使用Function.around. 由于bindJavaScript 已经 具有标准化 的 . Function.prototype_ _ _ beforeafteraroundafterThrowingafterFinally

将支持以下示例的代码库:

(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");
于 2014-12-25T17:47:54.613 回答
0

经过一番搜索,这是我的解决方案。希望对其他人有所帮助。


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;
}
于 2012-07-07T07:59:13.280 回答