概述
这是我的学习笔记,记录了JavaScript的学习过程,我是有一些Python基础的,因此在学习的过程中不自觉的把JavaScript的代码跟Python代码做对比,以便加深印象。在写博客的时候我会尽量详尽的记录每个知识点。如果你完全没接触过JavaScript,那么这一系列的学习笔记可能会对你有所帮助。
今天主要学习函数,主要是箭头函数、闭包、柯里化、自执行函数、回调函数等内容。
1.箭头函数
箭头函数提供了一种更简洁、更直观的方式来编写函数,特别是在处理简短的函数逻辑时,相比于传统的函数声明或函数表达式,箭头函数在语法上更加简洁,如下代码示例,是传统函数声明:
//传统函数声明
function add(a,b){
return a+b;
}
如下是传统函数表达式
//传统函数表达式
var add2 = function (a, b) {
return a + b;
};
上面的函数都是比较简单的,我们可以采用箭头函数,如下代码示意,箭头函数是匿名函数:
//箭头函数
var add3 = (a, b) => {
return a + b;
};
上面的代码还可以更加简化,如下:
//箭头函数简化,如果箭头函数有返回值,并且只有一行代码,可省略关键字return
const add4 = (a, b) => a + b;
注意上面这种简化写法,只有在函数有返回值,并且只有一行代码的情况下才可以省略关键字return和大括号,如果没有返回值,还是要带大括号,如下代码:
//箭头函数没有返回值不能省略大括号
var greeting = () => {
console.log("hello world");
};
//调用函数
greeting();//后面加小括号表示调用。
2.闭包
闭包是函数里面再定义函数,这样就形成了闭包。内部的函数可以访问外部函数作用域的变量,并且外部函数不暴露内部函数的话,外部无法访问内部函数,只能在函数内部使用,这样就能形成私有的函数,如下代码示例:
//如下定义一个函数,求两个数的平方和,在函数内定义了一个求平方的函数
function squarSum(a, b) {
function squar(x) {
return x * x;
}
return squar(a) + squar(b);
}
console.log(squarSum(2, 3));//调用函数
上面的代码中函数squar是内部的函数,我们是不能调用的,如下代码示例:
console.log(squarSum(2, 3)); //调用外部函数
console.log(squar(5));//访问不到内部函数,提示:Uncaught ReferenceError: squar is not defined
3.高阶函数(Higher-order function)
在闭包中内部函数可以作为返回值返回出去,这样就形成了高阶函数,也就是返回函数的函数。如下代码示例
function person() {
let name1 = "小朋"; //在外部函数里定义变量name1
//在外部函数里定义内部函数getName
function getName() {
return name1; //内部函数可以调用外部函数作用域的变量
}
return getName; //返回函数getName
}
下面我们调用一下这个函数:
//调用函数
let getNa = person(); //调用外部函数,得到的应该是person函数返回的getName函数
console.log(getNa);
上面输出如下内容,可以看到返回的是一个函数,并且把我们定义函数时的注释内容也返回出来了。
ƒ getName() {
return name1; //内部函数可以调用外部函数作用域的变量
}
最后我们再调用一个getNa,如下代码。
console.log(getNa()); //getNa是一个函数,后面加小括号表示调用,输出:小朋
这样的话,我就相当于给name1设置了只读属性,只能访问它的值,不能修改它的值,从而起到保护作用。
4.柯里化(curry)
柯里化(Currying)是将一个接受多个参数的函数转换成一系列函数,每个函数都接受一个单一参数,并返回一个新的函数,直到所有参数都被处理并返回最终结果。这种转换使得我们可以分步传递参数给函数,而不是一次性传递所有参数。
如下代码示例,我们先定义一个普通函数,求三个数的和,我们调用普通函数的时候直接把三个数传入。
//普通函数
function addTreeNums(a, b, c) {
return a + b + c;
}
console.log(addTreeNums(1, 2, 3));
上面的函数可以写出柯里化函数,如下代码:
//柯里化函数
function addTreeNumsCurry(a) {
return function (b) {
return function (c) {
return a + b + c;
};
};
}
console.log(addTreeNumsCurry(1)(2)(3));//柯里化函数调用方式
柯里化函数调用的时候是逐一参数传入,每个都是一个参数,直到全部参数传递完毕,如果我们前两个参数是固定的,我们可以把前两个参数出入后形成一个新的函数,如下代码示例:
//如果前两个变量是固定的,可以先把前两个算出来
let fixedTwo = addTreeNumsCurry(1)(2); //把前两个参数传入,算出来形成一个新的函数,赋值给变量fixedTwo
console.log(fixedTwo(10)); //输出:13
console.log(fixedTwo(20)); //输出:23
console.log(fixedTwo(30)); //输出:33
PS:在Python中是没有内置的柯里化函数,但是我们可以很容易的自己定义柯里化函数,如下代码示例:
# 以下是Python代码
# 定义柯里化函数
def curry(func):
def curried(*args, **kwargs):
if len(args) + len(kwargs) >= func.__code__.co_argcount:
return func(*args, **kwargs)
else:
return lambda *args2, **kwargs2: curried(*(args + args2), **(kwargs | kwargs2))
return curried
# 示例:一个接受三个参数的函数
def add_three_numbers(a, b, c):
return a + b + c
# 柯里化这个函数
curried_add_three_numbers = curry(add_three_numbers)
# 你可以分步调用这个柯里化函数
add_two_numbers = curried_add_three_numbers(1)
add_one_more = add_two_numbers(2)
result = add_one_more(3)
print(result) # 输出:6
# 或者一次性传入所有参数
result2 = curried_add_three_numbers(1, 2, 3)
print(result2) # 输出:6
Python中也有第三方库,直接调用第三方库可以直接定义柯里化函数,如下代码示例:
# 以下是Python代码
# 柯里化函数 借助第三方模块
# from toolz import curry # 这两个第三方模块都可以用,代码是一样的
from funcy import curry # 这两个第三方模块都可以用,代码是一样的
@curry #关键字声明下面的函数是柯里化函数
def addTreeNumsCurry(a,b,c):
return a+b+c
print(addTreeNumsCurry(1)(2)(3))
fixedTwo = addTreeNumsCurry(1)(2)
print(fixedTwo(10))
print(fixedTwo(20))
print(fixedTwo(30))
5.自执行函数
自执行函数,函数定义完之后直接调用它自己,外部是无法访问到的,防止被篡改,内部自己形成了作用域,防止和外面的变量命名冲突。如下代码示例:
let num1 = 10; //在函数外定义变量num1
//匿名函数不能做开头,所以圆括号括起来,后面的括号表示调用它自己
(function () {
var num1 = 20; //在函数内定义变量num1
console.log(num1);
})(); //增加小括号表示调用它自己 返回结果为 20
console.log(num1); //无法访问函数内的变量,返回的是函数外的变量,返回10
PS:在Python中没有与它相对应的概念,lambda函数跟它类似,但是功能及用法不一样。
6.回调函数
回调函数(Callback Function)指的是一个通过函数指针调用的函数。具体来说,回调函数是将函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,就称之为回调函数。这句话可能不好理解,我们来看下面代码示例及注释:
//定义函数request,cd形参是一个函数
function request(cd) {
console.log("请求数据");
cd(); //cd后面加上括号表示调用函数,这里也就回调的位置
console.log("请求结束");
}
//定义函数callback
function callback() {
console.log("执行回调");
}
//调用函数request,把callback函数作为参数传入
request(callback);
/*
以上代码运行结果:
请求数据
执行回调
请求结束
*/
上面的代码还可以将callback函数也可以传入参数,代码改写成如下:
//定义函数request2,cd形参是一个函数
function request2(cd) {
console.log("请求数据");
cd("成功"); //cd后面加上括号表示调用函数,括号的内容为实参,这里也就回调的位置
console.log("请求结束");
}
//定义函数callback2
function callback2(result) {
console.log("执行回调");
console.log("执行结果是:" + result);
}
//调用函数request2,把callback2函数作为参数传入
request2(callback2);
/*
以上代码运行结果:
请求数据
执行回调
执行结果是:成功
请求结束
*/
上面的代码也可以写出箭头函数的形式,缺点是不能复用,如下:
//改写成箭头函数,缺点是不能复用
function request3(cd) {
console.log("请求数据");
cd("成功");
console.log("请求结束");
}
request3((result) => {
console.log("执行回调");
console.log("执行结果是:" + result);
});
以上便是今天的学习内容,如果对你有所帮助,请点个赞再走吧。