一天时间迅速准备前端面试,快速构建初级前端知识体系

2022/6/20 天下无鱼

源链接:https://coding.imooc.com/class/400.html (opens new window)

快速搞定前端技术一面 匹配大厂面试要求

迅速建立初中级前端面试(0 ~ 2年)JS 知识体系 掌握解决面试题的思路与技巧

双越:BAT 资深面试官针对时下面试高频考点,帮你解决面试问题。课程不局限于讲解单一知识点,而是以面试官的角度出发,带你了解前端面试中每个 “门道” 与 “套路”。手把手带你分析考点及解答策略,梳理 JS 考试体系。

# 1. 课程介绍【说说面试的那些事儿】

  • 关于面试:基层工程师 -- 基础知识;高级工程师 -- 基础知识 + 项目经验;架构师 -- 解决方案能力。
  • 关于基础:工程师的自我修养 -- 基础知识;扎实的基础能让你高效学习新技术。
  • 拿到一个面试题,第一时间看到 -- 考点。面对题海看准考点。
  • 什么是知识体系:结构化的知识范围,结构化、有组织、易扩展

# 2. 面试前的准备【要知己知彼,不打无准备之仗】

  • 投递简历的几种方式:员工内推、猎头推荐、HR 主动收集。
  • 面试的主要环节:一面、二面(交叉面)、三面、HR 面。
  • JD 分析:Job Description。职位描述、岗位要求。

# 3. CSS 面试题【不多说了,前端面试 CSS 是必考知识,不过关直接回家】

  • 如何理解 HTML 语义化:让人更容易读懂,增加代码可读性; 让搜索引擎更容易读懂(SEO)。
  • margin 负值问题:margin-top 负值,元素向上移动;margin-bottom 负值,下方元素向上移动;margin-left 负值,元素向左移动;margin-right 负值,右侧元素向左移动
  • 布局:BFC、float、flex。
  • 定位:absolute、relative、fixed、垂直居中对齐。
  • line-height 的继承:px -- 直接继承;比例 -- 比例 * 自己的 font-size;百分比 -- 百分比 * 父元素的 font-size。
  • 响应式:window.innerWidth === 100vwwindow.innerHeight === 100vh

# 4. JS 基础-变量类型和计算【不会变量,别说你会 JS】

  • typeof 能判断的类型:undefined、string、number、boolean、Symbol、【function】、object
  • instanceof:用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。instanceof 是基于原型链实现的。【只能判断出引用数据类型和自定义引用数据类型,不能判断基本数据类型】
  • Object.prototype.toString.call(new Error("自定义错误")).slice(8, -1); // 输出 Error
  • 函数(function)是特殊引用类型,但不用于存储数据,所以没有 “拷贝、复制函数” 这一说。
  • 手写深拷贝。
  • 注意某些类型转换的坑:字符串拼接、==、if 语句和逻辑运算 -- &&、||
  • truly 变量:!! a === true;falsely 变量:!! a === false

# 5. JS 基础-原型和原型链【三座大山之一,必考!!!】

  • 如何用 class 实现继承。
  • [] instanceof Array --> true[] instanceof Object --> true
  • typeof Class --> functionclass 实际上是函数,可见是语法糖。
  • 如何理解 JS 原型:隐式原型:xiaowen.__proto__ === 显式原型:People.prototype

# 6. JS 基础-作用域和闭包【三座大山之二,不会闭包,基本不会通过】

  • 作用域:全局作用域、函数作用域、块级作用域(ES6 新增)。
  • 自由变量:一个变量在当前作用域没有定义,但被使用了;向上级作用域一层一层寻找;如果到全局作用域都没找到,则报错。在函数定义时查找。
  • 闭包:作用域应用的特殊情况,有两种表现:函数作为参数被传递、函数作为返回值被返回。存在自由变量查找规则。任何闭包的使用场景都离不开这两点:创建私有变量、延长变量的生命周期。【闭包是指那些能够访问自由变量的函数。 自由变量是指在函数中使用的,但既不是函数参数也不是函数的局部变量变量
  • this 的取值是在函数执行时决定的。
  • 手写 bind / call / apply 函数:
