Javascript 回调的范围问题

发布于 2024-09-05 03:00:23 字数 802 浏览 7 评论 0原文

我在使回调函数正常工作时遇到一些问题。这是我的代码:

SomeObject.prototype.refreshData = function()
{
  var read_obj = new SomeAjaxCall("read_some_data", { }, this.readSuccess, this.readFail);
}

SomeObject.prototype.readSuccess = function(response)
{
    this.data = response;
    this.someList = [];
    for (var i = 0; i < this.data.length; i++)
    {
      var systemData = this.data[i];
      var system = new SomeSystem(systemData);
      this.someList.push(system);
    }
    this.refreshList();
}

基本上 SomeAjaxCall 正在发出 ajax 数据请求。如果成功,我们使用回调“this.readSuccess”,如果失败,则使用“this.readFail”。

我发现 SomeObject.readSuccess 中的“this”是全局 this(又名窗口对象),因为我的回调被作为函数而不是成员方法调用。我的理解是,我需要使用闭包来保留“this”,但是,我无法让它发挥作用。

如果有人能够告诉我我应该做什么,我将不胜感激。我仍然在思考闭包是如何工作的,特别是在这种情况下它们将如何工作。

谢谢!

I am having some trouble getting a callback function to work. Here is my code:

SomeObject.prototype.refreshData = function()
{
  var read_obj = new SomeAjaxCall("read_some_data", { }, this.readSuccess, this.readFail);
}

SomeObject.prototype.readSuccess = function(response)
{
    this.data = response;
    this.someList = [];
    for (var i = 0; i < this.data.length; i++)
    {
      var systemData = this.data[i];
      var system = new SomeSystem(systemData);
      this.someList.push(system);
    }
    this.refreshList();
}

Basically SomeAjaxCall is making an ajax request for data. If it works we use the callback 'this.readSuccess' and if it fails 'this.readFail'.

I have figured out that 'this' in the SomeObject.readSuccess is the global this (aka the window object) because my callbacks are being called as functions and not member methods. My understanding is that I need to use closures to keep the 'this' around, however, I have not been able to get this to work.

If someone is able show me what I should be doing I would appreciate it greatly. I am still wrapping my head around how closures work and specifically how they would work in this situation.

Thanks!

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

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

发布评论

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

