Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/438.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 使用IIFE方法,将变量从一个文件传递到另一个文件_Javascript_D3.js - Fatal编程技术网

Javascript 使用IIFE方法,将变量从一个文件传递到另一个文件

Javascript 使用IIFE方法,将变量从一个文件传递到另一个文件,javascript,d3.js,Javascript,D3.js,问题之一是如何在多个.js文件之间组织代码。 现在我有一个问题 我在d3.js中有一张按国家划分的地图。当用户双击一个国家时,我想将一个变量传递给另一个js文件 这是我的html文件,index.hbs: <html lang='en'> <head> <meta charset='utf-8'> <script src='https://d3js.org/d3.v5.js' charset='utf-8'>

问题之一是如何在多个.js文件之间组织代码。 现在我有一个问题

我在d3.js中有一张按国家划分的地图。当用户双击一个国家时,我想将一个变量传递给另一个js文件

这是我的html文件,index.hbs

<html lang='en'>
    <head>
        <meta charset='utf-8'>
        <script src='https://d3js.org/d3.v5.js' charset='utf-8'></script>
        <script src='https://d3js.org/topojson.v2.min.js'></script>
        <script src='https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js'></script>

        <link href='/css/all.css' rel='stylesheet'/>
    </head>

    <body>
        <div id='map'></div>

        <script> 
            var viewData = {};  
            viewData.nuts0 = JSON.parse('{{json nuts0}}'.replace(/&quot;/g, '"').replace(/&lt;/, ''));
            viewData.CONFIG = JSON.parse('{{json CONFIG}}'.replace(/&quot;/g, '"').replace(/&lt;/, '')); 
        </script>

        <script src='/script/map.js' rel='script'/><{{!}}/script>
        <script src='/script/other.js' rel='script'/><{{!}}/script>
    </body>
</html>
var NAME=(function map() {

    var my = {};

    var CONFIG = viewData.CONFIG;
    var nuts0 = viewData.nuts0;

    // paths
    var countries;

    // width and height of svg map container
    var width = CONFIG.bubbleMap.width;
    var height = CONFIG.bubbleMap.height;

    // to check if user clicks or double click
    var dblclick_timer = false;

    // create Hammer projection
    var projectionCurrent = d3.geoHammer() 
        .scale(1) 
        .translate([width/2, height/2]); 

    var projectionBase = d3.geoHammer()
        .scale(1) 
        .translate([width/2, height/2]);

    // creates a new geographic path generator with the default settings. If projection is specified, sets the current projection
    var path = d3.geoPath().projection(projectionCurrent);

    // creates the svg element that contains the map
    var map = d3.select('#map');

    var mapSvg = map.append('svg')
        .attr('id', 'map-svg')
        .attr('width', width)
        .attr('height', height);

    var mapSvgGCountry = mapSvg.append('g').attr('id', 'nuts0');

    countries = topojson.feature(nuts0, nuts0.objects.nuts0);
    projectionCurrent.fitSize([width, height], countries);

    var mapSvgGCountryPath = mapSvgGCountry.selectAll('path')
        .data(countries.features)
        .enter()
        .append('path');

    mapSvgGCountryPath.attr('class', 'country')
        .attr('fill', 'tomato')
        .style('stroke', 'white')
        .style('stroke-width', 1) 
        .attr('d', path)
        .attr('id', function(c) {
            return 'country' + c.properties.nuts_id;
        })
        .on('click', clickOrDoubleCountry);

    function clickOrDoubleCountry(d, i) {
        if(dblclick_timer) { // double click
            clearTimeout(dblclick_timer);
            dblclick_timer = false;
            my.countryDoubleClicked = d.country; // <-- variable to pass
        }
        else { // single click
            dblclick_timer = setTimeout(function() {
                dblclick_timer = false;
            }, 250)
        } 
    } 

    return my;

}());
(function other(NAME) {
    console.log('my:', NAME.my); // undefined
    console.log('my:', NAME.countryDoubleClicked); // undefined
})(NAME);
var NAME = (function map() {
    var my = {};
    //...
    return my;
}());
var NAME=(function map() {

    var my = {};

    var CONFIG = viewData.CONFIG;
    var nuts0 = viewData.nuts0;

    // paths
    var countries;

    // width and height of svg map container
    var width = CONFIG.bubbleMap.width;
    var height = CONFIG.bubbleMap.height;

    // to check if user clicks or double click
    var dblclick_timer = false;

    // create Hammer projection
    var projectionCurrent = d3.geoHammer() 
        .scale(1) 
        .translate([width/2, height/2]); 

    var projectionBase = d3.geoHammer()
        .scale(1) 
        .translate([width/2, height/2]);

    // creates a new geographic path generator with the default settings. If projection is specified, sets the current projection
    var path = d3.geoPath().projection(projectionCurrent);

    // creates the svg element that contains the map
    var map = d3.select('#map');

    var mapSvg = map.append('svg')
        .attr('id', 'map-svg')
        .attr('width', width)
        .attr('height', height);

    var mapSvgGCountry = mapSvg.append('g').attr('id', 'nuts0');

    countries = topojson.feature(nuts0, nuts0.objects.nuts0);
    projectionCurrent.fitSize([width, height], countries);

    var mapSvgGCountryPath = mapSvgGCountry.selectAll('path')
        .data(countries.features)
        .enter()
        .append('path');

    mapSvgGCountryPath.attr('class', 'country')
        .attr('fill', 'tomato')
        .style('stroke', 'white')
        .style('stroke-width', 1) 
        .attr('d', path)
        .attr('id', function(c) {
            return 'country' + c.properties.nuts_id;
        })
        .on('click', clickOrDoubleCountry);

    function clickOrDoubleCountry(d, i) {
        if(dblclick_timer) { // double click
            clearTimeout(dblclick_timer);
            dblclick_timer = false;
            my.countryDoubleClicked = d.country; // <-- variable to pass
            if (my.doubleClickHandler) {
                my.doubleClickHandler(d.country);
            }
        }
        else { // single click
            dblclick_timer = setTimeout(function() {
                dblclick_timer = false;
            }, 250)
        } 
    } 

    return {
        my: my
    };

}());
我希望能够在
other.js
文件中读取在
map.js
中创建的my对象,然后能够从
other.js
访问
my.countryDoubleClicked
变量


