【问题标题】:Getting return value for Array.forEach function获取 Array.forEach 函数的返回值
【发布时间】:2013-10-25 00:18:41
【问题描述】:

我被以下函数卡住了,试图取回一个值(dom 树的一部分)。

我只是获得了0/undefined,而不是获得有用的价值。

var findNodeForAttributeValue = function (node, innerXmlAttributeName, innerXmlAttributeValue) {
var indirectReturnVar='0';
if ((node.nodeType === 1)&&(node.hasAttribute(innerXmlAttributeName))) {
    if (node.getAttribute(innerXmlAttributeName)==innerXmlAttributeValue) {
        indirectReturnVar=node;
        return indirectReturnVar;
    }
}
if((node.hasChildNodes())&&(node.firstChild!=null)) {
    Array.forEach ( node.childNodes, function (children) {
        findNodeForAttributeValue(children, innerXmlAttributeName, innerXmlAttributeValue);
    } );
    return indirectReturnVar;
}

编辑

更新代码:

var findNodeForAttributeValue = function (node, innerXmlAttributeName, innerXmlAttributeValue) {
  var indirectReturnVar='0';
  if ((node.nodeType === 1) && (node.hasAttribute(innerXmlAttributeName))) {
    if (node.getAttribute(innerXmlAttributeName) == innerXmlAttributeValue) {
      indirectReturnVar = node;
      return indirectReturnVar;
    }
  }

  if ((node.hasChildNodes()) && (node.firstChild != null)) {
    for (var fi=0, fiLen=node.childNodes.length; fi<fiLen; fi++) {
      findNodeForAttributeValue(node.childNodes[fi], innerXmlAttributeName, innerXmlAttributeValue);
    }
    return indirectReturnVar;
  }
}

【问题讨论】:

  • 欢迎来到 StackOverflow!感谢您发布您的代码,但请在您的问题中添加更多描述:您遇到什么问题,您期望的结果是什么,到目前为止what have you tried
  • childNodes 是 NodeList,而不是数组。
  • RobG - 似乎无论如何都可以工作,我在其他有节点的地方使用这个结构......问题是我无法返回一个值...... .

标签: javascript foreach


【解决方案1】:

当你这样做时:

> Array.forEach ( node.childNodes .. )

forEachArray.prototype 上的 Array 实例方法。 childNodes 属性是 NodeList,它不是数组。

在一些支持 ES5 的浏览器中,你可以这样做:

Array.prototype.forEach.call(childNodes, ...)

但这不能保证有效(在 IE 8 及更低版本中会失败)。所以只需使用 for 循环:

for (var i=0, iLen=node.childNodes.length; i<iLen; i++) {
  // do stuff with node.childNodes[i];
}

编辑

修复更新后的代码:

function findNodeForAttributeValue (node, innerXmlAttributeName, innerXmlAttributeValue) {

使用函数声明,我不明白您为什么要使用带有赋值的表达式。此外,较短的变量名会让生活变得更轻松,我可能会这样做:

function getNodeByAttributeValue (node, att, value)

如果您希望变量具有真实值,只需将其设置为 true。在这种情况下,您希望它是假的,因此要么将其保留为未定义,要么将其设置为 null(因为大多数 DOM 方法如果没有得到匹配的元素则返回 null):

  var indirectReturnVar = null;

这个for块很好。

  if ((node.nodeType === 1) && (node.hasAttribute(innerXmlAttributeName))) {

    if (node.getAttribute(innerXmlAttributeName) == innerXmlAttributeValue) {
      indirectReturnVar = node;
      return indirectReturnVar;
    }
  }

  if ((node.hasChildNodes()) && (node.firstChild != null)) {

这个位需要修改。仅在 indirectReturnVar 为假时保持循环:

    for (var fi=0, fiLen=node.childNodes.length; fi<fiLen && !indirectReturnVar; fi++) {

将递归函数的返回值赋值给indirectReturnVar,否则会迷失在以太中。

      indirectReturnVar = findNodeForAttributeValue(node.childNodes[fi], innerXmlAttributeName, innerXmlAttributeValue);


    }
  }

在递归循环外部返回值。它只会循环直到找到匹配的节点或用完节点。

  return indirectReturnVar;
}

【讨论】:

  • 这段代码有什么问题?---var findNodeForAttributeValue = function (node, innerXmlAttributeName, innerXmlAttributeValue) { var indirectReturnVar='0'; if ((node.nodeType === 1)&amp;&amp;(node.hasAttribute(innerXmlAttributeName))) { if (node.getAttribute(innerXmlAttributeName)==innerXmlAttributeValue) { indirectReturnVar=node; return indirectReturnVar; } } if((node.hasChildNodes())&amp;&amp;(node.firstChild!=null)) { for(var fi=0, fiLen=node.childNodes.length; fi&lt;fiLen; fi++) { findNodeForAttributeValue(node.childNodes[fi], innerXmlAttributeName, innerXmlAttributeValue); } return indirectReturnVar; } }
  • 我认为主问题中带有array.foreach结构的代码应该和我插入到注释中的代码是等价的,它使用了for循环:不同的是第一个执行得很快并正确退出,第二个挂在无限循环中......我做错了什么?嘘
  • 如果您更新了代码,您应该将其发布在您的 OP 中。作为评论发布的代码的问题(除了期望其他人复制和粘贴它,然后将其格式化为可读)是递归循环不会对返回的值做任何事情。
【解决方案2】:

find1 下方采用搜索函数f,将为提供的node 调用一次,并为每个节点的childNodes 调用一次。当f 返回true 时,将返回node。否则会给出undefined,表示没有找到结果。

const find1 = (f, node, cursor = 0) =>
  node.nodeType === 1 && f (node)
    ? node
  : cursor === node.childNodes.length
    ? undefined
  : find1 (f, node.childNodes[cursor]) || find1 (f, node, cursor + 1)

console.log
  ( find1
      ( node => node.tagName === 'P'
      , document
      )
      // <p>first paragraph</p>
      
  , find1
      ( node => node.textContent === 'and a span'
      , document
      )
      // <span>and a span</span>
      
  , find1
      ( node => node.getAttribute('class') === 'last'
      , document
      )
      // <p class="last">last paragraph</p>
  )
<div id="main">
  <!-- comment -->
  <h1>title</h1>
  <p>first paragraph</p>
  <p>second paragraph <span>and a span</span></p>
  <p class="last">last paragraph</p>
<div>

find1 以上不限于按特定属性和值搜索节点。相反,用户提供的 lambda 允许程序员将 find1 指向其目标。


如果我们想要 find 的所有结果怎么办?下面findAll返回一个包含所有匹配结果的数组

const findAll = (f, node) =>
{ const loop = function* (node)
  { if (node.nodeType === 1 && f (node))
      yield node
    for (const child of node.childNodes)
      yield* loop (child)
  }
  return Array.from (loop (node))
}

console.log
  ( findAll
      ( node => node.tagName === 'P'
      , document
      )
      // [ <p>first paragraph</p>
      // , <p>second paragraph<span>...</span></p>
      // , <p class="last">last paragraph</p>
      // ]
      
  , findAll
      ( node => node.getAttribute('class') === 'last'
      , document
      )
      // [ <p class="last">last paragraph</p> ]
  )
<div id="main">
  <!-- comment -->
  <h1>title</h1>
  <p>first paragraph</p>
  <p>second paragraph <span>and a span</span></p>
  <p class="last">last paragraph</p>
<div>

find1findAll 这样的高阶函数非常棒,因为它们可以以各种有用的方式进行专门化。

const findByTag = (tagName, node) =>
  findAll
    ( node => node.tagName === tagName.toUpperCase()
    , node
    )

const findByAttrValue = (attr, value, node) =>
  findAll
    ( node => node.getAttribute (attr) === value
    , node
    )

console.log
  ( findByTag ('p', document)
    // [ '<p>...</p>', '<p>...</p>', '<p>...</p>' ]

  , findByTag ('h1', document)
    // [ '<h1>title</h1>' ]

  , findByTag ('strong', document)
    // []

  , findByAttrValue ('class', 'last', document)
    // [ <p class="last">last paragraph</p> ]

  , findByAttrValue ('id', 'main', document)
    // [ <div id="main">...</div> ]

  , findByAttrValue ('class', 'first', document)
    // []
  )

【讨论】:

    猜你喜欢
    • 2017-02-13
    • 2016-01-03
    • 2018-08-25
    • 1970-01-01
    • 2018-06-25
    • 1970-01-01
    • 1970-01-01
    • 2014-05-28
    • 1970-01-01
    相关资源
    最近更新 更多