评论(3

木森分化 2024-09-12 03:00:23

最简单的做法就是将“this.readSuccess”包装在另一个函数中:

SomeObject.prototype.refreshData = function()
{
  var obj = this;
  var read_obj = new SomeAjaxCall("read_some_data", { }, 
    function() { obj.readSuccess(); }, function() { obj.readFail(); });
}

一些 Javascript 框架提供了一个实用程序来将函数“绑定”到对象,这意味着它会为您创建其中一个小函数。请注意,变量“obj”将被这些小函数“记住”,因此当调用处理程序时,“this”引用将指向用于调用“refreshData”的对象。

Well the most straightforward thing to do is to just wrap "this.readSuccess" in another function:

SomeObject.prototype.refreshData = function()
{
  var obj = this;
  var read_obj = new SomeAjaxCall("read_some_data", { }, 
    function() { obj.readSuccess(); }, function() { obj.readFail(); });
}

Some Javascript frameworks provide a utility to "bind" a function to an object, which simply means that it creates one of those little functions for you. Note that the variable "obj" will be "remembered" by those little functions, so when your handlers are called the "this" reference will be to the object that was used to call "refreshData".

空‖城人不在 2024-09-12 03:00:23

您这里的问题不完全是闭包或范围界定问题。问题在于,当您将 this.readSuccess 分配给变量时,您分配了函数本身,而没有任何其原始所属对象的概念。

以同样的方式,您可以采用常规的“独立”函数并将其用作对象的方法:

function hello() {
    alert("Hello "+this.planet);
}
var planet = "Earth";
hello(); // -> 'Hello Earth'

var Venus = {
    planet: "Venus"
};
hello.apply(Venus); // -> 'Hello Venus'
Venus.hello = hello;
Venus.hello(); // -> 'Hello Venus'

并且您的问题可以在本示例中复制

var helloVenus = Venus.hello;
helloVenus(); // -> 'Hello Earth'

所以您的问题是将 this.readSuccess 分配给某个变量 并将其作为 this 的方法调用。这可以通过 Pointy 演示的闭包来完成。由于我不知道“SomeAjaxCall”实际上做了什么,因此很难知道 this 的值是否实际上丢失以及 var obj = this 是否确实需要。很可能不是,所以您可以使用这种代码:

var helloVenus = function() { Venus.hello() }
helloVenus(); // -> 'Hello Venus'

在您的情况下,这将是(编辑:添加传递给处理程序的参数):

SomeObject.prototype.refreshData = function()
{
  var read_obj = new SomeAjaxCall(
    "read_some_data",
    { },
    function () { this.readSuccess.apply(this, arguments) },
    function () { this.readFail.apply(this, arguments) }
  );
}

如前所述,几个 js 框架提供一个bind 函数来简化此类问题。但您并不需要为此建立一个完整的框架:这里有一个完美的 Function#bind 方法,可以使用普通的 javascript 运行:

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

Function#bind 的帮助下,你可以写:

SomeObject.prototype.refreshData = function()
{
  var read_obj = new SomeAjaxCall(
    "read_some_data",
    { },
    this.readSuccess.bind(this),
    this.readFail.bind(this)
  );
}

Your problem here is not exactly a closure or scoping problem. The problem is that when you assign this.readSuccess to a variable, you assign the function itself without any notion of the object it originaly belongs to.

In the same way, you can take a regular, "stand-alone" function and use it as method of an object:

function hello() {
    alert("Hello "+this.planet);
}
var planet = "Earth";
hello(); // -> 'Hello Earth'

var Venus = {
    planet: "Venus"
};
hello.apply(Venus); // -> 'Hello Venus'
Venus.hello = hello;
Venus.hello(); // -> 'Hello Venus'

And your problem can be replicated in this example

var helloVenus = Venus.hello;
helloVenus(); // -> 'Hello Earth'

So your problem is to assign this.readSuccess to some variable and having it called as a method of this. Which can be done with a closure as demonstrated by Pointy. Since I don't know what "SomeAjaxCall" actually does, it's hard to know if the value of this is actually lost and if var obj = this is actually needed. Chances are that it's not, so you can be fine with this kind of code:

var helloVenus = function() { Venus.hello() }
helloVenus(); // -> 'Hello Venus'

In your case, that would be (edit: adding the arguments passed to the handler) :

SomeObject.prototype.refreshData = function()
{
  var read_obj = new SomeAjaxCall(
    "read_some_data",
    { },
    function () { this.readSuccess.apply(this, arguments) },
    function () { this.readFail.apply(this, arguments) }
  );
}

As noted previously, several js frameworks offer a bind function to simplify this kind of issue. But you don't need a complete framework just for this : here is a perfectly fine Function#bind method that works an plain javascript:

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

With the help of Function#bind, you can write:

SomeObject.prototype.refreshData = function()
{
  var read_obj = new SomeAjaxCall(
    "read_some_data",
    { },
    this.readSuccess.bind(this),
    this.readFail.bind(this)
  );
}
你另情深 2024-09-12 03:00:23

以下站点似乎表明问题可能更多地出在您的“类”建筑中,而不是使用中。如果您仔细阅读“使用原型属性重写”,他们会写到“类”结构的特定方法将使方法保持全局而不是基于实例。也许另一种创作方法?

http://devedge-temp.mozilla.org/viewsource/2001/oop -javascript/

The following site seems to suggest that the problem may be more in your "class" building than in the usage. If you read down to the "rewrite using prototype properties", they write that that particular method of "class" structuring will keep the methods global instead of instance-based. Perhaps another creation method?

http://devedge-temp.mozilla.org/viewsource/2001/oop-javascript/

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