使用回调参数获取匿名函数中的值

时间:2018-07-28 01:08:09

标签: javascript asynchronous callback asynccallback

我遇到了以下代码的回调函数。我了解代码,但无法解决。似乎太违反直觉了。

function greet(name,callback1){
    callback1(name)
}
greet("John Cena", function (somerandomName) {
    console.log(somerandomName);
    return someRandomName;
}); // Output is John Cena and undefined. 

这是我从代码中所了解的:

  1. 我们定义一个函数greet,该函数带有2个参数namecallback1。然后我们说callback1的参数是name。我们没有在greet函数中返回任何内容,为什么?

  2. 当我们调用greet函数时,我们将第二个参数作为匿名函数传递,其参数为someRandomName。然后我们console.log(someRandomName)。 我添加了返回someRandomName,但是此返回不起作用,我得到了打印的语句,后跟 undefined

有人可以用简单的话解释一下吗,这似乎太违反直觉了。

4 个答案:

答案 0 :(得分:2)

因此,我认为了解函数本身可以作为参数很重要。

在此示例中,您传递了一个字符串作为第一个参数,然后传递了一个以该字符串作为参数作为第二个参数的函数。

函数并不总是需要返回某些东西。函数通常可能会对dom执行操作,获取数据,配置某些内容或更改现有变量。当然,如果需要的话,您可以退货。

像您一样增加回报并没有多大作用。为了实际返回名称值,您必须编写这样的原始函数。

function greet(name,callback1){
    return callback1(name)
}

那么你可以做这样的事情

var wrestler = greet("John Cena", function (somerandomName) {
    console.log(somerandomName);
    return somerandomName;
});

console.log(wrestler) // prints John Cena

这有点奇怪,因为它没有实际用途。这样的事情可能会帮助您了解发生了什么。

    function greet(name, callback) {
      callback(name)
    }

    greet('John Cena', function(name){
      console.log('Hello ' + name) // prints Hello John Cena
    })

   OR return something and use it to manipulate dom

   function greet(name, callback) {
      return callback(name)
   }

   var greeting = greet('John Cena', function(name){
     return 'Hello ' + name
   })

   document.getElementById('message').innerHTML = greeting

   // somewhere in HTML...
   <h1 id='message'></h1>

无论哪种方式,至少我们现在都在对第一个参数做一些事情。回调可以做的事情是无限的。

回调是javascript的基本功能。当函数的第一部分是异步的(例如对api或数据库的调用)时,它们会发挥作用。在这种情况下,第一部分将是对数据库的调用,并且在从初始调用中获取值之前不会触发回调。最近,由于Promises,这种回调模式的使用量有所减少,但回调仍然有用。

因此是一个从前端到后端的通用api调用示例。通常,这可以使用Fetch Api或通过Request或Axios之类的库来完成。请记住,调用端点的第一个函数需要花费一些时间来执行和获取数据。在返回该数据之前,不会触发回调。当然,后端会有一个将错误或数据发送回回调的函数。我不想让事情变得过于复杂,而只是想知道回调通常用于什么。

function getDataFromBackend(endPoint, callback) {
  callback(error, data)
}

getDataFromBackend('/api/user', function(error, data) {
  if (error) {
    // handle error - show user error message in ui, etc
  }
   // do something with data - such as display welcome message to user, etc
})

我建议使用回调进行练习。我发现当我使用Node或使用前端和后端构建应用程序时,我会实现很多回调,因为发生了很多异步通信。希望我回答了你的问题。

答案 1 :(得分:1)

首先,您拥有return someRandomName,但您的参数称为somerandomName。变量区分大小写;这就是为什么您的返回值与您想要的不同。

您的问题是,为什么我们不返回greet函数中的任何内容。答案是“我不知道”。您 可以 返回某些内容。一些函数返回东西;有些功能没有。这与这里的回调安排无关。

function greet(name,callback1){
    return callback1(name)
}
var finalResult = greet("John Cena", function (someRandomName) {
    console.log(someRandomName);
    return someRandomName;
});

现在finalResult将是"John Cena"

如果在使用匿名函数的任何地方都提供帮助,则可以轻松使用命名函数。 (在实践中通常比较丑陋,但是为了理解这些概念...)

function greet(name,callback1){
    return callback1(name)
}
function myGreeterFunction(someRandomName) {
    console.log(someRandomName);
    return someRandomName;
});
var finalResult = greet("John Cena", myGreeterFunction);

在这种情况下,现在更容易看出callback1(name)与说myGreeterFunction(name)是同一件事。

答案 2 :(得分:1)

这是JavaScript的一种过时的方法,您完全正确,因为它反直观。在这个特定的示例中,使用callback编写代码没有任何优势,可能应该作为一个承诺来编写

greet("John Cena")
    .then(() => {
        return 'Next Action'
    })
    .then(nextAction => {
        console.log(nextAction)
    })

正如@ mark-meyer所指出的,如果您有一个异步事件,则需要这种方法。

实际上, AWS Lamda 函数实际上有一个可选 callback定义为它的第三个参数。 exports.myHandler = function(event, context, callback) {}。坦率地说,我认为这只能涵盖不许基于第三方库的情况。

尽管将callback传递给函数可能永远都不是正确的方法,但在某些情况下,将function传递给function是有价值的。也许在 pub / sub 系统中。

const events = {}

function subscribe (event, func) {
    if (events[event]) {
        events[event].push(func)
    } else {
        events[event] = [func]
    }
}

function publish (event) {
    if (events[events]) {
        events[event].forEach(func => func())
    }
}

如果您使用fp中的RamdaJs方法链接进行编写,链接功能将是编写内容的重要组成部分。

@ pi2018清除了一些内容吗?

答案 3 :(得分:0)

一般技术称为continuation-passing style –与direct style形成对比。

该技术确实允许出现一些有趣的程序。下面,我们有两个普通函数addmult。我们使用cont编写了两个程序,这使我们可以将这些函数串在一起,其中每一步都是 之前一个的延续。

const cont = x => k =>
  cont (k (x))
  
const add = x => y =>
  x + y
  
const mult = x => y =>
  x * y
  
cont (1) (add (2)) (mult (3)) (console.log) // 9
//    1 ->
//        x => 2 + x
//        cont (3) ->
//                  x => 3 * x
//                  cont (9) ->
//                             x => console.log (x)
//                             cont (undefined)

我们可以根据需要对任意数量的操作进行排序–

const cont = x => k =>
  cont (k (x))
  
const add = x => y =>
  x + y
  
const mult = x => y =>
  x * y

cont (2) (mult (2)) (mult (2)) (mult (2)) (mult (2)) (console.log) // 32
//    2 -> 
//        x => 2 * x
//        cont (4) ->
//                   x => 2 * x
//                   cont (8) ->
//                              x => 2 * x
//                              cont (16) ->
//                                         x => 2 * x
//                                         cont (32) ->
//                                                    x => console.log (x)
//                                                    cont (undefined)

可以使用连续传递样式来实现并发程序,但是JavaScript现在提供了更好的本机并发原语Promise。甚至还提供了新的asyncawait语法,使Promises的使用更加容易。

正如Wikipedia所指出的那样,连续传递样式在编译器中使用较多,在程序员中则较少。如果您尝试编写并发程序,我强烈建议您改用Promises。更高版本的Node包括util.promisify,它允许用户将继续传递样式功能转换为Promise-returning异步功能。