先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7
深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新Web前端全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。






既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上前端开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
如果你需要这些资料,可以添加V获取:vip1024c (备注前端)

正文
先给出柯里化的定义:在数学和计算机科学中,柯里化是一种将使用多个参数的一个函数转换成一系列使用一个参数的函数的技术。
柯里化的定义,理解起来有点费劲。为了更好地理解,先看下面这个例子:
function sum (a, b, c) {
console.log(a + b + c);
}
sum(1, 2, 3); // 6
毫无疑问,sum 是个简单的累加函数,接受3个参数,输出累加的结果。
假设有这样的需求,sum的前2个参数保持不变,最后一个参数可以随意。那么就会想到,在函数内,是否可以把前2个参数的相加过程,给抽离出来,因为参数都是相同的,没必要每次都做运算。
如果先不管函数内的具体实现,调用的写法可以是这样: sum(1, 2)(3); 或这样 sum(1, 2)(10); 。就是,先把前2个参数的运算结果拿到后,再与第3个参数相加。
这其实就是函数柯里化的简单应用。
sum(1, 2)(3); 这样的写法,并不常见。拆开来看,sum(1, 2) 返回的应该还是个函数,因为后面还有 (3) 需要执行。
那么反过来,从最后一个参数,从右往左看,它的左侧必然是一个函数。以此类推,如果前面有n个(),那就是有n个函数返回了结果,只是返回的结果,还是一个函数。是不是有点递归的意思?
网上有一些不同的柯里化的实现方式,以下是个人觉得最容易理解的写法:
function curry (fn, currArgs) {
return function() {
let args = [].slice.call(arguments);
// 首次调用时,若未提供最后一个参数currArgs,则不用进行args的拼接
if (currArgs !== undefined) {
args = args.concat(currArgs);
}
// 递归调用
if (args.length < fn.length) {
return curry(fn, args);
}
// 递归出口
return fn.apply(null, args);
}
}
解析一下 curry 函数的写法:
首先,它有 2 个参数,fn 指的就是本文一开始的源处理函数 sum。currArgs 是调用 curry 时传入的参数列表,比如 (1, 2)(3) 这样的。
再看到 curry 函数内部,它会整个返回一个匿名函数。
再接下来的 let args = [].slice.call(arguments);,意思是将 arguments 数组化。arguments 是一个类数组的结构,它并不是一个真的数组,所以没法使用数组的方法。我们用了 call 的方法,就能愉快地对 args 使用数组的原生方法了。在这篇 细说call、apply以及bind的区别和用法 中,有关于 call 更详细的用法介绍。
currArgs !== undefined 的判断,是为了解决递归调用时的参数拼接。
最后,判断 args 的个数,是否与 fn (也就是 sum )的参数个数相等,相等了就可以把参数都传给 fn,进行输出;否则,继续递归调用,直到两者相等。
测试一下:
function sum(a, b, c) {
console.log(a + b + c);
}
const fn = curry(sum);
fn(1, 2, 3); // 6
fn(1, 2)(3); // 6
fn(1)(2, 3); // 6
fn(1)(2)(3); // 6
都能输出 6 了,搞定!
理解了柯里化的实现之后,让我们来看一下它的实际应用。柯里化的目的是,减少代码冗余,以及增加代码的可读性。来看下面这个例子:
const persons = [
{ name: ‘kevin’, age: 4 },
{ name: ‘bob’, age: 5 }
];
// 这里的 curry 函数,之前已实现
const getProp = curry(function (obj, index) {
const args = [].slice.call(arguments);
return obj[args[args.length - 1]];
});
const ages = persons.map(getProp(‘age’)); // [4, 5]
const names = persons.map(getProp(‘name’)); // [‘kevin’, ‘bob’]
在实际的业务中,我们常会遇到类似的列表数据。用 getProp 就可以很方便地,取出列表中某个 key 对应的值。
需要注意的是,const names = persons.map(getProp('name')); 执行这条语句时 getProp 的参数只有一个 name,而定义 getProp 方法时,传入 curry 的参数有2个,obj 和 index(这里必须写 2 个及以上的参数)。
为什么要这么写?关键就在于 arguments 的隐式传参。
const getProp = curry(function (obj, index) {
console.log(arguments);
// 会输出4个类数组,取其中一个来看
// {
// 0: {name: “kevin”, age: 4},
// 1: 0,
// 2: [
// {name: “kevin”, age: 4},
// {name: “bob”, age: 5}
// ],
// 3: “age”
// }
});
map 是 Array 的原生方法,它的用法如下:
var new_array = arr.map(function callback(currentValue[, index[, array]]) {
// Return element for new_array
}[, thisArg]);
所以,我们传入的 name,就排在了 arguments 的最后。为了拿到 name 对应的值,需要对类数组 arguments 做点转换,让它可以使用 Array 的原生方法。所以,最终 getProp 方法定义成了这样:
const getProp = curry(function (obj, index) {
const args = [].slice.call(arguments);
总结
大厂面试问深度,小厂面试问广度,如果有同学想进大厂深造一定要有一个方向精通的惊艳到面试官,还要平时遇到问题后思考一下问题的本质,找方法解决是一个方面,看到问题本质是另一个方面。还有大家一定要有目标,我在很久之前就想着以后一定要去大厂,然后默默努力,每天看一些大佬们的文章,总是觉得只有再学深入一点才有机会,所以才有恒心一直学下去。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:vip1024c (备注前端)

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
g.csdnimg.cn/img_convert/718310d106ab948d6f467d78e08b1aed.png)
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:vip1024c (备注前端)
[外链图片转存中…(img-ChuVKC4w-1713269308961)]
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
3113



被折叠的 条评论
为什么被折叠?



