刷面试题
刷题的重要性,不用多说。对于应届生或工作年限不长的人来说,刷面试题一方面能够尽可能地快速自己对某个技术点的理解,另一方面在面试时,有一定几率被问到相同或相似题,另外或多或少也能够为自己面试增加一些自信心,可见适当的刷题是很有必要的。
开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
-
前端字节跳动真题解析
-
【269页】前端大厂面试题宝典
最后平时要进行自我分析与评价,做好职业规划,不断摸索,提高自己的编程能力和抽象思维能力。大厂面试远没有我们想的那么困难,摆好心态,做好准备,你也可以的。
我们来看上面的定义,闭包就是一个内部函数,所以这里就是指的 inner 函数。那么它的外部函数呢?这里当然指的就是全局执行环境啦,全局执行环境就是 js 代码整个的执行环境,模拟一下
(function global(){
var a = 1;
function inner(){
a = a + 1;
return a;
}
inner() // 2
})()
怎么样,这样就能看出是一个闭包了吧。当然,正常的闭包应该是下面这种方式
let global = ‘outer’
function outer(){
let global = ‘inner’;
let a = 5;
function inner(){
console.log(global)
console.log(a++);
}
return inner;
}
var b = outer();
// 执行完这一步 b = inner
b(); // inner 5;
b(); // inner 6;
这就是一个正常的闭包了,我们来分析一下
首先,outer() 代表运行这个函数,并返回结果 inner,这里就是将这个结果赋值给 b。
然后执行 b,其实执行的就是 inner,我们看看执行 inner 会发生什么,首先打印 global,但是函数内部没有啊?那怎么办,其实跟上面一样,刚刚是什么找到 a 的,现在就怎么找 global,只不过多加了一层函数而已,所以这里就在 outer 函数内部找到了 global,那么 outer 函数外部的 global 呢。这里就和原型链一样了,返回的是找到的第一个值。那么对于 a++ 呢,第一次返回 5 也没有问题,第二次呢?一般情况下,如果函数里面的变量没有继续被引用的话就会被销毁,但是我们考虑这么一个情况,还是第一个函数
var a = 1;
function inner(){
a = a + 1;
return a;
}
inner() // 2
console.log(a); // 2
这里的 a 会被销毁吗,不会,为什么,因为 js 主线程一直在运行,所以这个 a 一直存在。对应到上面的 b,正常情况下,outer 函数执行完以后,内部的 global,a,inner 应该都会被销毁的,但是这里为什么没有被销毁呢。我们对比上面的例子。b 引用了外部的 a,outer 内部的 global 变量,所以导致这个变量保存了下来。
用一句简单的话来说,内部函数调用时保存了外部参数的值并能在后续中维持这些参数。当然这么说不严谨,但是这么理解应该没什么问题。
闭包这个函数有如下几个可访问的作用域
-
在它自身声明之内的变量
-
全局变量
-
包含闭包函数的函数里面的变量,这里也就是 a 和 global
如果觉得还是不太清楚的话,可以留言,我后面会详细的讲一下。
4.2 真实的高阶函数(续)
有了对闭包的理解,我们可以实现一些真实有用的高阶函数
4.2.1 tap 函数
由于我们要在函数式编程中处理很多函数,因此需要一种调试方式。
下面实际一个名为 tap 的简单函数。tap 函数接受一个 value 并返回一个包含 value 的闭包函数,该函数将被执行
const tap = (value) => {
(fn) => (
(typeof(fn) === ‘function’ && fn(value)),
console.log(value)
)
}
这里用到了逗号表达式,逗号表达式就是计算逗号前面的值,并返回后面的值,例如
var a = 1;
// 先计算 a++,然后返回 a + 2
var b = (a++,a+2);
console.log(b) // 4
将 tap 函数改成 ES5 的语法即
var tap = function(value){
return function(fn){
return (
// 这句话的意思其实就是如果 fn 是函数的话,计算 fn(value),然后打印 value,否则直接打印 value
(typeof(fn) === ‘function’ && fn(value)),
console.log(value)
)
}
}
// 使用 tap 函数
tap(‘fun’)((it) => console.log(‘value is’,it))
// value is fun
// fun
// 参数不是函数,直接打印 value
tap(‘fun’)()
// fun
在这里分享一个很巧妙的运用逗号表达式的例子
‘helloworld’.split(‘’).reduce((p,k) => ((p[k]++||(p[k]=1)),p),{})
效果如下
按顺序统计出了各个字符的出现次数。为什么呢?首先,我们将它改成非箭头函数
‘helloworld’.split(‘’).reduce(function(p,k){
return (p[k]++||(p[k]=1)),p
},{})
首先,reduce 的第二个参数代表初始值,即这里为 {}。然后进行操作,如果当前字符存在,则 ++,否则则令当前字符为1,即 p[k]++||(p[k]=1)
,然后就是精髓的逗号,最后实际返回的是 p 对象。以上。
4.2.2 unary 函数
接下来我们看另一个函数
有这么一个例子相信大家都遇到过
[‘1’,‘2’,‘3’].map(parseInt);
// [1,NaN,NaN]
为什么会这样呢,因为 parseInt 接受两个参数,第一个要转换的字符串,第二个是按几进制转换(如果为 0 或者没有默认以 10 进制转换),而这里,map 的第二个参数 index 会默认作为 parse 的第二个参数,所以就产生了上面的结果,那么我们该怎么只传一个参数进去呢?这就是我们这节要讲的 unary 函数
unary 函数接受一个给定的多参数函数,并把它转换成一个只接受一个参数的函数
const unary = (fn) => {
return fn.length === 1 ? fn : (arg)=>fn(arg)
}
我们检查传入的 fn 是否有一个长度为 1 的参数列表,如果有,就什么也不做。如果没有,就返回一个函数,它只接受一个参数 arg,并用该参数调用 fn
让我们试一下
[‘1’,‘2’,‘3’].map(unary(parseInt));
// [1, 2, 3]
总结
-
框架原理真的深入某一部分具体的代码和实现方式时,要多注意到细节,不要只能写出一个框架。
-
算法方面很薄弱的,最好多刷一刷,不然影响你的工资和成功率😯
-
在投递简历之前,最好通过各种渠道找到公司内部的人,先提前了解业务,也可以帮助后期优秀 offer 的决策。
-
要勇于说不,对于某些 offer 待遇不满意、业务不喜欢,应该相信自己,不要因为当下没有更好的 offer 而投降,一份工作短则一年长则 N 年,为了幸福生活要慎重选择!!!
喜欢这篇文章文章的小伙伴们点赞+转发支持,你们的支持是我最大的动力!