【问题标题】:Array within Function in JavascriptJavascript中函数内的数组
【发布时间】:2016-06-02 06:19:56
【问题描述】:

代码:

<body>
    <div class="con">
        <button class="tabs"> HTM </button>
        <button class="tabs"> JS </button>
        <button class="tabs"> CSS </button>
    </div>
    <div class="data"> </div>
    <script>
        var bu = document.getElementsByClassName("tabs");
        var contents=["HTML", "js" , "css"];
        for(var i=0; i<bu.length; i++){ 
            alert(contents[i]);
            bu[i].onclick=function(){
                alert(contents[i]);
                document.getElementsByClassName("data").innerHTML = content[i]; 
                }
        }
    </script>
<body>

在上述程序中,for语句旁边的alert函数正确执行。但是,它在“功能”中不起作用。我什么 认为是,“功能”中的语句都只与按钮对象有关。这样对吗?如果是正确的,如何访问 “函数”中的数组?

【问题讨论】:

  • 确保bu的长度大于0,在for语句前加上alert,像这样:alert(bu.length);
  • @user3378165 是的。它返回 3。

标签: javascript arrays function


【解决方案1】:

使用Closures,这样返回的函数就会记住创建它的环境。

由于事件正在loop 中注册,在调用click-handler 时,i 的值是3array 中没有索引为3 的元素,@返回 987654332@。

另外注意,getElementsByClassName返回collection(array-like object)没有属性innerHTML,使用0th索引抓取元素或者使用querySelector


var bu = document.getElementsByClassName("tabs");
var contents = ["HTML", "js", "css"];
for (var i = 0; i < bu.length; i++) {
  bu[i].onclick = (function(i) {
    return function() {
      document.querySelector(".data").innerHTML = contents[i]; //correct typo here
    }
  })(i);
}
<div class="con">
  <button class="tabs">HTM</button>
  <button class="tabs">JS</button>
  <button class="tabs">CSS</button>
</div>
<div class="data"></div>

或使用Array#forEach

var bu = document.getElementsByClassName("tabs");
var contents = ["HTML", "js", "css"];

[].forEach.call(bu, function(item, index) {
  item.onclick = function() {
    document.querySelector(".data").innerHTML = contents[index];
  }
});
<div class="con">
  <button class="tabs">HTM</button>
  <button class="tabs">JS</button>
  <button class="tabs">CSS</button>
</div>
<div class="data"></div>

【讨论】:

    【解决方案2】:

    在单击事件发生时,该值将是数组的长度,因为 for 循环递增 i。因此,您需要在迭代中使用保存i 值的功能级别变量。


    您的代码中还有一个问题:document.getElementsByClassName() 返回一个类似于 live HTMLCollection 的数组,您需要获取一个元素来更新 innerHTML 属性。
    您可以在为变量提供块级范围的新浏览器中使用let

    <body>
      <div class="con">
        <button class="tabs">HTM</button>
        <button class="tabs">JS</button>
        <button class="tabs">CSS</button>
      </div>
      <div class="data"></div>
      <script>
        var bu = document.getElementsByClassName("tabs");
        var contents = ["HTML", "js", "css"];
        for (let i = 0; i < bu.length; i++) {
          alert(contents[i]);      
          bu[i].onclick = function() {
            alert(contents[i]);
            document.getElementsByClassName("data")[0].innerHTML = contents[i];
          }
        }
      </script>
    
      <body>


    或使用closure 并将i 作为参数传递

    <body>
      <div class="con">
        <button class="tabs">HTM</button>
        <button class="tabs">JS</button>
        <button class="tabs">CSS</button>
      </div>
      <div class="data"></div>
      <script>
        var bu = document.getElementsByClassName("tabs");
        var contents = ["HTML", "js", "css"];
        for (let i = 0; i < bu.length; i++) {
          alert(contents[i]);
          (function(i) {
            bu[i].onclick = function() {
              alert(contents[i]);
              document.getElementsByClassName("data")[0].innerHTML = contents[i];
            }
          })(i)
        }
      </script>
    
      <body>

    【讨论】:

    • 使用闭包就可以了。但它不适用于 div("data") 元素。点击按钮后内容不会改变。
    【解决方案3】:

    这是一个典型的回调在闭包变量的情况下不起作用的例子,因为闭包变量正在增加。您的变量 i 甚至在第一次单击按钮之前增加到 3 并且 contents[i] 不返回任何内容。将您的函数更改为具有如下 IIFE 以提供变量 i 的词法范围:

    for(var i=0; i<bu.length; i++){ 
       alert(contents[i]);
        (function (index) {
          bu[index].onclick=function(){
            alert(contents[index]);
            console.log(index);
            document.getElementsByClassName("data")[0].innerHTML = contents[index]; 
           }
        })(i);  
    }
    

    这将为每个按钮单击在词法上限定索引变量。

    您的代码中还有一个拼写错误,您使用的是content[i] 而不是contents[i]

    我在这里创建了一个可以工作的 JSBIn:https://jsbin.com/fasicu/2/edit?html,js,console,output

    更新

    Document.getElementsByClassName()

    返回具有所有给定类名的所有子元素的类数组对象。在文档对象上调用时,将搜索整个文档,包括根节点。

    因此,为了访问单个元素,您需要使用索引 0 从类似数组的对象中访问它

    详情请参考MDN:https://developer.mozilla.org/en/docs/Web/API/Document/getElementsByClassName

    【讨论】:

    • 提醒它正常工作。但它不会改变 div("data") 元素的内容。
    • 还有 1 个问题,document.getElementsByClassName("data") 将返回 NodeList 而不是元素。要访问具有类data 的div,您需要访问NodeList 中索引0 处的元素。我已经更新了相同问题的代码和 JSBIN 链接
    • 谢谢哥们。那么0的需要是什么。程序只包含一个带有“数据”类的div元素。那么,为什么我需要指定为“document.getElementsByClassName("data")[0].innerHTML = contents[index];”而不是 "document.getElementsByClassName("data").innerHTML = contents[index];"
    • 我已经更新了对未来其他人的回答中的要求
    猜你喜欢
    • 2021-08-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-07
    • 2014-05-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多