【问题标题】:TypeError: Assignment to constant variable, when trying to create an array of objectsTypeError:尝试创建对象数组时分配给常量变量
【发布时间】:2021-02-15 13:02:29
【问题描述】:

我一直在研究一个抓取工具,一切都很好,直到我尝试将抓取的数据对象推送到一个数组中。

现在我有这个:

exports.parseData = (getLink, getDescription, getPrice, getPicture) => {
  const apartments = [];
  apartments = {
    link: getLink,
    descr: getDescription,
    price: getPrice,
    picture: getPicture,
  };
  console.log(apartments);
};

但它会抛出错误:TypeError: Assignment to constant variable

现在我认为这是因为数据是如何发送到解析器的。 以下是我使用此代码时数据的外观:

exports.parseData = (getLink, getDescription, getPrice, getPicture) => {
  console.log(getLink);
  console.log(getDescription);
  console.log(getPrice);
  console.log(getPicture);
  console.log('-----------------');
};


https://www.sant.ba/nekretnine/nekretnina-3467-dvosoban-stan-sa-liftom-u-samom-centru-grada-63-m2
 dvosoban stan sa liftom u samom centru grada , 63 m2 
199000.00
https://www.sant.ba/thumb.php?file=photos/3467/3467_1_1563271355.jpg&maxw=273&maxh=205
-----------------
https://www.sant.ba/nekretnine/nekretnina-3689-troiposoban-stan-u-naselju-sunca
 Troiposoban stan u naselju Sunca
360000.00
https://www.sant.ba/thumb.php?file=photos/3689/3689_1_1612344465.jpg&maxw=273&maxh=205
-----------------
https://www.sant.ba/nekretnine/nekretnina-3677-trosoban-renoviran-stan-u-naselju-dolac-malta-73-m2
 trosoban, renoviran stan u naselju Dolac malta, 73 m2
150000.00
https://www.sant.ba/thumb.php?file=photos/3677/3677_1_1608550332.jpg&maxw=273&maxh=205
-----------------
https://www.sant.ba/nekretnine/nekretnina-3537-cetverosoban-stan-u-novogradnji-sa-prelijepim-pogledom-na-grad-118-38-m2
 Četverosoban stan u novogradnji sa prelijepim pogledom na grad, 118,38 m2 
538090.37
https://www.sant.ba/thumb.php?file=photos/3537/3537_1_1573217155.jpg&maxw=273&maxh=205
-----------------
https://www.sant.ba/nekretnine/nekretnina-3536-trosoban-stan-u-novogradnji-sa-prelijepim-pogledom-na-grad-105-34-m2
 Trosoban stan u novogradnji sa prelijepim pogledom na grad, 105,34 m2
478817.70
https://www.sant.ba/thumb.php?file=photos/3536/3536_2_1573216638.jpg&maxw=273&maxh=205
-----------------
https://www.sant.ba/nekretnine/nekretnina-3535-luksuzni-cetverosoban-stan-na-cobaniji-117-43m2
 Luksuzni četverosoban stan na Čobaniji,117,43m2
533772.19
https://www.sant.ba/thumb.php?file=photos/3535/3535_13_1573215220.jpg&maxw=273&maxh=205
-----------------
https://www.sant.ba/nekretnine/nekretnina-3534-trosoban-stan-u-novogradnji-90-m2
 trosoban stan u novogradnji, 90 m2
376923.46
https://www.sant.ba/thumb.php?file=photos/3534/3534_8_1573214216.jpg&maxw=273&maxh=205
-----------------
etc....

现在我想要的输出是:拥有一个对象数组,其中对象填充有数据,如上例所示。因此,为每个getLink, getDescription, getPrice, getPicture 创建新对象并将其推送到数组中(就像我在第一个代码块中使用它一样)。

我想得到的输出是:

[
   {
   
      link: https://www.sant.ba/nekretnine/nekretnina-3467-dvosoban-stan-sa-liftom-u-samom-centru-grada-63-m2
      descr: dvosoban stan sa liftom u samom centru grada , 63 m2 
      price: 199000.00
       picture: https://www.sant.ba/thumb.php?file=photos/3467/3467_1_1563271355.jpg&maxw=273&maxh=205
   },
   {
     link:https://www.sant.ba/nekretnine/nekretnina-3689-troiposoban-stan-u-naselju-sunca
     descr: Troiposoban stan u naselju Sunca
     price: 360000.00
     picture: https://www.sant.ba/thumb.php?file=photos/3689/3689_1_1612344465.jpg&maxw=273&maxh=205
   },
   etc...
]

这样的事情容易实现吗? 谢谢!

这里是这些变量的发送位置:

const cheerio = require('cheerio');
const axios = require('axios');
const parsing = require('./parseData');

exports.olxScraper = () => {
  const url =
    'https://www.olx.ba/pretraga?vrsta=samoprodaja&kategorija=23&sort_order=desc&kanton=9&sacijenom=sacijenom&stranica=1';

  const getRawData = async () => {
    try {
      await axios.get(url).then((res) => {
        const $ = cheerio.load(res.data);
        $('div[id="rezultatipretrage"] > div')
          .not('div[class="listitem artikal obicniArtikal  i index"]')
          .not('div[class="obicniArtikal"]')
          .each((index, element) => {
            $('span[class="prekrizenacijena"]').remove();
            const getLink = $(element)
              .find('div[class="naslov"] > a')
              .attr('href');
            const getDescription = $(element)
              .find('div[class="naslov"] > a > p')
              .text();
            const getPrice = $(element)
              .find('div[class="datum"] > span')
              .text()
              .replace(/\.| ?KM$/g, '')
              .replace(' ', '');
            const getPicture = $(element)
              .find('div[class="slika"] > img')
              .attr('src');

            parsing.parseData(getLink, getDescription, getPrice, getPicture);
          });
      });
    } catch (error) {
      console.log(error);
    }
  };
  getRawData();
};

exports.santScraper = () => {
  const url = `https://www.sant.ba/pretraga/prodaja-1/tip-2/cijena_min-20000/stranica-1`;

  const getRawData = async () => {
    try {
      await axios.get(url).then((response) => {
        const $ = cheerio.load(response.data);

        $('div[class="col-xxs-12 col-xss-6 col-xs-6 col-sm-6 col-lg-4"]').each(
          (index, element) => {
            const getLink = $(element).find('a[class="re-image"]').attr('href');
            const getDescription = $(element).find('a[class="title"]').text();
            const getPrice = $(element)
              .find('div[class="prices"] > h3[class="price"]')
              .text()
              .replace(/\.| ?KM$/g, '')
              .replace(',', '.');
            const getPicture = $(element).find('img').attr('data-original');
            /*const getSquaremeters = $(element)
        .find('span[class="infoCount"]')
        .first()
        .text()
        .replace(',', '.')
        .split('m')[0];

      const pricepersquaremeter =
        parseFloat(getPrice) / parseFloat(getSquaremeters);
      articles[index] = {
        id: getLink.substring(42, 46),
        link: getLink,
        descr: getDescription,
        price: Math.round(getPrice),
        pictures: getPicture,
        sqm: Math.round(getSquaremeters),
        ppm2: Math.round(pricepersquaremeter),
      };*/
            parsing.parseData(getLink, getDescription, getPrice, getPicture);
          }
        );
      });
    } catch (error) {
      console.log(console.log(error));
    }
  };
  getRawData();
};

this.olxScraper();
this.santScraper();

