首页 > 解决方案 > 重写这行javascript

问题描述

https://codepen.io/kurt_cagle/pen/xqoMBG我找到了一个带有以下语句的函数 walkData:

var buf = Object.keys(data).map((key)=>`<details><summary  id="${key}" ${Object.keys(data[key]).map((subkey)=>{return subkey != 'children'?`data-${subkey}="${data[key][subkey]}"`:' '}).join(' ')}><img class="icon" src="${me.imageBase}${data[key].icon?data[key].icon:data[key].children?'Folder.png':'Item.png'}"> </img>${data[key].label}</summary>
 ${data[key].children?me.walkData(data[key].children):""}</details>`); 

作为一个老式的非功能恐龙,我发现地图和插值是一团糟,几乎不可能跟随、调试或修改。codepen“格式化Javascript”按钮有帮助,但还不够。(我会在这里发布,但格式让我失望)

是否可以将其重新设计为使用手写循环、中间变量和较短的行,理想情况下它们只做一件事。

作为一个附带问题,那一行中有四个`,谁能向我解释一下js是如何解析它的?

标签: javascript

解决方案


我保留了您的原始代码只是添加了适当的换行符和缩进。

我添加的只是:

  • 要渲染到的目标元素
  • data我使用该功能进行逆向工程的一些假货
  • walkData一个只返回“CHILDREN”的假函数......

注意:我实际上可以稍微改进此代码并删除<img>元素的结束标记,因为这些是不必要的。subkeymap 函数也是单行函数,因此它实际上可以转换为不带大括号或显式 ; 的lambda return。就像key它外面的映射器一样。

例子

我一点点格式化有很长的路要走。模板文字很棒,因为您不必处理混乱的字符串连接。

const data = {
  'a': { label: 'Directory A', children: [] },
  'b': { label: 'File B', children: null }
}

const me = {
  imageBase: '/',
  walkData: (children) => 'CHILDREN'
}

const buf = Object.keys(data).map((key) => `
  <details>
    <summary
        id="${key}" ${Object.keys(data[key]).map((subkey) => {
          return subkey != 'children'
            ? `data-${subkey}="${data[key][subkey]}"` : ' '
        }).join(' ')}>
      <img class="icon"
          src="${me.imageBase}${data[key].icon
            ? data[key].icon : data[key].children
              ? 'Folder.png' : 'Item.png'}">
      </img>
      ${data[key].label}
    </summary>
    ${data[key].children ? me.walkData(data[key].children) : ""}
  </details>
`)

document.getElementById('target').innerHTML = buf.join('')
<div id="target"></div>

更新

这是另一个具有单独函数调用和注释的版本。它在功能上与前面的代码相同。

没有明确return的陈述,因为所有的 lambda 都是单行的。

const data = {
  'a': { label: 'Directory A', children: [] },
  'b': { label: 'File B', children: null }
}

const me = {
  imageBase: '/',
  walkData: children => 'CHILDREN'
}

const main = () => {
  document.getElementById('target').innerHTML = render(data)
}

const render = data =>
  Object.keys(data).map(key =>
    renderDetails(key, data)).join('')

const renderDetails = (key, data) =>
  `<details>
    <summary id="${key}" ${renderDataAttributes(data[key])}>
      <img class="icon" src="${renderImageSource(data[key])}">
      </img>
      ${data[key].label}
    </summary>
    ${data[key].children ? me.walkData(data[key].children) : ""}
  </details>`

const renderDataAttributes = detail =>
  Object.keys(detail)
    .filter(key => key !== 'children')          // Filter-out children
    .map(key => `data-${key}="${detail[key]}"`) // Map to a data attr
    .join(' ')                                  // Join the values

const renderImageSource = detail =>
  me.imageBase + (
    detail.icon          /* If the detail has an icon,   */
      ? detail.icon      /* Use the defined icon         */
      : detail.children  /* Else, does it have children? */
        ? 'Folder.png'   /* If so, it's  directory       */
        : 'Item.png'     /* Else, it's a file            */
  )

main()
<div id="target"></div>


推荐阅读