此代码不工作,我得到
TypeError:NAME.my未定义

您需要设置显式字段。。。例如:

let x = (function(){
    let obj = {}; // the "namespace"
    let private_var = 0;
    function foo() {
        return private_var++; // Access private vars freely
    };
    obj.foo = foo; // "publish" the function
    console.log(foo()); // you can use unqualified foo here
    return obj;
})();

// outputs 0 from the console log call inside the "constructor"

console.log(x.private_var); // undefined, it's not published
console.log(x.foo()); // outputs 1, the function was published
console.log(x.foo()); // 2
console.log(x.foo()); // 3

Javascript函数的局部变量或局部函数不会隐式发布到任何地方。如果要访问它们,则需要设置一个对象字段。

有几件事正在进行:

揭示变量 首先,您没有在map.js中显示
my
变量作为
NAME.my

<html lang='en'>
    <head>
        <meta charset='utf-8'>
        <script src='https://d3js.org/d3.v5.js' charset='utf-8'></script>
        <script src='https://d3js.org/topojson.v2.min.js'></script>
        <script src='https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js'></script>

        <link href='/css/all.css' rel='stylesheet'/>
    </head>

    <body>
        <div id='map'></div>

        <script> 
            var viewData = {};  
            viewData.nuts0 = JSON.parse('{{json nuts0}}'.replace(/&quot;/g, '"').replace(/&lt;/, ''));
            viewData.CONFIG = JSON.parse('{{json CONFIG}}'.replace(/&quot;/g, '"').replace(/&lt;/, '')); 
        </script>

        <script src='/script/map.js' rel='script'/><{{!}}/script>
        <script src='/script/other.js' rel='script'/><{{!}}/script>
    </body>