【问题讨论】:

    标签: javascript node.js arrays object


    【解决方案1】:

    当你声明一个常量时,引用不能改变。在您的代码中它显示const apartments = [],因此您将 const 声明为一个数组,然后尝试将 const 声明为一个对象。

    试试

    apartments.push({
        link: getLink,
        descr: getDescription,
        price: getPrice,
        picture: getPicture,
      });
    

    【讨论】:

    • Tnx 的答案。但它并没有像我预期的那样工作。它返回给我:带有对象的数组。带有对象的数组 带有对象的数组等等。而不是只有一个数组里面有多个对象
    • @pupeeterMaster 如果你想要一个数组,你可以在这个函数之外声明这个数组并将它作为参数发送,或者这个函数返回一个将推入数组的对象,例如 const const apartment = {//properties}跨度>
    【解决方案2】:

    您的代码不止一个问题:

    1. 您不能重新分配 const 变量。

       const apartments = [];
       apartments = { ... };  //this is not allowed, becasue apartments is const.
      
    2. 您将apartments 定义为一个数组,然后尝试将一个对象分配给同一个变量。这在 javascript 中是允许的,但可能不是你想要的......

    编辑

    至于您的评论:如果您希望单个数组包含所有对象,则必须在函数之外定义数组并定义 parseData 函数以返回一个对象,然后可以将其推入该数组。

    const apartments = [];
    const getRawData = async () => {
        try {
          await axios.get(url).then((res) => {
            const $ = cheerio.load(res.data);
            $('div[id="rezultatipretrage"] > div')
              .not('div[class="listitem artikal obicniArtikal  i index"]')
              .not('div[class="obicniArtikal"]')
              .each((index, element) => {
                $('span[class="prekrizenacijena"]').remove();
                const getLink = $(element)
                  .find('div[class="naslov"] > a')
                  .attr('href');
    
                ....
    
                //push the result of parseData into the array
                apartments.push(parsing.parseData(getLink, getDescription, getPrice, getPicture));
    
    
               //if your parsedata just returns an object created from its parameters,
               //you can get rid of the function and just do 
               //apartments.push({
               //  link: getLink,
               //  descr: getDescription,
               //  price: getPrice,
               //  picture: getPicture           
               //});
              });
          });
        } catch (error) {
          console.log(error);
        }
      };
    

    重新定义parseData 只返回一个对象。虽然看起来没有必要,但拥有一个只返回其参数对象的函数。

    exports.parseData = (getLink, getDescription, getPrice, getPicture) => {
      const apartment = {
        link: getLink,
        descr: getDescription,
        price: getPrice,
        picture: getPicture,
      };
      return apartment;
    };
    

    【讨论】:

    • 感谢您的回答!但它并没有像预期的那样让我恢复输出。它一个接一个地返回包含对象的数组,覆盖自身,而不是只获取一个包含多个对象的数组。
    • 如果要将所有对象添加到单个数组中,则必须在外部范围(即调用函数的位置)中定义该数组,然后将数组传递给函数或者只返回一个对象并将函数的结果添加到数组中
    • 我已经更新了我想要的输出。你的建议是什么?什么是最清晰易读的。请注意,我将在其中放置数据的刮板不止一个。
    • @pupeeterMaster 查看更新的答案。如果您有多个爬虫,则必须找到一些全局状态,您可以在其中创建数组,以便所有爬虫都可以访问它
    • 我现在有点困惑。那么我将如何输出我的公寓呢?而且我正在从这个组件发送数据到 parseData 组件。所以我的数据从这个 Scarping 组件发送到 parseData,在那里我需要处理我的数据并将它们插入到对象数组中。
    【解决方案3】:

    你正在用 const 声明公寓。

    const apartments = [];
    

    所以它被设置为一个数组。但是随后您尝试将其更改为对象。

    apartments = {
        link: getLink,
        descr: getDescription,
        price: getPrice,
        picture: getPicture,
      };
    

    常量不能被更新或声明。一旦你将它声明为一个数组。它只能作为一个数组保留。您可以推送到该数组,但不能将其更改为对象或任何其他数据类型。

    在你的情况下,你可以直接将 const 公寓声明为一个对象。

    const apartments = {
        link: getLink,
        descr: getDescription,
        price: getPrice,
        picture: getPicture,
      };
    

    您可以在此处阅读有关 var、let 和 const 的更多信息:https://www.freecodecamp.org/news/var-let-and-const-whats-the-difference/

    添加基于 cmets 的示例。

    const data = [];
    
    const parseData = (getLink, getDescription, getPrice, getPicture) => {
        const apartments = {
            link: getLink,
            descr: getDescription,
            price: getPrice,
            picture: getPicture,
          };
        data.push(apartments)
        console.log(data);
    };
    

    data 不限于 parseData 函数,因此可以包含所有被推送给它的公寓对象。 data 数组的声明位置很大程度上取决于您的代码,并且可能也应该作为参数传递给 parseData 函数。

    【讨论】:

    • 谢谢,我完全理解你的回答。但我认为你不理解我想要达到的目标。现在,它在没有, 的情况下给我返回一个又一个对象,所以它会相互覆盖,我不希望这样。
    • 我想我理解你的问题。您需要在 parseData 函数之外声明一个数组,并将您的公寓对象推送给它。
    • 是的。我需要以某种方式为这四个变量中的每一个创建带有键:值对的对象,并将所有对象推送到数组中,因此我将从那里将它们传递到验证组件,然后再传递到数据库。
    【解决方案4】:

    我看到的是您将变量apartments 分配为数组并将其声明为常量。然后,您尝试将变量重新分配给对象。

    当您将变量分配为const 数组并尝试将其更改为对象时,您实际上是在更改对变量的引用,这是使用const 所不允许的。

    const apartments = [];
      apartments = {
        link: getLink,
        descr: getDescription,
        price: getPrice,
        picture: getPicture,
      };
    

    我认为最简单的选项是将对象推入数组:

    apartments.push({
        link: getLink,
        descr: getDescription,
        price: getPrice,
        picture: getPicture,
      });
    

    或者在你即将推入数组时总是将对象分配给一个变量:

    const apartments = [];
    let apartment = {
        link: getLink,
        descr: getDescription,
        price: getPrice,
        picture: getPicture,
      };
    
    apartments.push(apartment);
    

    【讨论】:

    • 感谢您的回答。但这并没有给我预期的输出。使用这个解决方案,我得到 [ {} ] [ {} ] 等。所以我让每个数组都覆盖,而不是让一个数组里面有对象。
    猜你喜欢
    • 2021-03-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-08
    • 2016-09-18
    • 1970-01-01
    • 2010-09-17
    • 2016-10-04
    相关资源
    最近更新 更多