打破循环

时间:2017-11-03 13:28:32

标签: javascript for-loop callback

我正在尝试创建一个函数,这样你就可以遍历一个包含很多对象的大对象,并按值找到一个特定的方法。我想通过使用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');

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

2 个答案:

答案 0 :(得分:1)

您的问题是,在递归调用fbc并且window_loop的返回值未用于打破外部循环时,达到window_loop值。

您可以对window_loop方法进行一些更改(评论内嵌

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;
    })    
};

<强>演示

&#13;
&#13;
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');
&#13;
&#13;
&#13;

答案 1 :(得分:1)

请考虑以下代码段:

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循环范围之外没有任何影响。根据这些信息,您应该能够弄清楚自己发生了什么。

我希望你不要责怪我尝试原创方法: - )