</html>
var NAME=(function map() {

    var my = {};

    var CONFIG = viewData.CONFIG;
    var nuts0 = viewData.nuts0;

    // paths
    var countries;

    // width and height of svg map container
    var width = CONFIG.bubbleMap.width;
    var height = CONFIG.bubbleMap.height;

    // to check if user clicks or double click
    var dblclick_timer = false;

    // create Hammer projection
    var projectionCurrent = d3.geoHammer() 
        .scale(1) 
        .translate([width/2, height/2]); 

    var projectionBase = d3.geoHammer()
        .scale(1) 
        .translate([width/2, height/2]);

    // creates a new geographic path generator with the default settings. If projection is specified, sets the current projection
    var path = d3.geoPath().projection(projectionCurrent);

    // creates the svg element that contains the map
    var map = d3.select('#map');

    var mapSvg = map.append('svg')
        .attr('id', 'map-svg')
        .attr('width', width)
        .attr('height', height);

    var mapSvgGCountry = mapSvg.append('g').attr('id', 'nuts0');

    countries = topojson.feature(nuts0, nuts0.objects.nuts0);
    projectionCurrent.fitSize([width, height], countries);

    var mapSvgGCountryPath = mapSvgGCountry.selectAll('path')
        .data(countries.features)
        .enter()
        .append('path');

    mapSvgGCountryPath.attr('class', 'country')
        .attr('fill', 'tomato')
        .style('stroke', 'white')
        .style('stroke-width', 1) 
        .attr('d', path)
        .attr('id', function(c) {
            return 'country' + c.properties.nuts_id;
        })
        .on('click', clickOrDoubleCountry);

    function clickOrDoubleCountry(d, i) {
        if(dblclick_timer) { // double click
            clearTimeout(dblclick_timer);
            dblclick_timer = false;
            my.countryDoubleClicked = d.country; // <-- variable to pass
        }
        else { // single click
            dblclick_timer = setTimeout(function() {
                dblclick_timer = false;
            }, 250)
        } 
    } 

    return my;

}());
(function other(NAME) {
    console.log('my:', NAME.my); // undefined
    console.log('my:', NAME.countryDoubleClicked); // undefined
})(NAME);
var NAME = (function map() {
    var my = {};
    //...
    return my;
}());
var NAME=(function map() {

    var my = {};

    var CONFIG = viewData.CONFIG;
    var nuts0 = viewData.nuts0;

    // paths
    var countries;

    // width and height of svg map container
    var width = CONFIG.bubbleMap.width;
    var height = CONFIG.bubbleMap.height;

    // to check if user clicks or double click
    var dblclick_timer = false;

    // create Hammer projection
    var projectionCurrent = d3.geoHammer() 
        .scale(1) 
        .translate([width/2, height/2]); 

    var projectionBase = d3.geoHammer()
        .scale(1) 
        .translate([width/2, height/2]);

    // creates a new geographic path generator with the default settings. If projection is specified, sets the current projection
    var path = d3.geoPath().projection(projectionCurrent);

    // creates the svg element that contains the map
    var map = d3.select('#map');

    var mapSvg = map.append('svg')
        .attr('id', 'map-svg')
        .attr('width', width)
        .attr('height', height);

    var mapSvgGCountry = mapSvg.append('g').attr('id', 'nuts0');

    countries = topojson.feature(nuts0, nuts0.objects.nuts0);
    projectionCurrent.fitSize([width, height], countries);

    var mapSvgGCountryPath = mapSvgGCountry.selectAll('path')
        .data(countries.features)
        .enter()
        .append('path');

    mapSvgGCountryPath.attr('class', 'country')
        .attr('fill', 'tomato')
        .style('stroke', 'white')
        .style('stroke-width', 1) 
        .attr('d', path)
        .attr('id', function(c) {
            return 'country' + c.properties.nuts_id;
        })
        .on('click', clickOrDoubleCountry);

    function clickOrDoubleCountry(d, i) {
        if(dblclick_timer) { // double click
            clearTimeout(dblclick_timer);
            dblclick_timer = false;
            my.countryDoubleClicked = d.country; // <-- variable to pass
            if (my.doubleClickHandler) {
                my.doubleClickHandler(d.country);
            }
        }
        else { // single click
            dblclick_timer = setTimeout(function() {
                dblclick_timer = false;
            }, 250)
        } 
    } 

    return {
        my: my
    };

}());
这会将
NAME
设置为
my
,而不是将
NAME.my
设置为
my
。如果您确实想这样做,您可以这样做:

var NAME = (function map() {
    var my = {};
    //...
    return {
      my: my
    };
}());
您可以从以下文章中了解更多有关此技术的信息,称为“显示模块模式”:

以后使用函数运行代码 其次,正如其他人所提到的,正如您所意识到的,由于
other.js
中的代码会立即运行,因此它会在用户有机会点击某个国家之前运行该代码。相反,您希望代码能够按需运行(在这种情况下,当用户双击某个对象时)。在JavaScript中,这通常是通过分配或传递函数来完成的。为简单起见,我们可以将某些内容分配给
my.doubleClickHandler
,然后在
clickOrDoubleCountry
中调用该函数。为此,除了将country指定给
NAME.my.countryDoubleClicked
,我还将country作为一个参数传递给处理程序,但您可能只需要使用其中一个参数

