首先声明:“面向函数”是飞哥“自定义”的一个说法,算是一种借用,和面向过程/面向对象并列,便于记忆和理解,但并不严谨。
类似的、主流的说法是函数式编程,但和我想表达的内容还是有一些差距。
一般我们认为变量是一种数据,函数是一种操作。
数据是可以传递的,比如变量赋值、函数传参之类的。
但操作呢?操作/动作/行为能不能传递?……
随着编程语言的发展(当然根源是开发的需要),现代编程语言普遍允许将函数也视为(或类似于)一种值或变量,可以传递。
随之产生了各种各样的语法现象:
但为什么需要?不搞明白这个问题,你越学越晕!需求:找出数组中满足某种条件的数。
某种条件,可以是大于0,于是你的代码就是:
for (let i = 0; i < numbers.length; i++) { if(numbers[i]>0){ //就筛选条件变化着的 console.log(numbers[i]); }//else nothing }
也可能是奇数,那么你的代码就是:
for (let i = 0; i < numbers.length; i++) { if(numbers[i]%2==1){ //就筛选条件变化着的 console.log(numbers[i]); }//else nothing }
注意:这两段代码我们进行了复制粘贴:
(格言:程序员厌恶复制粘贴。)
然后只改了一点点……
以后还可能是其他任何稀奇古怪的要求,比如能同时被3和5整除……
我们能不能把这些代码重用一下?
经过观察,我们发现,上述代码中唯一不同的就是筛选条件,假如我们把两段代码封装成一个方法,把筛选条件作为一个变量/参数……
PS:这就有点“封装变化”的味道了
JavaScript变量就可以直接被函数赋值:
let where = function(number){ return number > 0; }等号右边就是一个函数,只是没有名字,所以被称之为匿名函数。
被函数赋值之后,where就变成了一个函数变量,实际上也就是一个函数。演示:
既然where是变量,那么就可以被重新赋值:
where = function(number){ return number % 2 == 1; }甚至把命名函数赋值给where也是没有问题的:(注意:是alert不是alert(),没有圆括号)
对的,JavaScript就这么任性(但强烈不建议!)
综上,就可以封装这么一个filter函数:
function filter(numbers, where){ //参数where是一个回调函数 for (let i = 0; i < numbers.length; i++) { if(where(numbers[i])){ //where被作为函数直接使用 console.log(numbers[i]); }//else nothing } }
把函数作为参数,传递给另外一个函数,作为参数的函数就被称之为回调函数。
调用filter时,既可以传递一个(命名)函数名,也可以是函数变量,
filter([1, 8, -13, 21, -9], where) //注意where后面没有圆括号甚至还可以是匿名函数:
filter([1, 8, -13, 21, -9], function(number){ return number<0;} )
……时光飞逝……
本质上,Lambda就是一个匿名函数。而且省略掉了function/delegate关键字,引入了一个箭头
以JavaScript为例:
let where = (number) => { return number > 0; }
然后,再引入一些简写规则:
let where = number => { //一个参数可以不加() let where = () => { //但没有参数也要保留圆括号() let where = () => alert('一行代码省略花括号'); let where = (number) => number > 0; //连return也省略了
根据变量的作用域规则,lambda表达式中可以使用其外部的变量:
let number = 10; let where = () => { return number > 0; }
这就是(广义上的)闭包。
如果:这个使用了外部变量lambda表达式,是作为一个方法的返回值:
function find() { let number = 10; return () => { return number > 0; } }这就会形成(狭义上的)闭包,从而产生一个结果:
lambda表达式延长了number的生命周期。
断点演示:
为什么是#常见面试题#:在早期的JavaScript中,使用var定义变量,会带来一些“莫名其妙”的问题……
重用,只是“函数做变量”的一个作用。事件机制,才是它的必然。
正常调用:我要实现某个功能,需要某个函数(我知道这个函数干嘛的),于是我开开心心的去调用它。
但回调:
为什么要搞得这么复杂?
编程开发的事件里,比如点击一个按钮,就可以触发了一个事件(event)。类似的还有:移动鼠标、右键、按下键盘……都可以触发事件。
按钮是谁做的?以后你们就会知道:按钮是浏览器厂商做好的,我们只需要简单的声明就可以生成:
<button>我是按钮</button>但是,浏览器厂商的开发人员在生成这个按钮的时候(一样要写代码),
怎么办?在线等,挺急的……
就让button暴露一个click事件(算了,我通俗点……)。大致对话内容如下:
当然是函数了:
function welcome(){ alert("一起帮·源栈课堂欢迎您!") }
这个函数就是回调函数,因为它会被作为参数传递给button:
<button onclick="welcome()">我是按钮</button>在button被点击时调用(注意:不是一声明就调用)
多快好省!前端后端,线上线下,名师精讲
更多了解 加: