你能说这是 Javascript Closure 的一个正确的例子吗?我们需要考虑避免闭包的地方在哪里?

发布于 2024-08-17 15:53:07 字数 1369 浏览 2 评论 0原文

问题与原因

我的一位队友最终陷入了在 javascript 中实现函数挂钩的混乱局面。这是实际的代码

 function ActualMethod(){   
       this.doSomething = function() {
              this.testMethod();
        };

       this.testMethod = function(){
            alert("testMethod");
        };
   }


 function ClosureTest(){
       var objActual= new ActualMethod();   
    var closeHandler = objActual.doSomething;   
    closeHandler();     
    closeHandler.apply(objActual,arguments); //the fix i have added
    this.ActualTest = function() {
        alert("ActualTest");
        };
  }

在上面的代码中,var closeHandler 是在 ClosureTest() 的上下文中创建的,但它保存了 ActualMethod.doSomething 的处理程序。每当调用 closeHandler() 时都会出现“对象不支持此方法”错误。

这是因为 doSomething() 函数调用了另一个名为 this.testMethod(); 的方法。这里 this 指的是调用者的上下文而不是被调用者。所以我假设 closeHandler 绑定到实际创建的环境(ClosureTest)。即使它将处理程序保存到另一个上下文,它也只是暴露了其自身上下文的属性。

解决方案

为了避免这种情况,我建议使用apply来指定它需要执行的上下文。

closeHandler.apply(objActual,参数);

问题

是关闭的完美场景吗??

你在 javascript 中遇到过哪些有趣的地方的闭包?

更新

是的,它很简单,我可以直接调用该方法。但问题是,在特定场景中,我需要拦截对实际方法的调用并在此之前运行一些代码,最后执行实际方法。

举个例子,我正在使用第 3 方 aspx 网格库,并且所有mouseclick 事件被它们的控件捕获。特别是通过鼠标单击进行分组,我需要拦截对其 ilbrary 方法的调用,并挂钩我的方法来执行,并将调用重定向到实际的库方法

希望这会有所帮助

Problem & Reason

One of my team mate ended up in messy situtaion implementing function hooking in javascript. this is the actual code

 function ActualMethod(){   
       this.doSomething = function() {
              this.testMethod();
        };

       this.testMethod = function(){
            alert("testMethod");
        };
   }


 function ClosureTest(){
       var objActual= new ActualMethod();   
    var closeHandler = objActual.doSomething;   
    closeHandler();     
    closeHandler.apply(objActual,arguments); //the fix i have added
    this.ActualTest = function() {
        alert("ActualTest");
        };
  }

In the above code, var closeHandler is created in the context of ClosureTest(), but it holds the handler of the ActualMethod.doSomething. Whenever calling the closeHandler() ended up in "object doesnt support this method" error.

This is because doSomething() function calls another method inside called this.testMethod();. Here this refers to the context of the caller not callee.so i assume the closeHandler is bound to the environment(ClosureTest) actually created.Even though it holds the handler to the another context, it just exposes the properties of its own context.

Solution

To avoid this i suggest to use apply to specify the conext in which it needs to execute.

closeHandler.apply(objActual,arguments);

Questions

is it perfect scenario for closures..??

What are the intersting places you have encountered closures in javascript..?

UPDATE

Yes its simple i can call the method directly. but the problem is, in a particular scenario I need to intercept the call to actuall method and run some code before that, finally execute the actual method..

say for an example, am using 3rd party aspx grid library, and all the mouseclick events are trapped by their controls. In particular group by mouse click i need to intercept the call to their ilbrary method and hook my mthod to execute instead and redirect the call to actual library method

hope this helps

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

下雨或天晴 2024-08-24 15:53:07

更新:因为您可能在代码中遗漏了一些细节,所以很难在不遗漏实际代码要点的情况下将其调整为可行的内容。我确实认为我理解您所描述的根本问题。我希望以下内容有所帮助。

假设下面这个简单的例子:

// Constructor function.
function Example() {
    // Method:
    this.method = function() {
        alert("original method");
    }
}

// You would use it like this:
var obj = new Example();
obj.method(); // Calls original method.

要拦截这样的方法调用,你可以这样做:

function wrap(obj) {
    var originalMethod = obj.method;
    obj.method = function() {
        alert("intercepted call");
        originalMethod.apply(this, arguments);
    }
    return obj;
}

var obj = wrap(new Example());
obj.method(); // Calls wrapped method.

不幸的是,因为 method() 是在构造函数中定义的,而不是在原型上,所以你需要有一个对象实例来包裹物体。


原始问题的答案: doSomething() 函数用作使用 ActualMethod() 创建的对象的方法。您应该将其用作方法,而不是将其分离并在不同的上下文中将其用作函数。为什么不直接调用方法呢?

function ClosureTest(){
    var objActual = new ActualMethod();
    // Call method directly, avoid messy apply() calls.
    objActual.doSomething();
    this.ActualTest = function() {
        alert("ActualTest");
    };
}

如果您将一个方法(某个对象上的函数)分配给 Javascript 中的局部变量并调用它,上下文将会不同(this 的值会发生变化)。如果你不想让它发生,就不要这样做。

Update: Because you probably left out some details in your code, it is difficult to adapt it into something workable without missing the point of your actual code. I do think I understand your underlying problem as you describe it. I hope the following helps.

Suppose the following simple example:

// Constructor function.
function Example() {
    // Method:
    this.method = function() {
        alert("original method");
    }
}

// You would use it like this:
var obj = new Example();
obj.method(); // Calls original method.

To intercept such a method call, you can do this:

function wrap(obj) {
    var originalMethod = obj.method;
    obj.method = function() {
        alert("intercepted call");
        originalMethod.apply(this, arguments);
    }
    return obj;
}

var obj = wrap(new Example());
obj.method(); // Calls wrapped method.

Unfortunately, because method() is defined in the constructor function, not on a prototype, you need to have an object instance to wrap the object.


Answer to original question: The doSomething() function is used as a method on objects created with ActualMethod(). You should use it as a method, not detach it and use it as a function in a different context. Why don't you just call the method directly?

function ClosureTest(){
    var objActual = new ActualMethod();
    // Call method directly, avoid messy apply() calls.
    objActual.doSomething();
    this.ActualTest = function() {
        alert("ActualTest");
    };
}

If you assign a method (a function on some object) to a local variable in Javascript and call it, the context will be different (the value of this changes). If you don't want it to happen, don't do it.

划一舟意中人 2024-08-24 15:53:07

当我想要挂钩一个函数时,我使用以下 Function 方法,这也是闭包演示的一个很好的部分:

Function.prototype.wrap = function (wrapper) {
 var __method = this;
 return function() {
  var __obj = this;
  var args = [ __method.bind(__obj) ];
  for(var i=0; i<arguments.length; i++) args.push(arguments[i]);
  return wrapper.apply(__obj, args);
 }
};

然后执行类似以下操作:

ActualMethod = ActualMethod.wrap(function (proceed, option) {
  // ... handle option
  proceed(); // calls the wrapped function
});

proceed 绑定到其初始对象,因此您可以安全地调用它。

When I want to hook a function, I use the following Function method which is also a fine piece of Closure demonstration:

Function.prototype.wrap = function (wrapper) {
 var __method = this;
 return function() {
  var __obj = this;
  var args = [ __method.bind(__obj) ];
  for(var i=0; i<arguments.length; i++) args.push(arguments[i]);
  return wrapper.apply(__obj, args);
 }
};

Then do something like:

ActualMethod = ActualMethod.wrap(function (proceed, option) {
  // ... handle option
  proceed(); // calls the wrapped function
});

proceed is bound to its initial object, so you can safely call it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文