【问题标题】:Javascript functions within self-executed block not accesible. Why?无法访问自执行块中的 Javascript 函数。为什么?
【发布时间】:2015-10-19 02:57:02
【问题描述】:

我有一个简单的 index.html 文件,其中包含一些可拖动的图像。我的 JS 文件如下所示:

    function drop(ev){
      ev.preventDefault();
      var data = ev.dataTransfer.getData('text');
      ev.target.appendChild(document.getElementById(data));
    }

    function drag(ev){
      ev.dataTransfer.setData('text',ev.target.id);
    }

效果很好。但是,据我所知,在自执行块中编写代码是一种很好的做法。

所以,我移动了我的两个函数:

    (function(){

      function drop(ev){
        ev.preventDefault();
        var data = ev.dataTransfer.getData('text');
        ev.target.appendChild(document.getElementById(data));
      }

      function drag(ev){
        ev.dataTransfer.setData('text',ev.target.id);
      }

    })();

现在,当拖动图像时,函数似乎“未定义”。他们可能是新手问题,但是:

  • 我可以将我的函数保留在块范围内,并且仍然像 <div id="div0" ondrop="drop(event)">...</div> 这样在 HTML 上使用它们吗?

  • 如果不是,为什么?

【问题讨论】:

  • 试着看看闭包。反正内部函数只会被解析,但除非你调用它,否则它不会被执行
  • 这是一个范围问题。如果您希望这些功能是全局的,window.drop=function(ev){ ...
  • 我不是从 HTML 标签中调用它吗? <div id="div0" ondrop="drop(event)">...</div>
  • 是的,所以它需要是全局的

标签: javascript html function scope


【解决方案1】:

将东西封闭到 IIFE 中的全部目的是隔离它们,而不是用不必要的东西污染全球环境。例如,

var counter = (function() {
  var current = 0;
  function getCurrentAndIncrement() {
    return current++;
  };
  return getCurrentAndIncrement;
})();

counter()
// 0
counter()
// 1
current
// ReferenceError: current is not defined

我们隐藏应该私有的,暴露应该公开的。

你把所有东西都藏起来了——那么它无法访问的事实就不足为奇了。

最后,<div id="div0" ondrop="drop(event)">...</div> 是一个不好的做法。从 JavaScript 绑定事件侦听器要好得多,如果有点复杂的话。这样做:

<div id="div0">...</div>

然后在 JavaScript 中,

var div0 = document.getElementById('div0');
div0.addEventListener('drop', myHandler);

这确实可以塞进 IIFE。无论您从 HTML 中引用什么(如在您的 drop 函数中)都需要在全局范围内,否则浏览器将无法找到它。

【讨论】:

    【解决方案2】:

    答案是范围。函数内定义的变量和函数只能在该函数内访问。在您的第一个示例中,您正在全局定义它们;在您的第二个示例中,它们位于函数内部。

    我可以将我的函数保留在块范围内,并且仍然像&lt;div id="div0" ondrop="drop(event)"&gt;...&lt;/div&gt; 这样在 HTML 上使用它们吗?

    要使用老式onxyz 属性处理程序中的函数,它们必须是全局的。您可以通过将它们分配给全局对象上的属性来使您的函数全局化,您可以在浏览器上以window 的身份访问:

    (function() {
    
        function drop(ev) {
            ev.preventDefault();
            var data = ev.dataTransfer.getData('text');
            ev.target.appendChild(document.getElementById(data));
        }
    
        function drag(ev) {
            ev.dataTransfer.setData('text', ev.target.id);
        }
    
        window.drop = drop;
        window.drag = drag;
    
    })();
    

    ...但理想情况下,最好不要创建全局变量;全局命名空间难以置信拥挤,添加它只是要求冲突。相反,请使用现代事件处理(addEventListenerattachEvent)而不是 onxyz 属性。

    【讨论】:

      【解决方案3】:

      内部函数不会被执行。闭包的美妙之处来了,让 js 对象成为 private 和 public 。此代码可能符合您的目的

      var demoFunction =(function(){
          function _drop(ev){
              alert("Helo");
                _drag();
            }
          function _drag(ev){
             alert("Hello1");
            }
          _drop();
      
         return{
               drop :_drop,
               drag:_drag    
          }
      })();
      

      你也可以通过demoFunction.drop等调用这个drop和从其他函数拖拽。希望对你有帮助

      jsfiddle

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-08-11
        • 1970-01-01
        • 1970-01-01
        • 2010-10-10
        • 2020-10-24
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多