【问题标题】:Breaking from for loop从 for 循环中断
【发布时间】:2017-11-03 13:28:31
【问题描述】:

我正在尝试创建一个函数,以便您可以遍历一个包含大量对象的大对象,并按值查找特定方法。当使用 break 语句找到值时,我想停止函数中的循环。这是我的代码。

let fake_window = {
    aaa: "aaa",
    bbb: "bbb",
    ccc: "ccc",
    ddd: function ddd() {
        console.log('ddd');
    },
    eee: {
        eea: "eea",
        eeb: "eeb",
        eec: "eec"
    },
    fff: {
        ffa: "ffa",
        ffb: "ffb",
        ffc: {
            fac: "fac",
            fbc: "fbc",
            fcc: "fcc",
            fdc: "fdc"
        }
    },
    ggg: {
        gga: {
            gaa: "gaa",
            gba: "gba"
        },
        ggb: "ggb"
    }

};

const window_loop = function (window_obj, value) {
    for (const prop in window_obj) {
        if (window_obj.hasOwnProperty(prop)) {
            if (value) {
                if (value === window_obj[prop]) { // when value is found
                    console.log("FOUND, NOW STOP!");
                    break;
                }
            }
            console.log(prop + ' => ' + window_obj[prop]);
            if (typeof window_obj[prop] === "object") {
                window_loop(window_obj[prop], value);
            }
        }
    }
};

window_loop(fake_window, 'fbc');

找到值后,我会控制台“找到,现在停止!”然后我打破循环。但由于某种原因,循环不断迭代。有人可以帮我解释为什么会这样吗?

【问题讨论】:

  • window_loop(fake_window, 'fbc') 调用 window_loop(fake_window['fff'], 'fbc') 调用 window_loop(fake_window['fff']['ffc'], 'fbc')。只有最后一个会损坏。
  • 我添加了代码来展示如何通过最小的更改仍然可以使用原来的方法。
  • @gurvinder372 非常感谢!

标签: javascript for-loop callback


【解决方案1】:

您的问题是,当递归调用window_loop 并且window_loop 的返回值不用于中断外循环时,会达到fbc 值。

您可以对 window_loop 方法进行一些更改(cmets inline

window_loop = function (window_obj, value) {
    var isFound = false; //new flag is introduced
    for (const prop in window_obj) {
        if (window_obj.hasOwnProperty(prop)) {
            if (value) {
                if (value === window_obj[prop]) { // when value is found
                    console.log("FOUND, NOW STOP!");
                    isFound = true;
                    break;
                }
            }
            console.log(prop + ' => ' + window_obj[prop]);
            if (typeof window_obj[prop] === "object") {
                isFound = window_loop(window_obj[prop], value);
                if ( isFound ) //break when returned value from loop is true
                {
                    break;
                }
            }
        }
    }
    return isFound; //return this value 
};

另一种简洁的方法是

var window_loop = function (window_obj, value) {
    //return the value of find
    return Object.keys( window_obj ).find( function( key ){
       if (typeof window_obj[key] === "object") {
            //invoke window_loop recursively if the value is object.
            return window_loop(window_obj[key], value);
       }
       if ( value == key )
       {
           console.log("FOUND, NOW STOP!", key);
       }
       else 
       {
           console.log("Not FOUND, continue !", key);
       }
       return value == key;
    })    
};

演示

var fake_window = {
    aaa: "aaa",
    bbb: "bbb",
    ccc: "ccc",
    ddd: function ddd() {
        console.log('ddd');
    },
    eee: {
        eea: "eea",
        eeb: "eeb",
        eec: "eec"
    },
    fff: {
        ffa: "ffa",
        ffb: "ffb",
        ffc: {
            fac: "fac",
            fbc: "fbc",
            fcc: "fcc",
            fdc: "fdc"
        }
    },
    ggg: {
        gga: {
            gaa: "gaa",
            gba: "gba"
        },
        ggb: "ggb"
    }

};

var window_loop = function (window_obj, value) {
    return Object.keys( window_obj ).find( function( key ){
       if (typeof window_obj[key] === "object") {
            return window_loop(window_obj[key], value);
       }
       if ( value == key )
       {
           console.log("FOUND, NOW STOP!", key);
       }
       else 
       {
           console.log("Not FOUND, continue !", key);
       }
       return value == key;
    })    
};

window_loop(fake_window, 'fbc');

【讨论】:

    【解决方案2】:

    考虑以下代码 sn-p:

    var pre = document.getElementById("trace");
    
    f(0, "root", {
      a: { aa: "aa", ab: "ab", ac: "ac" },
      b: { ba: "ba", bb: "bb", bc: "bc" }
    });
    
    function f(depth, name, tree) {
      log(depth, "call f on \"" + name + "\"");
      log(depth + 1, "for each child of \"" + name + "\"");
      for (let name in tree) {
        log(depth + 2, "child \"" + name + "\"");
        if (!isLeaf(tree[name])) {
          log(depth + 2, "if child is not a leaf");
          f(depth + 3, name, tree[name]);
        } else if (name === "aa") {
          log(depth + 2, "if child is \"aa\"");
          log(depth + 3, color("red", "break"));
          break;
        }
      }
    }
    
    function isLeaf(node) {
      return node.hasOwnProperty("length");
    }
    
    function color(c, s) {
      return "<span style=\"color:" + c + "\">" + s + "</span>";
    }
    
    function log(depth, line) {
      for (let i = 0; i < depth; i++) {
        if ((i + 2) % 3 === 0) {
          pre.innerHTML += color("red", "| ");
        } else if ((i + 1) % 3 === 0) {
          pre.innerHTML += color("gray", "| ");
        } else {
          pre.innerHTML += color("blue", "| ");
        }
      }
      pre.innerHTML += line + "\n";
    }
    pre{font-family:Consolas,Menlo,Monaco,Lucida Console,Liberation Mono,DejaVu Sans Mono,Bitstream Vera Sans Mono,Courier New,monospace,sans-serif;font-size:12px;display:inline-block;vertical-align:top;margin:0}
    #trace{padding-left:12px;border-left:12px solid #ddd;margin-left:12px}
    <pre>
    function f(depth, name, tree) {
      for (let name in tree) {
        if (!isLeaf(tree[name])) {
          f(depth + 3, name, tree[name]);
        } else if (name === "aa") {
          break;
        }
      }
    }
    
    f(0, "root", {
      a: { aa: "aa", ab: "ab", ac: "ac" },
      b: { ba: "ba", bb: "bb", bc: "bc" }
    });
    </pre><pre id="trace"></pre>

    输出的右侧部分是执行跟踪。阅读方法如下:

    • 每条水平线都是一个事件。
    • 事件按时间升序排序。
    • 垂直线是一个范围,即一对大括号。
    • 垂直线的长度就是示波器的使用寿命。
    • 蓝色竖线是函数范围。
    • 红色垂直线是for 循环范围。

    你需要知道的是,break 语句对最近的红线左侧没有影响,从技术上讲,它在for 循环范围之外没有影响。根据这些信息,您应该能够自己弄清楚发生了什么。

    我希望你不要怪我尝试了一个原创的方法:-)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-06-07
      相关资源
      最近更新 更多