在JavaScript中递归中添加对象

发布于 2025-02-05 12:20:38 字数 2492 浏览 2 评论 0 原文

我正在通过满足的API处理数据,并且正在尝试建立我正在构建的网站的结构。我正在使用GraphQL API并获得满足页面,但是由于限制速率,在获得参考和层次结构方面,我无法对我的查询进行深度深度。

这使我在查询“页面”内容类型并获取每个页面并获取其父页面ID,只有一个级别。理论是,如果我为每个页面执行此操作,我可以通过在构建过程中运行一些JS来递归构建页面结构(我正在使用高架来构建网站)。

我需要一个函数来生成一个面包屑阵列,理想情况下,我会给该功能一个页面的ID,它将跟踪数据,从而为我提供父母的详细信息,父母的父母,依此类推,直到没有更多的父母为止。

我有以下代码,目前分为两个函数(尽管不确定这是最好的方法!)

  /**
   * This takes an ID and finds it within the contentfulPages array (the result
   * of the GraphQL query to Contentful)
   * It returns an object containing the page's ID, slug (for the URL), title
   * (for the readable text) and the parentPageId so we can use that to get the
   * same details for the parent page
   */
  function getParentPage(pageId) {
    const { id, slug, title, parentPageId } = contentfulPages.find(
      (page) => page.id === pageId
    );
    return { id, slug, title, parentPageId };
  }

  /**
   * This takes an ID and passes it to getParentPage to get the first parentPage
   * details. If there is another parent page, it calls itself with the newly 
   * found parent page and pushes that object to the breadcrumbArray. Because it
   * returns the breadcrumb array, each iteration is a more deeply nested array 
   * as opposed to an object at the same level
   */
  function getBreadcrumb(pageId) {
    let breadcrumbArray = [];
    const { id, slug, title, parentPageId } = getParentPage(pageId);
    breadcrumbArray.push({ id, slug, title, parentPageId });
    if (parentPageId) {
      breadcrumbArray.push(getBreadcrumb(parentPageId));
    }
    return breadcrumbArray;
  }

我明白了为什么它在做它在做什么,但是我不知道如何修复它 - 我想要最终结果是一系列平坦的对象,但是递归功能引起了我的问题,因为我认为它必须返回某些东西,但我不确定该怎么做!

一个三层深页的一个例子是:

// Expected:
[
  {
    id: 'page-3',
    slug: 'courses',
    title: 'Courses',
    parentPageId: 'page-2'
  },
  {
    id: 'page-2',
    slug: 'training',
    title: 'Training',
    parentPageId: 'page-1'
  },
  {
    id: 'page-1',
    slug: 'services',
    title: 'Services',
    parentPageId: false
  },
]


// Actual:
[
  {
    id: 'page-3',
    slug: 'courses',
    title: 'Courses',
    parentPageId: 'page-2'
  },
  [
    {
      id: 'page-2',
      slug: 'training',
      title: 'Training',
      parentPageId: 'page-1'
    },
    [ 
      {
        id: 'page-1',
        slug: 'services',
        title: 'Services',
        parentPageId: false
      },
    ]
  ]
]

非常感谢您的帮助!

I'm working with data via the Contentful API and I'm trying to build up a structure of the website I'm building. I'm using the GraphQL API and getting Contentful pages, but, due to rate-limiting, I can't go super deep with my query when it comes to getting references and hierarchical structure.

This has left me querying my "pages" content type and getting each page and getting its parent page ID, just one level up. The theory being that if I do this for every page, I can build up the page structure recursively by running some JS during the build (I'm using Eleventy to build the site).

I need a function to generate me a breadcrumbs array, ideally I'd give the function a single page's ID and it would track through the data getting me the details of the parent, the parent's parent and so on until there are no more parents.

I've got the following code, split into two functions at the moment (although not sure if that's the best approach!)

  /**
   * This takes an ID and finds it within the contentfulPages array (the result
   * of the GraphQL query to Contentful)
   * It returns an object containing the page's ID, slug (for the URL), title
   * (for the readable text) and the parentPageId so we can use that to get the
   * same details for the parent page
   */
  function getParentPage(pageId) {
    const { id, slug, title, parentPageId } = contentfulPages.find(
      (page) => page.id === pageId
    );
    return { id, slug, title, parentPageId };
  }

  /**
   * This takes an ID and passes it to getParentPage to get the first parentPage
   * details. If there is another parent page, it calls itself with the newly 
   * found parent page and pushes that object to the breadcrumbArray. Because it
   * returns the breadcrumb array, each iteration is a more deeply nested array 
   * as opposed to an object at the same level
   */
  function getBreadcrumb(pageId) {
    let breadcrumbArray = [];
    const { id, slug, title, parentPageId } = getParentPage(pageId);
    breadcrumbArray.push({ id, slug, title, parentPageId });
    if (parentPageId) {
      breadcrumbArray.push(getBreadcrumb(parentPageId));
    }
    return breadcrumbArray;
  }

