JavaScript - 函数无法访问另一个函数范围的变量

问题描述:

我试图用javscript创建一个滑块。我想要有两个功能 - 第一个功能,parseDom(),应该负责从DOM获取元素;第二个configureRange()应负责设置范围属性,如minmax值。这两个函数都在匿名函数中调用,该函数被分配给window.onload变量。JavaScript - 函数无法访问另一个函数范围的变量

function parseDom() { 
    var main = document.getElementById('main'); 
    main.classList.add('red'); 
    // red class added - main selector is ok 
    var rangeContainer = main.querySelector('.range-container'); 
    rangeContainer.classList.add('green'); 
    // green class added - rangeContainer selector is ok 
    var rangeInput = rangeContainer.querySelector('.range-input'); 
    rangeInput.classList.add('crosshair'); 
    // crosshair class added - rangeInput selector is ok 

} 

function configureRange(){ 
    rangeInput.classList.add('pointer'); 
    rangeInput.setAttribute('min', '0'); 
} 

window.onload = function(){ 
    parseDom(); 
    configureRange(); 
} 

然而,从parseDom()变量不能从configureRange() accesed,因为这些功能里面变量在不同的范围。所以我的代码configureRange()不起作用。我可以用一个函数而不是两个来完成所有的事情,但是这会使代码变得混乱。我如何创建一个好的模块化解决方案?

代码是在这里: https://codepen.io/t411tocreate/pen/oeKwbW?editors=1111

+1

将参数传递给函数。 – Script47

最简单的事情可能是通过configureRange它所需要的信息,通过具有parseDom调用它:

...或者由具有控制器功能( parseAndConfigure,无论什么),查找输入并将其传递给两个函数。


边注:在保持功能小,保证了名的条款是指示它做什么(似乎是你的目标),parseDom不分析什么,它不仅仅能识别相关的DOM元素(它也向它们添加类)。也许三个功能:getDom,addClassesconfigureRange或类似。然后:

window.onload = function() { 
    var dom = getDom(); 
    addClasses(dom); 
    configureRange(dom); 
} 

...或类似的东西。

+0

理想的解决方案将是第二个,因为它明确定义了代码中发生的事情,并消除了与变量发生冲突的可能性。 – Script47

+0

@ Script47:是的,我的观点也是如此。它真的应该高于此线,而不是低于它,但我会保持原样,因为我看到现在有其他答案(如[adeneo's](https://*.com/a/46133778/157247) ))它在哪里它是属于它的前面。 ([麦当劳](https://*.com/a/46133795/157247),虽然没有'getDom'函数。) –

你可以声明变量的.onload内,然后将它们作为参数传递给尽可能多的功能,只要你喜欢:

function parseDom(main, rangeContainer, rangeInput) { // <= arguments 
    main.classList.add('red'); 
    rangeContainer.classList.add('green'); 
    rangeInput.classList.add('crosshair'); 
} 

function configureRange(rangeInput){ // <= argument 
    rangeInput.classList.add('pointer'); 
    rangeInput.setAttribute('min', '0'); 
} 

window.onload = function(){ 
    var main = document.getElementById('main'), 
    rangeContainer = main.querySelector('.range-container'), 
    rangeInput = rangeContainer.querySelector('.range-input'), 
    // other elements 
    parseDom(main, rangeContainer, rangeInput); // <= pass as arguments 
    configureRange(rangeInput); // <= pass as argument 
} 
+1

不是一个好主意。这只是['code smell'](https://*.com/questions/5063878/how-to-cleanly-deal-with-global-variables)。更好的选择是传递参数。 – Script47

+0

@ Script47当您拥有数十个操纵相同元素的函数时,它对模块化非常有用。 –

+0

看看@ T.J.Crowder的第二个解决方案,它会处理你提出的情况。 – Script47

你可以保留元素的对象,然后返回一个对象,是重用其他地方

function parseDom() { 
    var els = (function(d) { 
    var main   = d.getElementById('main'), 
     rangeContainer = main.querySelector('.range-container'), 
     rangeInput  = rangeContainer.querySelector('.range-input'); 

    return {main, rangeContainer, rangeInput}; 
    })(document); 

    els.main.classList.add('red'); 
    els.rangeContainer.classList.add('green'); 
    els.rangeInput.classList.add('crosshair'); 

    return els; 
} 

function configureRange(els) { 
    els.rangeInput.classList.add('pointer'); 
    els.rangeInput.setAttribute('min', '0'); 

    return els; 
} 

window.onload = function() { 
    var elems = parseDom(); 
    configureRange(elems); 
} 

最简单的方法是抽象从parseDom功能选择离开,也许称之为updateDom代替,并在顶层的功能,例如解析选择

function updateDom(main, rangeContainer, rangeInput) { 
    main.classList.add('red'); 
    // red class added - main selector is ok 

    rangeContainer.classList.add('green'); 
    // green class added - rangeContainer selector is ok 

    rangeInput.classList.add('crosshair'); 
    // crosshair class added - rangeInput selector is ok 

} 

function configureRange(rangeInput){ 
    rangeInput.classList.add('pointer'); 
    rangeInput.setAttribute('min', '0'); 
} 

window.onload = function(){ 
    var main = document.getElementById('main'), 
    rangeContainer = main.querySelector('.range-container'), 
    rangeInput = rangeContainer.querySelector('.range-input'); 

    updateDom(main, rangeContainer, rangeInput); 
    configureRange(rangeInput); 
}