当然也可以看我的 github 的 issues 欢迎 star!
前言
其实,现在已经总结的够多了,大家可以看看:
- 总结了17年初到18年初百场前端面试的面试经验(含答案)
- (中篇)中高级前端大厂面试秘籍,寒冬中为您保驾护航,直通大厂以及上篇都挺不错的
- JavaScript 算法
- 一个合格的中级前端工程师必须要掌握的 28 个 JavaScript 技巧
但是看过了还是很容易就忘了,还是得自己敲一遍好。就总结一些自己有问题的地方吧
自己遇到以及整理的一些点:
1. this 的指向:
const a = {
count:1,
b:{
count: 2,
getCount: function(){
console.log(this.count);
}
}
}
const getb = a.b.getCount
console.log(getb())
console.log(a.b.getCount()) // 这里要注意不要被迷惑了
理解的话,首先要明确的是 this 是在函数里面,在函数调用时动态指定的,指向当前函数(方法)的执行栈(上下文)。 可以查看 理解 JavaScript 中函数调用和 this
2. 正则匹配判断
一个字符串只由[](){}
这几种构成,要求写一个函数 isMatch(str)
匹配如下格式
(1)({[())]}
(2)([{({[]})})]
,结果返回 boolean
分析:要求有两个
- 它们是成对出现的
[{(
分别都是在}])
的前面 后来的代码实现:
function updateStr(str, reg) {
let isLoop = true;
let result = str;
while (isLoop) {
result = result.replace(reg, (val, str1, str2) => {
val = val.substring(1, val.length - 1);
return val;
});
if (!reg.test(result)) {
isLoop = false;
}
}
return result;
};
function isMatch(str) {
const reg1 = /(\()[\{\}\(\[\]]*(\))/; // 每次匹配一个 (),然后去除
const reg2 = /(\{)[\(\)\{\[\]]*(\})/;// 每次匹配一个 {},然后去除
const reg3 = /(\[)[\[\(\)\{\}]*(\])/;// 每次匹配一个 [],然后去除
const REGS = [reg1, reg2, reg3];
const result = REGS.reduce((total, reg, index) => {
return updateStr(total, reg);
}, str);
return !result;
}
// 测试
let strArray = ['}([(())]){', '{[{([(())])})', '{{[[{([(())])}))'];
let result = strArray.map(val => {
return isMatch(val);
});
console.log(result);
<!--当然在 LeetCode 上也有类似的题目,通过栈的特性来解决的-->
// https://leetcode.com/problems/valid-parentheses/submissions/1
function isMatch(str) {
let map = {
'(': -1,
')': 1,
'[': -2,
']': 2,
'{': -3,
'}': 3
};
let stack = [];
for (let i =0; i < str.length; i++){
if(map[str[i]] < 0){
stack.push(str[i]);
}else{
let last = stack.pop();
if(map[last] + map[str[i]] !==0) return false;
}
}
return stack.length <= 0;
}
3. 实现一个 LazyMan 的对象
要求如下
LazyMan('Tony');
// Hi I am Tony
LazyMan('Tony').sleep(10).eat('lunch');
// Hi I am Tony
// 等待了10秒...
// I am eating lunch
LazyMan('Tony').eat('lunch').sleep(10).eat('dinner');
// Hi I am Tony
// I am eating lunch
// 等待了10秒...
// I am eating diner
LazyMan('Tony').eat('lunch').eat('dinner').sleepFirst(5).sleep(10).eat('junk food');
// Hi I am Tony
// 等待了5秒...
// I am eating lunch
// I am eating dinner
// 等待了10秒...
// I am eating junk food
关键点:
- 实现一个事件队列,每次
shift()
调用一个 - 链式调用
4. 将一维数组通过 pid 转成多维数组:
要求:
const previous = [{
name: "1",
id: 1,
pid: 0
},
{
name: "2",
id: 2,
pid: 1
},
{
name: "3",
id: 3,
pid: 2
}]
const result = [{
name: "1",
id: 1,
pid: 0,
children:[{
name: "2",
id: 2,
pid: 1
}]
},{
name: "3",
id: 3,
pid: 2
}
]
要点:
- 递归
- 判断每一个 item 是否属于 tree 中元素
- 找到它的 parent,并把 item 添加到它的 children 中,返回一个新的 tree
其实就是树的不同表现形式
代码实现可以看这里 codesandbox.io/s/nw5xlozk6…
5. 模拟实现加法器
2个正整数字符串的相加,即 '1'+'19' --> '20',注意考虑超长字符串相加
思路:
- 超级长,不能用 parseInt,它有最大值的限制
Number.MAX_VALUE
- 模拟实现一个十进制的加法器
- 可以扩展支持任意进制的运算
6. AMD,CMD,CommonJs,ES6 Module:解决原始无模块化的痛点
- AMD:requirejs 在推广过程中对模块定义的规范化产出,提前执行,推崇依赖前置
- CMD:seajs 在推广过程中对模块定义的规范化产出,延迟执行,推崇依赖就近
- CommonJs:模块输出的是一个值的 copy,运行时加载,加载的是一个对象(module.exports 属性),该对象只有在脚本运行完才会生成
- ES6 Module:模块输出的是一个值的引用,编译时输出接口,ES6 模块不是对象,它对外接口只是一种静态定义,在代码静态解析阶段就会生成。
7. HTTP 缓存有哪几种?
关键: ETag、CacheControl、Expires 参考 HTTP缓存控制小结
8. 一些 webpack -- 按需加载?构建速度?
参考
9. 翻转二叉树
10. 自己遇到的css梳理
11. js 基础梳理 -- 冴羽大大的blog
12. web 安全
13. 静态资源放置于独立域名之下
- 启用新的一级域名,每次请求浏览器不会携带cookie。这对于cookie内容比较大,并且流量大的网站会省去不少宽带费用。同时这也解惑了为什么不用二三级域名。
- 动静分离。静态资源与动态内容分离,有利于部署于CDN,减轻web服务器压力
- HTTP协议对同一个域名的同时下载线程数有限制。主要是为了优化下载速度,防止同一域名下下载线程数过多,导致下载速度变慢。各个浏览器都会遵守这个规定,但是限制的数目可能不一致。基于这个原因,可将资源部署于不同的域名,以达到最大化并发下载。
- 静态资源独立部署,为全局产品服务。这属于业务划分的范畴了。比如taobao.com和tmll.com都会用到tbcdn.cn上的静态资源,这些资源不必从属于某个产品。
- 接第4点原因,有利于最大化利用客户端缓存。比如访问taobao.com,缓存了tbcdn.cn上的某个js文件,之后再访问tmll.com时,也用到此js文件,不必再从tbcdn.cn上下载,直接用客户端缓存即可。
同时,就已经减轻了每台服务器的压力,服务器越多,每个服务器压力就越小
13. react 相关
查看我的博客
总结
平时学习就要多假设一下,为什么会这样,如果换成那个(那里)又会怎么样,这两者比较起来有什么不同!总之要多总结回顾,你会有不一样的感受