I can see why it's doing what it's doing, but I don't know how to fix it - I want the end result to be a flat array of objects, but the recursive function is causing me problems I think, because I think it has to return something, but I'm not sure how to do that!

An example for a three-levels deep page is this:

// Expected:
[
  {
    id: 'page-3',
    slug: 'courses',
    title: 'Courses',
    parentPageId: 'page-2'
  },
  {
    id: 'page-2',
    slug: 'training',
    title: 'Training',
    parentPageId: 'page-1'
  },
  {
    id: 'page-1',
    slug: 'services',
    title: 'Services',
    parentPageId: false
  },
]


// Actual:
[
  {
    id: 'page-3',
    slug: 'courses',
    title: 'Courses',
    parentPageId: 'page-2'
  },
  [
    {
      id: 'page-2',
      slug: 'training',
      title: 'Training',
      parentPageId: 'page-1'
    },
    [ 
      {
        id: 'page-1',
        slug: 'services',
        title: 'Services',
        parentPageId: false
      },
    ]
  ]
]

Assistance would be much appreciated!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

南汐寒笙箫 2025-02-12 12:20:38

您可以使用 getBreadcrumb 推入结果,而是可以从返回数组中推动单个数组元素-us/docs/web/javascript/referent/operators/spread_syntax“ rel =“ nofollow noreferrer”> vrize语法( ...

breadcrumbArray.push(...getBreadcrumb(parentPageId))

请注意,如果阵列阵列,上述内容将失败由 getBreadcrumb()返回,非常大,超过了最大值计数,您可以将其传递到 .push()函数。您总是可以选择做自己当前正在做的事情,然后调用 .flat(infinity) 在您的返回结果上。确实可以避免在您的阵列上添加额外的通行证。
您可以通过返回一个新数组来克服这些问题,而返回的数组则会扩散到其中:

function getBreadcrumb(pageId) {
  const { id, slug, title, parentPageId } = getParentPage(pageId);
  return [{ id, slug, title, parentPageId }, ...(parentPageId ? getBreadcrumb(parentPageId) : [])];
}

以您的 {id,slug,...} 对象为第一个,将创建一个新数组元素,然后是什么都没有的(如果 parentpageId 是虚假的),或者呼叫返回的该数组中的数组元素,返回到 getBreadcrumb(parentpageId)

Rather than pushing the entire returned array from getBreadcrumb into your result, you can instead push the individual array elements from the returned array using the spread syntax (...):

breadcrumbArray.push(...getBreadcrumb(parentPageId))

Note that the above will fail if the array returned by getBreadcrumb() is very large an exceeds the max-argument count that you can pass to the .push() function. You do always have the option of doing what you're currently doing, and then calling .flat(Infinity) on your returned result. This does add an additional pass over your array though which can be avoided.
You can overcome these issues by instead returning a new array, with your returned array spread into that:

function getBreadcrumb(pageId) {
  const { id, slug, title, parentPageId } = getParentPage(pageId);
  return [{ id, slug, title, parentPageId }, ...(parentPageId ? getBreadcrumb(parentPageId) : [])];
}

The above will create a new array, with your {id, slug, ...} object as the first element, followed by either nothing (if parentPageId is falsy), or the array elements from that array returned by the call to getBreadcrumb(parentPageId))

我很坚强 2025-02-12 12:20:38

这是一种非回收方法,请使用a 循环,然后重新计算 getParentPage()

function getBreadcrumb(pageId) {
  let breadcrumbArray = [];
  let { id, slug, title, parentPageId } = getParentPage(pageId);
  breadcrumbArray.push({ id, slug, title, parentPageId });
  
  // while parentPageId === false, execute getParentPage with found id
  while ( parentPageId ) {
      pageObj = getParentPage(id);
      breadcrumbArray.push(pageObj);
      // update found id and parentPageId for while loop
      id = pageObj.parentPageId;
      parentPageId = pageObj.parentPageId;
  }
  return breadcrumbArray;
}

// okay to ignore the rest...
// parent page mock up, randomly return a parentPageId that equates to false
function getParentPage(pageId) {
  return { id: 1, slug: "slug", title: "title", parentPageId: Math.floor(Math.random() * 2) };
}
console.log(getBreadcrumb(3));

Here's a non-recursive approach, use a while loop, and re-call getParentPage():

function getBreadcrumb(pageId) {
  let breadcrumbArray = [];
  let { id, slug, title, parentPageId } = getParentPage(pageId);
  breadcrumbArray.push({ id, slug, title, parentPageId });
  
  // while parentPageId === false, execute getParentPage with found id
  while ( parentPageId ) {
      pageObj = getParentPage(id);
      breadcrumbArray.push(pageObj);
      // update found id and parentPageId for while loop
      id = pageObj.parentPageId;
      parentPageId = pageObj.parentPageId;
  }
  return breadcrumbArray;
}

// okay to ignore the rest...
// parent page mock up, randomly return a parentPageId that equates to false
function getParentPage(pageId) {
  return { id: 1, slug: "slug", title: "title", parentPageId: Math.floor(Math.random() * 2) };
}
console.log(getBreadcrumb(3));

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文