// bind
Function.prototype.myBind = function () {
  // 将参数拆解成数组
  const args = Array.prototype.slice.call(arguments);
  // 获取 this (数组的第一个元素)
  const t = args.shift();
  // 调用 myBind 的函数
  const self = this;
  // 返回一个函数
  return function () {
    return self.apply(t, args);
  }
}

// call
Function.prototype.myCall = function (context) {
  if (typeof this !== "function") {
    throw new Error("Type error");
  }
  // 首先获取参数
  let args = [...arguments].slice(1);
  let result = null;
  // 判断 context 是否传入,如果没有传就设置为 window
  context = context || window;
  // 将被调用的方法设置为 context 的属性
  // this 即为我们要调用的方法
  context.fn = this;
  // 执行要被调用的方法
  result = context.fn(...args);
  // 删除手动增加的属性方法
  delete context.fn;
  // 将执行结果返回
  return result;
};

// apply
Function.prototype.myApply = function (context) {
  if (typeof this !== "function") {
    throw new Error("Type error");
  }
  let result = null;
  context = context || window;
  // 与上面代码相比,我们使用 Symbol 来保证属性唯一
  // 也就是保证不会重写用户自己原来定义在 context 中的同名属性
  const fnSymbol = Symbol();
  context[fnSymbol] = this;
  // 执行要被调用的方法
  if (arguments[1]) {
    result = context[fnSymbol](...arguments[1]);
  } else {
    result = context[fnSymbol]();
  }
  delete context[fnSymbol];
  return result;
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
  • 实际开发中闭包的应用:隐藏数据、做一个简单的 cache 工具。
  • 注意以下 let 位置的不同:
let a
for (let i = 0; i < 10; i++) {
  a = document.createElement('a')
  a.innerHTML = i + '<br>'
  a.addEventListener('click', function (e) {
    e.preventDefault()
    alert(i)
  })
  document.body.appendChild(a)
}

let i, a
for (i = 0; i < 10; i++) {
  a = document.createElement('a')
  a.innerHTML = i + '<br>'
  a.addEventListener('click', function (e) {
    e.preventDefault()
    alert(i)
  })
  document.body.appendChild(a)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 7. JS 基础-异步【三座大山之三,必考!!!】

  • 同步和异步有何不同:基于 JS 是单线程语言;同步会阻塞代码执行;异步不会阻塞代码执行。
  • 异步的应用场景:网络请求、定时任务。
  • Promise:是异步编程的一种解决方案,解决 callback hell。
Promise.resolve('foo');
// 等同于
new Promise(resolve => resolve('foo'));

Promise.reject('出错了');
// 等同于
new Promise((resolve, reject) => reject('出错了'));
1
2
3
4
5
6
7
  • JS 是单线程运行的,异步要基于回调来实现

# 8. JS 异步进阶【想要进大厂,更多异步的问题等着你】

  • event loop:事件循环,事件轮询。就是异步回调的实现原理。callback queue
  • DOM 事件和 event loop 的关系:DOM 事件也是使用回调,基于 event loop。回调 --> 异步 --> event loop
  • DOM 渲染和 event loop 的关系:JS 的执行和 DOM 渲染公用一个线程。先尝试 DOM 渲染,再进行 event loop。微任务在 DOM 渲染前,宏任务在 DOM 渲染后(微任务执行早于宏任务的原因,使用 appendChild / alert 做实验)。
  • Promise 有哪三种状态:pending、fulfilled、rejected。【1】变化不可逆。【2】resolved 触发后续 then 回调,rejected 触发后续 catch 回调。【3】then 和 catch 影响状态的变化:then、catch 正常返回 resolved,里面有报错则返回 rejected
  • async-await 语法:是同步语法,彻底消除回调函数,处理异步编程的最终方案。【1】执行 async 函数,返回的是一个 Promise 对象。【2】await 相当于 Promise then。【3】try...catch 可捕获异常,代替 Promise 的 catch。【4】await 后面的代码,即下一排的代码开始,都可以看作是 callback 里面的内容,即异步,会启动 event loop。
  • for...of 常用于异步的遍历,for...in、for、forEach 是常规的同步遍历。
function multi(num) {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(num * num);
    }, 1000)
  })
}
const nums = [1,2,3];
;(async function () {
  for (let i of nums) {
    // 在 for...of 循环体的内部,遇到 await 会挨个串行计算
    const res = await multi(x);
    console.log(res);
  }
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  • 宏任务和微任务。

# 9. JS-Web-API-DOM【学会 DOM,才能具备网页开发的基础】

  • JS 基础知识,规定语法(ECMA 262 标准);JS Web API,网页操作的 API(W3C 标准)。前者是后者的基础,两者结合才能真正实际应用。
  • DOM 本质:Document Object Model,本质是一棵树。
  • DOM 节点操作:获取节点、attribute(修改 html 属性,会改变 html 结构)、property(修改对象属性,不会体现到 html 结构中)。
  • DOM 结构操作:新增/插入节点、获取子元素列表(nodeType、nodeName)、获取父元素、删除子元素。
  • 优化 DOM 操作的性能:避免频繁的 DOM 操作(document.createDocumentFragment())、对 DOM 查询做缓存(document.getElementsByTagName('p').length)。

# 10. JS-Web-API-BOM【内容虽然不多,但是你不能不会】

  • BOM:Browser Object Model。知识点 -- navigator、screen、location、history
  • 如何识别浏览器类型:navigator.userAgent
  • 分析拆解 url 各个部分:location

# 11. JS-Web-API-事件【事件不会,等于残废,必考!必考!】

  • 事件绑定:element.addEventListener('', event => { })
  • 事件冒泡:event.preventDefault()
  • 事件代理:依赖于事件冒泡。

# 12. JS-Web-API-Ajax【每个工程师必须熟练掌握的技能】

  • AJAX 全称 (Async Javascript and XML) 即异步的 JavaScriptXML,是一种创建交互式网页应用的网页开发技术,可以在不重新加载整个网页的情况下,与服务器交换数据,并且更新部分网页。【1】优点:页面无刷新,用户的体验非常好;使用异步方式与服务器通信;把一些服务器负担的工作转嫁到客户端处理;被广泛的支持。【2】缺点:破坏了浏览器前进和后退机制(因为 ajax 自动更新机制);对搜索引擎的支持比较弱;安全性问题不太好(可以用数据加密解决)。
  • XMLHttpRequest:ajax 的核心 API。
const xhr = new XMLHttpRequest();
// true 表示异步
xhr.open('GET', 'https://api.github.com/users/diego3g', true);
xhr.onreadystatechange = function () {
  if (xhr.readyState === 4) {
    if (xhr.status === 200) {
      console.log(xhr.responseText);
    }
  }
}
xhr.send(null);
// post 请求
// xhr.send(JSON.stringify({ foo: 'foo' }));
1
2
3
4
5
6
7
8
9
10
11
12
13
  • 浏览器的同源策略:协议、域名(指向主机)、端口,只有这三个完全相同的 URL 才能称之为同源(安全)。加载图片、css、js 可无视同源策略。
<img src='跨域的图片地址' />
<link href='跨域的css地址'/>
<script src='跨域的js地址'> <script/>
1
2
3
  • 实现跨域的常见方式:JSONP、CORS。【1】JSONP:<script> 可绕过跨域限制、服务器可以任意动态拼接数据返回。【2】CORS:服务器设置 http header。【3】Proxy:使用在开发环境中。
  • 解决跨域问题实际上改的是 http 里面哪个参数:header -- Access-Control-Allow-Origin。

# 13. JS-Web-API-存储【内容虽然不多,但不可不会】

  • cookie:document.cookie = 'a=100' 是一个追加的效果,而不是替换。缺点:存储大小,最大 4KB;请求时需要发送到服务端,增加请求数据量;不方便修改。
  • localStorage、SessionStorage:HTML5 专门为存储而设计,最大可存 5M;API 简单易用,setItem / getItem;不会随着 http 请求被发送出去。

# 14. http 面试题【前后端分离的时代,网络请求是前端的生命线】

  • http 状态码:【1】状态码分类:1xx -- 服务器收到请求、2xx -- 请求成功、3xx -- 重定向、4xx -- 客户端错误、5xx -- 服务端错误;【2】常见状态码:200、301 永久重定向、302 临时重定向、304 资源未修改使用缓存、403 没有权限、404、500、504 网关超时;【3】关于状态码的协议与规范:就是一个约定。
  • http methods:post(create)、delete(delete)、patch / put(update)、get(select)。
  • Restful API:一种新的 API 设计方法(早已推广使用)。传统 API 设计把每个 url 当作一个功能,Restful API 设计把每个 url 当作一个唯一的资源。如何设计成一个资源:尽量不用 url 参数,用 method 表示操作类型。
  • http headers:【1】request headers -- Accept / Accept-Encoding / Accept-Language / Connection / Cookie / Host / User-Agent / Content-type;【2】response headers -- Content-type / Content-length / Content-Encoding / Set-Cookie。【3】缓存相关的 headers -- Cache-Control / Last-Modified / Etag。
  • http 缓存:【1】什么是缓存:当浏览器向服务器请求资源的时候,都会率先抵达浏览器缓存,如果浏览器有这个资源请求的副本,就可以直接从浏览器获取资源,而不用去请求服务器;【2】为何需要缓存:为了提高网页打开速度,减少请求次数,降低服务器压力;可以被缓存的静态资源 js css img;【3】缓存策略:强制缓存、协商缓存;【4】强制缓存:Cache-Control -- max-age / no-cache,在 response headers 中,代替比较老的 Expires;【5】协商缓存:服务器端缓存策略,服务器判断客户端资源是否和服务端资源一样,一致则返回 304 否则返回 200 和新资源。请求和响应的时候带着资源标识,在 response headers 中,有两种 Last-Modified、Etag(优先使用)。
  • 刷新页面对 http 缓存的影响:【1】正常操作 -- 地址栏输入 url / 跳转链接 / 前进后退:强制缓存有效,协商缓存有效;【2】手动刷新 -- F5 / 点击刷新按钮:强制缓存失效,协商缓存有效;【3】强制刷新 -- ctrl + F5:强制缓存失效,协商缓存失效。

# 15. 开发环境【不会这些,你就会被认定是菜鸟小白,没做过项目】

  • 前端开发常用的开发工具:git、调试工具、抓包、webpack / babel、linux 常用命令
  • git:代码版本管理工具,熟悉常用命令。
  • chrome 调试工具:Elements、Console、Debugger、Network、Application。
  • 抓包工具:fiddler。
  • 配置 webpack / babel:@babel/core(@ 表示一个组)。
  • 如何配置 webpack 生产环境:"build": "webpack --config webpack.prod.js"
  • ES6 模块化规范:import、export。

# 16. 运行环境【这些会了,你就可以飞了】

  • 运行环境:浏览器、nodejs。

  • 网页加载过程:加载渲染。【1】从输入 url 到渲染出页面的整个过程:DNS 解析、浏览器发起 http 请求、服务器处理 http 请求返回资源、解析 HTML、生成 DOM 树、CSSOM、渲染;【2】window.onload(不靠谱) 和 DOMContentLoaded(推荐在此过程中执行 JS 代码):window.onload 是页面的全部资源加载完才会执行,包括图片视频;DOMContentLoaded 是 DOM 渲染完即可执行,图片视频可能没有加载完。

    img.onload = () => {};
    window.addEventListener("load", () => {});
    document.addEventListener("DOMContentLoaded", () => {});
    
    1
    2
    3
  • 性能优化:原则是,多使用内存、缓存;减少 CPU 计算量;减少网络加载耗时。【1】加载更快:减小资源体积 -- 压缩代码;减少访问次数 -- 合并代码;缓存;SSR;CDN。【2】渲染更快:css 放在 head,js 放在 body 最下面;尽早执行 js;懒加载;减少对 DOM 的频繁操作 -- 缓存 DOM 查询结果,多次 DOM 操作的合并。

  • 节流、防抖:手写。

// throttle
const div = document.getElementById('div');
function throttle(fn, delay = 200) {
  let timer = null;
  return function () {
    if (timer) {
      return;
    }
    timer = setTimeout(() => {
      fn.apply(this, arguments);
      timer = null;
    }, delay);
  }
}
div.addEventListener('drag', throttle(function (e) {
  console.log(e.offsetX, e.offsetY);
}));

// debounce
const input = document.getElementById('input');
function debounce(fn, delay = 500) {
  // timer 是闭包中的
  let timer = null;
  return function () {
    if (timer) {
      clearTimeout(timer);
    }
    timer = setTimeout(() => {
      fn.apply(this, arguments);
      timer = null;
    }, delay);
  }
}
input.addEventListener('keyup', debounce((e) => {
  console.log(e.target);
  console.log(input1.value);
}, 1000));
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
  • 安全:【1】XSS 跨站脚本攻击:通过嵌入 <script> 脚本,注入恶意代码,进行控制和获取数据;使用替换特殊字符来预防,Cookie 设置 http-only 后 JS 无法获取 Cookie。【2】XSRF 跨站请求伪造:利用身份验证的漏洞,使用 post 接口 / 增加 token 验证来预防。

# 17. 课程总结【很有必要带你避免面试犯低级错误】

  • 面试技巧。

# 18. 真题模拟【我是来告诉你答案是什么】

  • 手写深度比较:
// 判断是否是对象或数组
function isObject(obj) {
  return typeof obj === 'object' && obj !== null
}
// 全相等(深度)
function isEqual(obj1, obj2) {
  if (!isObject(obj1) || !isObject(obj2)) {
    // 值类型(注意,参与 equal 的一般不会是函数)
    return obj1 === obj2
  }
  if (obj1 === obj2) {
    return true
  }
  // 两个都是对象或数组,而且不相等
  // 1. 先取出 obj1 和 obj2 的 keys ,比较个数
  const obj1Keys = Object.keys(obj1)
  const obj2Keys = Object.keys(obj2)
  if (obj1Keys.length !== obj2Keys.length) {
    return false
  }
  // 2. 以 obj1 为基准,和 obj2 一次递归比较
  for (let key in obj1) {
    // 比较当前 key 的 val —— 递归!!!
    const res = isEqual(obj1[key], obj2[key])
    if (!res) {
      return false
    }
  }
  // 3. 全相等
  return true
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
  • 函数声明和函数表达式:函数声明会在代码执行前预加载,函数表达式不会。
// 函数声明
function fn () {}
// 函数表达式
const fn = function () {}
1
2
3
4
  • new Object() 和 Object.create() 的区别:
new Object() 等同于 {},原型 Object.prototype
Object.create(null),没有原型
Object.create({...}),可以指定原型
1
2
3
  • 正则表达式。
  • 如何捕获 JS 中的异常:try...catch...finally / window.onerror
  • window.requestAnimationFrame():MDN (opens new window)
  • CI / CD:Continuous Integration -- 持续集成 、Continuous Delivery -- 持续交付、Continuous Deployment -- 持续部署。
Last Updated: 2023/04/22, 23:39:26
彩虹
周杰伦