function clickOrDoubleCountry(d, i) {
    if(dblclick_timer) { // double click
        clearTimeout(dblclick_timer);
        dblclick_timer = false;
        my.countryDoubleClicked = d.country; // <-- variable to pass
        if (my.doubleClickHandler) {
            my.doubleClickHandler(d.country);
        }
    }
    // ...
} 
因此,除了上面修改的other.js之外,这是完全修改的map.js

<html lang='en'>
    <head>
        <meta charset='utf-8'>
        <script src='https://d3js.org/d3.v5.js' charset='utf-8'></script>
        <script src='https://d3js.org/topojson.v2.min.js'></script>
        <script src='https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js'></script>

        <link href='/css/all.css' rel='stylesheet'/>
    </head>

    <body>
        <div id='map'></div>

        <script> 
            var viewData = {};  
            viewData.nuts0 = JSON.parse('{{json nuts0}}'.replace(/&quot;/g, '"').replace(/&lt;/, ''));
            viewData.CONFIG = JSON.parse('{{json CONFIG}}'.replace(/&quot;/g, '"').replace(/&lt;/, '')); 
        </script>

        <script src='/script/map.js' rel='script'/><{{!}}/script>
        <script src='/script/other.js' rel='script'/><{{!}}/script>
    </body>
</html>
var NAME=(function map() {

    var my = {};

    var CONFIG = viewData.CONFIG;
    var nuts0 = viewData.nuts0;

    // paths
    var countries;

    // width and height of svg map container
    var width = CONFIG.bubbleMap.width;
    var height = CONFIG.bubbleMap.height;

    // to check if user clicks or double click
    var dblclick_timer = false;

    // create Hammer projection
    var projectionCurrent = d3.geoHammer() 
        .scale(1) 
        .translate([width/2, height/2]); 

    var projectionBase = d3.geoHammer()
        .scale(1) 
        .translate([width/2, height/2]);

    // creates a new geographic path generator with the default settings. If projection is specified, sets the current projection
    var path = d3.geoPath().projection(projectionCurrent);

    // creates the svg element that contains the map
    var map = d3.select('#map');

    var mapSvg = map.append('svg')
        .attr('id', 'map-svg')
        .attr('width', width)
        .attr('height', height);

    var mapSvgGCountry = mapSvg.append('g').attr('id', 'nuts0');

    countries = topojson.feature(nuts0, nuts0.objects.nuts0);
    projectionCurrent.fitSize([width, height], countries);

    var mapSvgGCountryPath = mapSvgGCountry.selectAll('path')
        .data(countries.features)
        .enter()
        .append('path');

    mapSvgGCountryPath.attr('class', 'country')
        .attr('fill', 'tomato')
        .style('stroke', 'white')
        .style('stroke-width', 1) 
        .attr('d', path)
        .attr('id', function(c) {
            return 'country' + c.properties.nuts_id;
        })
        .on('click', clickOrDoubleCountry);

    function clickOrDoubleCountry(d, i) {
        if(dblclick_timer) { // double click
            clearTimeout(dblclick_timer);
            dblclick_timer = false;
            my.countryDoubleClicked = d.country; // <-- variable to pass
        }
        else { // single click
            dblclick_timer = setTimeout(function() {
                dblclick_timer = false;
            }, 250)
        } 
    } 

    return my;

}());
(function other(NAME) {
    console.log('my:', NAME.my); // undefined
    console.log('my:', NAME.countryDoubleClicked); // undefined
})(NAME);
var NAME = (function map() {
    var my = {};
    //...
    return my;
}());
var NAME=(function map() {

    var my = {};

    var CONFIG = viewData.CONFIG;
    var nuts0 = viewData.nuts0;

    // paths
    var countries;

    // width and height of svg map container
    var width = CONFIG.bubbleMap.width;
    var height = CONFIG.bubbleMap.height;

    // to check if user clicks or double click
    var dblclick_timer = false;

    // create Hammer projection
    var projectionCurrent = d3.geoHammer() 
        .scale(1) 
        .translate([width/2, height/2]); 

    var projectionBase = d3.geoHammer()
        .scale(1) 
        .translate([width/2, height/2]);

    // creates a new geographic path generator with the default settings. If projection is specified, sets the current projection
    var path = d3.geoPath().projection(projectionCurrent);

    // creates the svg element that contains the map
    var map = d3.select('#map');

    var mapSvg = map.append('svg')
        .attr('id', 'map-svg')
        .attr('width', width)
        .attr('height', height);

    var mapSvgGCountry = mapSvg.append('g').attr('id', 'nuts0');

    countries = topojson.feature(nuts0, nuts0.objects.nuts0);
    projectionCurrent.fitSize([width, height], countries);

    var mapSvgGCountryPath = mapSvgGCountry.selectAll('path')
        .data(countries.features)
        .enter()
        .append('path');

    mapSvgGCountryPath.attr('class', 'country')
        .attr('fill', 'tomato')
        .style('stroke', 'white')
        .style('stroke-width', 1) 
        .attr('d', path)
        .attr('id', function(c) {
            return 'country' + c.properties.nuts_id;
        })
        .on('click', clickOrDoubleCountry);

    function clickOrDoubleCountry(d, i) {
        if(dblclick_timer) { // double click
            clearTimeout(dblclick_timer);
            dblclick_timer = false;
            my.countryDoubleClicked = d.country; // <-- variable to pass
            if (my.doubleClickHandler) {
                my.doubleClickHandler(d.country);
            }
        }
        else { // single click
            dblclick_timer = setTimeout(function() {
                dblclick_timer = false;
            }, 250)
        } 
    } 

    return {
        my: my
    };

}());
var NAME=(函数映射(){
var my={};
var CONFIG=viewData.CONFIG;
var nuts0=viewData.nuts0;
//路径
var国家;
//svg地图容器的宽度和高度
var width=CONFIG.bubbleMap.width;
var height=CONFIG.bubbleMap.height;
//检查用户是否单击或双击
var dblclick_timer=false;
//创建锤子投影
var projectionCurrent=d3.geoHammer()
.比额表(1)
.翻译([宽度/2,高度/2]);
var projectionBase=d3.geoHammer()
.比额表(1)
.翻译([宽度/2,高度/2]);
//使用默认设置创建新的地理路径生成器。如果指定了投影,则设置当前投影
var path=d3.geoPath().projection(projectionCurrent);
//创建包含地图的svg元素
var map=d3。选择(“#map”);
var mapssvg=map.append('svg')
.attr('id','map svg')
.attr('width',width)
.attr('高度'),高度;
var mapSvgGCountry=mapSvg.append('g').attr('id','nuts0');
countries=topojson.feature(nuts0,nuts0.objects.nuts0);
projectionCurrent.fitSize([宽度,高度],国家/地区);
var mapSvgGCountryPath=mapSvgGCountry.selectAll('path'))
.数据(国家/地区.特征)
.输入()
.append('path');
mapSvgGCountryPath.attr('class','country')
.attr('填充','番茄')
.style('笔划','白色')
.style('笔划宽度',1)
.attr('d',路径)
.attr('id',函数(c){
返回“国家”+c.properties.nuts_id;
})
。在('单击',单击或双国家/地区);
功能单击或双国家(d,i){
if(dblclick\u计时器){//双击
clearTimeout(dblclick_定时器);
dblclick_timer=false;

my.countryDoubleClicked=d.country;//我更喜欢显示模块模式上方的原始模块模式,主要是因为松散扩展的好处;简而言之,它允许将模块分解为可以异步加载的部分,请阅读更多

通过代码下面的
window.NAME=window.NAME |{}
,如果名称为NAME的自定义命名空间尚不存在,则会声明该命名空间。模块1在其中声明变量
my
,模块2声明变量
other
;模块1在模块2之前还是之后运行无关紧要

当主模块被执行时(在模块1和2之后),它可以访问这两个模块中定义的变量。注意,这些变量可以通过3种不同的方式访问

//Module1.js。
(职能(名称){
NAME.my=“foo”//Replace为地图实例。
})(window.NAME=window.NAME | |{});
//Module2.js。
(函数(名称空间){
namespace.other=“bar”
})(window.NAME=window.NAME | |{});
//主模块使用上述两个模块中定义的内容。
(函数(名称空间){
console.log(NAME.my);
log(namespace.my)
console.log(window.NAME.my);
console.log(NAME.other);
log(namespace.other)
console.log(window.NAME.other)

})(window.NAME=window.NAME | |{})
function new
最好调用一个函数,而不是保留关键字..?第一行无法工作,因为您返回的是
my
,而不是一个名为
my
的属性对象。我还看不到第二行的问题(如果有问题的话)。在调用
clickOrDoubleCountry
事件处理程序之前,它肯定是未定义的。@Alnitak:很好point@Alnitak我不知道我是否理解你的意思,但当然,当事件发生时,变量必须被传递,我是这个问题答案的作者