匿名函数中变量的范围

时间:2017-05-01 21:01:55

标签: javascript function scope

我有这个功能

function parseLink(link) {
    var product;
    request(link, function (error, response, body) {
        if (!error && response.statusCode == 200) {
            var $ = cheerio.load(body);

            // title
            var title = $('h1').text();
            if (!title)
                var title = $('title').text();

            var description = $('meta[name="description"]').attr('content');

            product = new Product(link.trim(), title.trim(), description.trim());
        }
    });
    console.log(product);
    return product;
}

我不明白为什么当我在请求电话之外执行 console.log(产品)时,我已经未完成但在里面,我可以看到我的产品。

我在javascript中学习了很多关于范围的事情,我不明白,我在顶部函数中定义了产品。 我需要返回这个变量来获取它在另一个函数中,如果在请求中返回我当然有一个未定义的所以我需要在外面做这个... 谢谢

2 个答案:

答案 0 :(得分:0)

javascript不运行像cphp这样的代码,您可以确保下一行代码在前一代准备就绪时运行。在你的情况下,request是一个异步函数,所以两行

console.log(product);
return product;

主要在request功能准备就绪之前运行。在这种情况下,您不能仅从parseLink函数返回一些值。你有两种可能性:

  1. 使用承诺: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise

  2. 使用回调:

  3. 像这样:

    function parseLink(link, callback) {
        var product;
        request(link, function (error, response, body) {
            if (!error && response.statusCode == 200) {
                var $ = cheerio.load(body);
    
                // title
                var title = $('h1').text();
                if (!title)
                    var title = $('title').text();
    
                var description = $('meta[name="description"]').attr('content');
    
                product = new Product(link.trim(), title.trim(), description.trim());
                callback(product);
            }
        });
    }
    

    然后运行像

    这样的代码
    parseLink('http://...', function(product) { /* do something with the product */ });
    

    ps:回调的使用要容易得多,但在某些情况下,如果你在for循环中运行它,你可以分开范围

答案 1 :(得分:0)

request是异步调用,因此此过程被推送到事件队列,该队列将在当前调用堆栈完成后运行。 console.log打印undefined,因为这是未分配变量的默认值。

如果需要从异步调用中返回值,则必须使用回调或promise。以下是使用Promise

的示例
function parseLink(link) {
  return new Promise((resolve, reject) => {
    request(link, function(error, response, body) {
      if (error) return reject(error);

      if (response.statusCode !== 200) {
        return reject(new Error('Not OK'));
      }

      var $ = cheerio.load(body);

      var title = $('h1').text() || $('title').text();
      var description = $('meta[name="description"]').attr('content');
      var product = new Product(link.trim(), title.trim(), description.trim());

      resolve(product);
    });
  });
}

parseLink('http://example.com')
  .then(product => {
    console.log(product);
  })
  .catch(error => {
    console.error(error);
  });