从零起步,真正理解 Javascript 回调函数
Posted SegmentFault
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了从零起步,真正理解 Javascript 回调函数相关的知识,希望对你有一定的参考价值。
本文转载于 SegmentFault 社区
前言
对于它的了解,只知道在微信的网页授权用到了回调,以及在 Angular 中可以用观察者模式进行 .subscribe 订阅,但对于它原理的理解,却是一团浆糊。直到昨天开会时,突然被问到回调函数的知识,我才意识到自己真的不理解。
一
基础知识:JavaScript 标准写法
1. 如何测试 JS 代码
2. JS 定义函数
说明:这里的"函数"相当于面向对象的"方法"
/* 定义名为test的函数
传入的参数是a
功能:输出传入的变量 */
var test = function(a){
console.log(a);
};
//调用方法,输出HelloWorld
test('helloworld');
3. 函数调用函数
/* 定义函数sum
传入两个参数a,b
作用:求a,b的和 */
var sum = function(a,b)
{
return a+b;
};
/* 定义函数test
调用sum
传入参数1,2 */
var test = function()
{
result = sum(1,2);
console.log(result);
}
//调用test,启动程序
test();
二
数据和算法
var test = function( ){
console.log("HelloWorld");
};
一个函数里面,既有算法又有数据:"算法"指的是输出字符串的这个操作,"数据"这的是输出的内容 'HelloWorld' 。所以如果我们想让这个函数发挥作用,就要让它可以变化。
1. 改变数据——普通的函数
//写死的函数
var test = function( ){
console.log("HelloWorld");
};
test();
//加上参数
var test = function(string){
console.log(string);
};
test('HelloWorld');
2. 改变算法——回调函数
把一个写死的函数变活,可以传入数据,用相同的算法对不同的数据进行处理;当然也可以传入一个算法,用不同的算法对相同的数据进行处理,而后者,正是回调函数。
//函数1
var test = function(abc){
console.log(abc);
};
//函数1的调用
test('HelloWorld');
//函数2
var test = function(abc){
abc('Helloworld');
};
//函数2的调用
test( function(words) {console.log(words);} );
而函数 2 是回调函数,参数是作为算法传入的,然后用传进来的这个函数 abc 来操作 'HelloWorld' 这个字符串。
而回调函数,参数是函数,在调用 test() 时,传入输出字符串的方法,那么 abc 就是输出字符串的方法,test 函数将会用传进来的输出字符串的方法对一个固定字符串 HelloWorld 执行操作。与此同时,这个 HelloWorld 字符串,又成了传到 test 函数的这个 function(words) {console.log(words);} 函数的参数,如果传入的参数有名字的话,在调用 test 时,在函数内部,等价于发生了如下操作:
{
//调用test传进来一个函数之后,abc就是那个函数
abc = function(words) {console.log(words);};
//用abc操作字符串,'HelloWorld'变成了传进来的函数的参数
abc('HelloWorld');
}
三
深入回调函数
//以下两种写法等价
function (words) {console.log(words);}
(words) => {console.log(words);}
这种省略写法更贴近生产环境:
//函数2
var test = function(abc){
abc('Helloworld');
};
//函数2的调用
test( (words) => {console.log(words);} );
1. 了解参数的对应关系
//
var test = function(abc, def){
abc('HelloWorld1', 'HelloWorld2');
def('HelloWorld1', 'HelloWorld2');
};
//
test((words1,words2) => {
console.log('我是箭头1,我输出'+words1);
console.log('我是箭头1,我输出'+words2);
},
(words1,words2)=> {
console.log('我是箭头2,我输出'+words1);
console.log('我是箭头2,我输出'+words2)
}
);
四
回调函数嵌套
//普通函数
var test = function(abc){
console.log(abc);
}
//回调函数
var test = function(abc){
abc('HelloWorld');
};
//回调函数嵌套
var test = function(abc){
abc( (def) => {console.log(def);} );
}
练习题:问,以上三种情况下,如果分别调用三个函数,输出 HelloWorld 字符串?
//普通函数
test('HelloWorld');
//回调函数
test( (words) => {console.log(words);});
而再看回调函数嵌套,它也是传进去一个函数 abc,但不同的是,它是用这个传进来的函数去操作另一个函数。
此时,我们传入的 abc 函数需要一种可以接收函数的能力,而不再是接收变量的能力。
所以怎么办?——在传进去的这个函数 abc 中再使用一次回调,使得 abc 接收的参数是一个函数,而不是一个变量:
//回调函数嵌套
test( (aFunction) => {aFunction('HelloWorld')} );
//如果看不明白,把箭头函数复原,如下
test( function(aFunction) {aFunction('HelloWorld')});
成功输出了结果:
五
图解具体步骤
abc = function(aFunction) {aFunction('HelloWorld')}
aFunction = Function(def){console.log(def);}
def = 'HelloWorld';
六
生产环境中的观察者
//向8080端口的helloWorld路径发起请求
httpClient.get('http://localhost:8080/helloWorld')
.subscribe(
function success(data) {
console.log('请求成功');
console.log(data);
},
function error(data) {
console.log('请求失败');
console.log(data);
});
· .get 设定请求地址。
· .subscript 是设定请求完成的操作。
既然变量就在那里放着不动,我们只需要想办法,去操作这个状态的变量就可以了,——传入两个函数, success 和 error ,在请求成功之后调用 success ,如果失败调用 error 。再次强调,它已经有数据了,我们传进去的是函数,请求完毕后,就会用我们传入的函数去操作这个请求状态。我们传入的“输出”,他就“输出”这个状态!
//向8080端口的helloWorld路径发起请求
httpClient.get('http://localhost:8080/helloWorld')
.subscribe(
function success(data) {
console.log('请求成功');
console.log(data);
},
function error(data) {
console.log('请求失败');
console.log(data);
});
//系统中的subscirbe函数
function subscribe(success,error)
{
request_success;//请求是否成功
request_data;//请求数据
if (request_success == 1) {
success(request_data);
}
else{
error(request_data);
}
}
七
总结
以上是关于从零起步,真正理解 Javascript 回调函数的主要内容,如果未能解决你的问题,请参考以下文章