命名空间、“this”和库的 javascript 问题

Posted

技术标签:

【中文标题】命名空间、“this”和库的 javascript 问题【英文标题】:javascript issue with namespace, "this" and a library 【发布时间】:2014-03-09 09:20:53 【问题描述】:

我正在构建一个可视化页面(使用dc.js),我决定为此进行跳转并将其全部收集到一个命名空间中。由于 Python 的简单性,与 javascript 的疯狂作用域相冲突已经够难的了,所以请多多包涵。

我有一个通用的JS结构如下:

var NamespaceClass = function() 

    this.var0 = "something";
    this.var1 = dc.SomeChartClass("#some-css-selector");

    this.setup = function(error, config, dataset) 
        console.log("Inside setup:", this);
        this.var2 = this.process_data(dataset);
        // Do some more stuff...
    

    this.process_data = function(data) 
        var whatever;
        //Do stuff with "data"...
        return whatever;
    

    this.start = function() 
        console.log("Inside start:", this);
        var q;

        q = queue().defer(d3.json, "config.json")
                   .defer(d3.csv, "data.csv");
        q.await(this.setup);
    


var MyNamespace = new NamespaceClass();
MyNamespace.start();

其中queue 是Mike Bostock's queue lib,用于异步文件排队。当我尝试测试脚本时,我进入了控制台:

Inside start: Object  var0 = "something", var1=..., more...
Inside setup: Window testpage.html
TypeError: this.process_data is not a function

因此,从q.await 调用setup 会使其失去对象的作用域(或在JavaScript 中调用的任何东西......)。我怎样才能避免这种情况?我也尝试过使用代理对象,例如:

    this.start = function() 
        console.log("Inside start:", this);
        var q, proxy;

        q = queue().defer(d3.json, "config.json")
                   .defer(d3.csv, "data.csv");
        proxy = this.setup;
        q.await(proxy);
    

无济于事!

【问题讨论】:

这和你的问题无关,但是没有必要创建一个类来拥有命名空间。一个简单的对象就可以了,您可以使用 IIFE 对其进行初始化,以使所有变量都具有范围,这样它们就不会污染全局范围。 这是迄今为止唯一允许我执行类间方法调用的方法(如this.fun1 调用this.fun2)。但是每次都使用this. 相当乏味。你愿意指出一些你所建议的例子吗? 这个answer 有一个例子。 我尝试过这种方式,但它不允许我让类函数(方法)自己调用其他方法。 【参考方案1】:

this 的值取决于你如何调用包含它的函数。您无法控制如何调用 setup 函数,因为它是在 q.await 函数内部调用的。

当您执行q.await(this.setup) 时,您传递了对函数设置的引用,但“丢失”了与您的命名空间的任何连接。您需要将函数绑定到命名空间以使其具有正确的this 值:

q.await(this.setup.bind(this));

更好的是,由于您的所有函数只有在 this 是命名空间时才能工作,所以您应该像这样将它们绑定到命名空间:

this.start = function() 
  // body
.bind(this);

// usage:
q.await(this.setup);

现在无论你经过它们,它们的内部都会有正确的this

注意:在这种情况下,bind 的工作方式如下:

this.start = function() 
    var namespace = this;

    q.await(function() namespace.setup(); );

【讨论】:

以上是关于命名空间、“this”和库的 javascript 问题的主要内容,如果未能解决你的问题,请参考以下文章

在代码点火器中调用帮助程序和库的方法有区别吗?

为啥将 javascript 命名空间作为一个函数?

Javascript使用函数做命名空间

JavaScript 命名空间和 jQuery 事件处理程序

error C2825: '_Iter': 当后面跟“::”时必须为类或命名空间 -- 原因可能是参数错误或者自定义函数名和库函数名冲突

31款轻量高效的开源JavaScript插件和库