Javascript 匿名函数中变量的作用域

Javascript 匿名函数中变量的作用域,javascript,function,scope,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 =

我有这个函数

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(product)时,我得到了未定义的,但在内部,我可以看到我的产品

我在javascript中学习了很多关于作用域的知识,但我不理解,因为我在top函数中定义了product。 我需要返回这个变量,以便在另一个函数中获取它,如果在内部执行返回请求,我当然有一个未定义的,所以我需要在外部执行该操作。。。
谢谢

javascript不会运行类似于
c
php
的代码,在这些代码中,您可以确保在上一行代码准备就绪时运行下一行代码。在您的例子中,
request
是一个异步函数,因此这两行

console.log(product);
return product;
通常在
请求
功能准备就绪之前运行。在这种情况下,您不能仅从
parseLink
函数返回一些值。这里有两种可能性:

  • 使用承诺:

  • 使用回调:

  • 像这样:

    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:回调的使用在imo中要容易得多,但在某些情况下,您可以分离作用域,例如,如果您在
    for
    循环中运行它,则
    请求是一个异步调用,因此此过程被推送到事件队列,该队列将在当前调用堆栈完成后运行
    console.log
    打印
    未定义的
    ,因为这是未分配变量的默认值

    如果需要从异步调用返回值,则必须使用回调或承诺。下面是一个使用的示例:


    因为您没有在top函数和
    console.log()
    中为变量
    product
    赋值,所以不要等待请求函数的赋值。您的
    request
    函数定义的位置可能重复?谢谢,但我需要返回值,如
    var linkParsed=parseLink(数据[0])var linkParsed=parseLink(数据[0])就像我写的那样,不可能直接从异步函数返回值。在我回答的最后是一个带有回调函数的示例。米格尔还提供了一个承诺人的例子,那么C呢?您可以在调用中将指向函数的指针作为参数传递,您不知道在该调用返回时函数是否已被调用。谢谢,但我需要返回值,如
    var linkParsed=parseLink(数据[0])谢谢,但我需要返回值,如
    var linkParsed=parseLink(数据[0])
    @Tech您需要执行同步请求,但强烈建议不要这样做
    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);
      });