【问题标题】:Javascript this scoping problemJavascript这个范围问题
【发布时间】:2011-06-08 23:21:29
【问题描述】:

我正在加载一个 csv 文件并对其进行解析。我希望得到的数组是某个对象的成员,但它最终是未定义的,因为我没有正确使用“this”关键字。

function SimPlayer(){

    this.dataset = new Array();
    var client = new XMLHttpRequest();
    var dset = this.dataset;

    function handler(){
        if(client.readyState == 4){
            if(client.status == 200){
                //file is done loading
                //split by lines
                dset = client.responseText.split("\n");
                for(var i=0; i<dset.length; i++){
                    //split each line by commas
                    dset[i] = dset[i].split(",");
                    //convert to ints
                    for(var j=0; j<dset[i].length; j++){
                        dset[i][j] = parseInt(dset[i][j]);
                    }
                }
                //dset is defined here, no problem. It contains the data from the csv file
                console.log(dset[0]);
            }
        }
    }
    client.onreadystatechange = handler;
    client.open("GET", "http://nathannifong.com/LayerCake/simdata/rec0_i0.csv");
    client.send();

    this.check = function(){
        //does not work because this.dataset will be empty.
        console.log(this.dataset[0])
    }
}

假设我创建了一个 SimPlayer 实例,然后稍后调用 check(在 csv 文件有时间加载之后)

foo = new SimPlayer();
//....time passes....
foo.check();

foo.check() 原因

Uncaught TypeError: Cannot read property '0' of undefined

如何修复我的代码,以便在 check() 中,this.dataset 将包含 csv 文件中的数据?

【问题讨论】:

  • 您在代码中的哪个位置为实际的 dataset 数组设置了任何内容?
  • 另外,您可能会发现my answer to another question about prototypes 很有用。
  • 为什么不在加载时将 dset 分配给 this.dataset,而不是之前?
  • 如果我在 handler() 中引用 this.dataset,它不存在,因为在处理程序中,this 是指客户端
  • foo = new SimPlayer(); 后面不能跟 foo.check(),因为你需要一些时间来做 AJAX,A 代表“异步”。

标签: javascript scope closures this


【解决方案1】:

您需要存储对正确 this 绑定的引用:

var _this = this;
this.check = function(){
    //does not work because this.dataset will be empty.
    console.log(_this.dataset[0])
}

【讨论】:

  • 这就是我试图做的: var client = new XMLHttpRequest(); var dset = this.dataset;因为我最初在处理程序中将 MLHttpRequest 实例作为 t​​his 引用,并将 SimPlayer 实例作为 SimPlayer 中的 this 引用。我不能同时引用两者,所以我尝试保存正确的绑定。我做错了吗?
  • 已解决。我做错了。应该这样做: var sim = this;函数 handler(){ sim.dataset } 而不是: var dset = this.dataset;函数处理程序(){ dset }
  • 嗯,由于foo.check() 调用将其设置为foo,因此此处已正确绑定。问题确实是dset 不是this.dataset 的引用,因此处理程序内部的赋值只会改变 dset 的值 :)
  • 太棒了。这与我在使用非常相似的东西时遇到的完全相同的问题。是否有任何文档或页面可以查看有关此范围如何工作的更多详细信息?
【解决方案2】:

作为替代选项,您可以考虑以下示例:

this.check = (function(thus){
    return function() {//does not work because this.dataset will be empty.
       console.log(thus.dataset[0])
    };
})(this);

PS:我还没有完全阅读原始帖子,我的例子 - 只是答案的另一种方式。您可以在许多 JavaScript 示例中找到此类代码。您应该了解使用闭包。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-04-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-17
    • 2014-10-24
    • 1970-01-01
    相关资源
    最近更新 更多