【面试】2021前端校招笔记

274 阅读17分钟

HTML 部分

结构

一个 HTML 文档的基本结构如下:

<!DOCTYPE html>
<html lang="en">
  <head>
    <!--页面的字符集-->
    <meta charset="utf-8" />
    <!--页面的头文件-->
    <meta http-equiv="expires" content="31 Dec 2008" />
    <!--页面的描述信息-->
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <!--用于SEO的描述信息-->
    <meta name="description" content="..." />
    <meta name="keywords" content="..." />
    <meta name="author" content="..." />
    <meta name="copyright" content="..." />
    <!--页面的标题-->
    <title>Document</title>
    <!--页面的外部资源-->
    <link rel="stylesheet" type="text/css" href="theme.css" />
    <!--页面的样式信息-->
    <style></style>
  </head>
  <body>
    <!--客户端脚本-->
    <script></script>
    <!--客户端不支持脚本时的替代显示内容-->
    <noscript>浏览器不支持JavaScript脚本时的说明文字</noscript>
  </body>
</html>

标签

标签分类

根据闭合特征,标签分为闭合标签非闭合标签。其中,闭合标签如<html></html>,非闭合标签如<br />

根据换行特征,标签分为块级元素行内元素。其中,块级元素独占一行,具有宽、高等盒模型相关的 CSS 属性,从上到下排布,块级元素宽度继承自父元素宽度,高度由元素本身内容决定;行内元素和其它行内元素同占一行,不能被直接被定义宽、高等盒模型相关的 CSS 属性,如margin属性和padding属性仅影响元素水平方向上的排布,行内元素宽度和高度均有元素本身内容决定。

新增标签

HTML5 中新增了如下标签:

<!--多媒体(视频和音频)-->
<video controls>
  <source src="test.ogg" type="video/ogg" />
  <source src="test.mp4" type="video/mpeg" />
  浏览器不支持video标签
</video>
<audio controls>
  <source src="test.ogg" type="audio/ogg" />
  <source src="test.mp3" type="audio/mpeg" />
  浏览器不支持audio标签
</audio>

<!--进度条-->
<progress value="22" max="100"></progress>

<!--画布-->
<canvas></canvas>

<!--语义化-->
<header>
  <nav></nav>
</header>
<main>
  <article></article>
  <strong></strong>
</main>
<footer></footer>

存储

HTML5 中新增了CookieWebStorageSeesionStorageLocalStorage),它们的对比如下:

  • Cookie:在客户端和服务端之间来回传递,大小不超过 4KB。在所有同源窗口中共享,过期前均有效(有效期通过expires字段或max-age字段进行设置)。在控制台输入window.document.cookie,可以查看当前Cookie的值,其形式为由键值对组成的字符串,如name1:value1; name2:value2; ...。服务端通过set-cookie响应字段以设置Cookie;客户端通过cookie请求字段以发送Cookie
  • LocalStorage:仅存储在客户端,大小最大为 5MB。在所有同源窗口中共享,浏览器关闭后仍不失效。绑定在window.localStorage上。客户端通过window.localStorage.setItem()/getItem()/removeItem()/clear()来管理LocalStorage
  • SeesionStorage:仅存储在客户端,大小最大为 5MB。仅在当前窗口中有效,浏览器关闭后即失效。绑定在window.sessionStorage上。客户端通过window.sessionStorage.setItem()/getItem()/removeItem()/clear()来管理sessionStorage

CSS 部分

属性

CSS3 中新增了如下属性:

  • 盒模型类:box-sizing等。
  • 边框类:border-radiusbox-shadow等。
  • 背景类:background-sizebackground-origin等。
  • 变换类:transform等。
  • 动画类:animation等。

选择器

略。

盒模型

CSS3 中,将元素们看作一个个盒子,盒子包含外边距、边框、内边距和宽高成分。

CSS3 中的盒模型分为以下两种:

  • 标准盒模型:盒子 = 元素自身
  • 怪异/IE 盒模型:盒子 = 边框 + 内边距 + 元素自身

切换盒模型的方法如下:

.box {
  box-sizing: content-box; /* 标准盒模型 */
  box-sizing: border-box; /* 怪异盒模型 */
}

定位

CSS3 中包含以下几种定位:

.box {
  position: static; /*静态*/
  position: relative; /*相对*/
  position: absolute; /*绝对*/
  position: fixed; /*固定*/
  position: sticky; /*粘性*/
}

BFC

BFC 是一个将元素内外隔开的容器,可用于解决 margin 塌陷(父子元素之间)和 margin 合并(兄弟元素之间)的问题。

触发 BFC 的方法如下:

.bfc {
  /*1.overflow属性不为visible*/
  overflow: auto;
  overflow: scroll;
  overflow: hidden;
  /*2.float属性不为none*/
  float: left;
  float: right;
  /*3.position属性为absolute或fixed*/
  position: absolute;
  position: fixed;
  /*4.display属性为flex、inline-flex和inline-block等*/
  display: flex;
  display: inline-flex;
  display: inline-block;
}

响应式布局

Flex 布局

请见此文

Table 布局

略。

媒体查询

媒体查询是指根据某些属性设计多种样式方案的过程:

/*当页面宽度小于300px时有效*/
@media screen and (max-width: 300px) {
  body {
    background-color: lightblue;
  }
}

常见问题

清除浮动

利用clear属性或通过触发 BFC 来清除浮动:

.clear {
  clear: both;
  overflow: auto;
  overflow: hidden;
}

垂直居中

利用 Flex 布局、padding属性、margin属性和transform属性等可实现垂直居中。

JavaScript 部分

数据类型

JavaScript 中的数据类型划分如下:

  • 基本类型:UndefinedNullBooleanNumberStringSymbol
  • 引用类型:Object

使用typeof可以对数据的基本类型进行判断:

// 返回其基本类型
typeof undefined; // 'undefined'
typeof true; // 'boolean'
typeof 42; // 'number'
typeof 9007199254740992n; // "bigint"
typeof '42'; // 'string'
typeof Symbol(); // 'symbol'
typeof {}; // 'object'
typeof []; // 'object'
typeof new Map(); // 'object'
typeof new Set(); // 'object'
// null和函数例外
typeof null; // 'object'
typeof function () {}; // 'function'

使用toString可以获取数据的内部类型:

// 包装toString方法
function toString(obj) {
  return Object.prototype.toString.call(obj);
}
// 内部类型判断
toString(null); // '[object Null]'
toString(undefined); // '[object Undefined]'
toString(true); // '[object Boolean]'
toString(42); // '[object Number]'
toString('42'); // '[object String]'
toString(Symbol()); // '[object Symbol]'
toString({}); // '[object Object]'
toString([]); // '[object Array]'
toString(new Map()); // '[object Map]'
toString(new Set()); // '[object Set]'
toString(new Date()); // '[object Date]'
toString(/regex-literal/i); // '[object RegExp]'
toString(function () {}); // '[object Function]'

作用域和执行上下文

原型链和继承

事件循环、宏任务和微任务

**事件循环(Event Loop)**是一种保证 JavaScript 单线程运行却不会阻塞的机制,它将任务分为以下 2 种:

  • 同步任务:按顺序执行的任务。
  • 异步任务:不按顺序、延迟一段时间才执行的任务。

同步任务和异步任务的执行流程如下:

  1. 如果遇到同步任务,则将其放入到主线程中执行;如果遇到异步任务,则将其放入 Event Table 中并注册相应的回调函数。
  2. 主线程中的同步任务的执行过程中,如果 Event Table 中有异步任务完成(如计时器计时完成),则将相应的回调函数放入 Event Queue 中。
  3. 当主线程中没有可执行的同步任务时,就会到 Event Queue 中寻找是否有可执行的回调函数,如果有,则执行。

异步任务又被进一步地分为以下 2 种:

  • 宏任务(Macro Task):整体代码、setTimeoutsetInterval
  • 微任务(Micro Task)Promise.thenprocess.nextTick

宏任务和微任务的执行流程如下:

  1. 宏任务的回调函数会被放入宏任务的 Event Queue 中,微任务的回调函数会被放入微任务的 Event Queue 中。
  2. 当主线程中没有可执行的同步任务时,优先执行微任务的回调,再执行宏任务的回调。

无论如何,在同一轮事件循环中,异步任务晚于同步任务执行,而异步任务中宏任务晚于微任务执行。

另外,通过以上可知:

  • setTimeout(fn,0)的含义为:立即将fn放入 Event Queue 中,待主线程为空时执行。
  • setInterval(fn,n)的含义为:每过n毫秒,将fn放入 Event Queue 中,待主线程为空时执行。

异步编程

常见问题

this 指向及其改变

请见此文此文

事件委托、冒泡和捕获

请见此文

函数防抖和节流

函数防抖是指函数在被调用后等待一定时间再执行回调,若函数在一定时间内又被调用,则重新计时。

// 利用定时器实现:
function debounce(func, delay) {
  let timer;
  return function (params) {
    // 如果被重复调用,则重新计时
    if (timer) clearTimeout(timer);
    timer = setTimeout(() => {
      func(params);
    }, delay);
  };
}

函数节流是指函数在一定时间内只能被调用一次,若函数在一定时间内被调用多次,则只有一次生效。

// 利用定时器实现:
function throttle(func, delay) {
  let timer;
  return function (params) {
    if (timer) return;
    timer = setTimeout(() => {
      func(params);
    }, delay);
  };
}
// 利用时间戳实现:
function throttle(func, delay) {
  let prev;
  return function (params) {
    // 设置当前时间
    let now = new Date();
    // 在单位时间过后被调用
    if (!prev || now - prev > delay) {
      func(params);
      prev = now;
    }
  };
}

函数柯里化

请见此文

Vue 框架

原理

响应式原理:为每个属性定义 setter/getter 和一个依赖收集器 dep,并在 getter 中收集依赖,在 setter 中更新依赖。每一个组件对应一个依赖 watcher。当 render 时,触发 getter 收集依赖;当数据更新时,遍历该属性的 dep 中的 watcher 们,通知其重新渲染组件。

vue-diff 原理:将 node 抽象成 vnode,更新时,不是直接将 vnode 转换成 node 并覆盖旧 node,而是对旧 vnode 树和新 vnode 树进行比较,且比较只会在同层级进行,不会跨层级比较。且两个 vnode 的 key 和 sel 相同才去比较它们

模板语法

常用指令:

v-once
v-show v-if v-for
v-bind v-model v-on
v-text v-html

自定义指令:

// 全局指令
Vue.directive('directive-name', {
  bind() {}, // 绑定时
  update() {}, // 值更新时
  unbind() {}, // 解绑时
  inserted(el, binding) {}, // 插入到父节点(DOM)时
  componentUpdated() {}, // vnode更新时
});
// 局部指令
Vue.component('component-name', {
  directives: {
    'directive-name'() {},
  },
});

组件

  • 组件注册。
  • 组件配置:propscomponentdatamethodswatchcomputedfiltersdirectives
  • 组件通信:props$emit
  • 组件生命周期。
  • 组件复用:插槽、混入等。

过渡和动画

生态

VueRouter

  • hash 模式:不会向服务端发送请求,hash 值变化时,会触发 hashChange 事件,并将 hash 值发生的变化记录下来。
  • history 模式:利用 History 的 pushState 和 replaceState 方法改变 url,且不发送请求,如此一来抛弃了丑陋的#,但是不支持刷新,除非服务端支持(使所有请求指向同一个 html 文件)。
const router = new VueRouter({
  mode: 'history | hash',
  routes: [
    {
      path: '/user/:id',
      name: 'User',
      component: User,
      meta: {},
      beforeEnter(to, from, next) {},
    },
  ],
  beforeEach(to, from, next) {},
  beforeResolve(to, from, next) {},
  afterEach(to, from, next) {},
});

export default {
  name: 'Component',
  beforeRouteEnter(to, from, next) {},
  beforeRouteUpdate(to, from, next) {},
  beforeRouteLeave(to, from, next) {},
};

this.$router.push({
  // =>'/user'
  name: 'User',
  // =>'/user?id=ke'
  params: {
    id: 'ke',
  },
  // =>'/user/ke'
  query: {
    id: 'ke',
  },
});
this.$route.params;
this.$route.query;

Vuex

const store = new Vuex.Store({
  // this.$store.state
  state: {},
  // 触发:this.$store.commit(mutationName,payload)
  // 用于直接改变state,必须同步
  mutations: {
    mutationA(state, payload) {},
  },
  // 触发:this.$store.dispatch(actionName,payload)
  // 可以异步
  actions: {
    async actionA(context, payload) {
      // context.state
      // context.commit(mutationName,payload)
      // context.dispatch(actionName,payload)
      await actionB();
    },
  },
});

常见问题

computed 和 watch

  • watch:不支持缓存,建立对数据的依赖,依赖变则触发操作。
  • computed:支持缓存,间接建立对数据的依赖,依赖变则重新计算。

$nextTick

在数据更新后,DOM 不会立即更新。通过$nextTick可以获取更新后的 DOM:

this.$nextTick(() => {
  const ref = this.$refs;
});

Vue3 的改进

最大的改变,使用 es6 中的 Proxy 来代替 Object.defineProperty,在目标对象之上架了一层拦截,代理的是对象而不是对象的属性。这样可以将原本对对象属性的操作变为对整个对象的操作,可以监听到对象属性的增删和数组长度的变化,还可以监听 Map,Set,WeakSet,WeakMap 等,同时实现了惰性监听,即不会再初始化的时候创建所有的 observer,而是会在用到的时候才去监听。

const targetWithProxy = new Proxy(target, {
  get(target, key) {},
  set(target, key, val) {},
});

前端工程化

Babel

@babel/core
@babel/traverse
@babel/polyfill

babel-loader

过程:

  1. 解析:词法分析,语法分析,获取 AST。
  2. 转换:遍历并转换 AST。
  3. 生成:将修改后的 AST 复原成代码。

Webpack

module.exports = {
  mode: 'development',
  entry: '',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'bundle.js',
  },
  // 文件加载器
  module: {
    rules: [
      { test: /\.css/, use: ['style-loader', 'css-loader'] },
      { test: /\.js/, use: ['babel-loader'] },
    ],
  },
  // 其他作用
  plugins: [
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, 'src', 'index.html'),
      title: '首页',
    }),
  ],
};

性能优化

可以从以下几个方面进行前端性能优化:

  • 传输:使用 Webpack 合并资源,减少 HTTP 请求。使用 gzip 压缩传输内容。
  • 缓存:利用 HTTP 强缓存和协商缓存,以及将离线数据缓存到 localStorage 中。
  • 渲染:调整 HTML 文档顺序,如将样式表放在文档顶端,将脚本放在文档底端。
  • 其它:慎用闭包,防止内存泄漏。尽量减少全局变量的定义。尽量避免对 DOM 和样式的直接操作。

网络和安全

从输入 URL 到页面显示的过程

从用户输入 URL 到页面显示这一期间,依次经历了以下流程:

  1. 通过 DNS 服务器将域名解析为 IP 地址(优先级为:浏览器缓存>系统缓存>路由器缓存>运营商缓存>根域名服务器>顶级域名服务器)。
  2. 客户端与服务端之间经过三次握手,建立 TCP 连接。
  3. 客户端发送 HTTP 请求至服务端。
  4. 服务端处理 HTTP 请求,并将响应结果返回至客户端。
  5. 客户端与服务端之间经过四次挥手,关闭 TCP 连接。
  6. 浏览器解析 HTML 文档,生成 DOM 和 CSSOM,并结合这两者构建渲染树。
  7. 浏览器基于构建好的渲染树,经过回流重绘,完成页面的渲染和布局。

GET 与 POST 请求对比

GET 请求和 POST 请求的对比如下:

  • 参数传递:GET 请求通过 URL,POST 请求通过请求体。
  • 参数长度:GET 请求有,POST 请求无。
  • 安全表现:GET 请求参数暴露在 URL 中,不如 POST 请求安全。
  • 编码类型:GET 请求仅支持 URL 编码,POST 请求支持application-xxxx-www-form-urlencodemultiple/form-data等多种编码格式。
  • 记录保留:GET 请求会被完整的保留在历史记录中,而 POST 请求不会被保留。
  • 数据传输:两者本质上都是 TCP 链接,但 GET 请求产生一个 TCP 数据包(发送请求-返回 200 状态码和资源),POST 请求产生两个 TCP 数据包(发送请求头-返回 100 状态码-发送请求体-返回 200 状态码和资源)。

状态码

HTTP 中的状态码由三个十进制数字组成,其中,第一个数字定义了状态码的类型。

状态码的分类如下:

  • 1xx:服务端处于临时响应状态,等待客户端的进一步请求。
  • 2xx:服务端处理请求成功。
  • 3xx:请求重定向。
  • 4xx:客户端发出的请求存在问题。
  • 5xx:服务端处理请求时内部发生错误。

常见的状态码及其解释如下:

  • 101:服务端正在进行协议升级的请求,如将连接类型升级到 WebSocket。
  • 200:服务端处理请求成功,并通知客户端缓存响应内容。
  • 204:服务端处理请求成功,但客户端无需更新现有页面。
  • 301:永久重定向,即客户端请求的资源已经被移动到了另一位置,搜索引擎会根据 Location 响应头进行修正。
  • 302:临时重定向,即客户端请求的资源被暂时地移动到了另一位置,搜索引擎不会自动进行修正。
  • 304:协商缓存,详情请见缓存机制相关内容。
  • 400:请求存在语法错误。
  • 403:服务端拒绝请求。
  • 404:服务端找不到请求资源。
  • 408:服务端等待请求超时。
  • 500:服务端处理请求时抛出了错误。
  • 505:服务端不支持请求中的 HTTP 协议版本。

缓存机制

为节约请求消耗与提高网站性能,浏览器会将请求到的资源缓存下来,以供后续直接复用。HTTP 中的缓存机制分为强缓存协商缓存两种,相关介绍如下:

  • 强缓存:借助ExpiresCache-Control这两个响应字段进行控制。其中,Expires为一个时间戳,表示缓存有效截止时间,如果为0则表示资源已经过期,当缓存失效时,将自动进入协商缓存阶段;Cache-Control为一系列键值对,包含有表示缓存有效时间的max-age属性和表示是否禁用强缓存的no-cache属性,结合max-age属性和Date响应字段,可以计算出强缓存的有效截止时间。Cache-Control的优先级高于Expires
  • 协商缓存:当强缓存过期或者请求头设置不使用强缓存时,将进入协商缓存阶段。协商缓存涉及两对字段:(1)If-Modified-SinceLaset-Modified字段,如果请求头中携带了If-Modified-Since字段,则会请求服务端校验资源是否发生变化,如果有变化,服务端将正常返回当下最新的资源,并返回 200 状态码;如果没有变化,服务端将返回表示资源有效截止时间的Laset-Modified字段及 304 状态码,客户端收到后将使用缓存资源并更新缓存有效期。(2)If-None-MatchETag字段,两者都是用于充当资源标识符的哈希值,通过对比请求头中的If-None-Match字段和响应头中的ETag字段,能够判断出协商缓存是否过期。

网络模型

OSI七层模型
  应用层:HTTP/HTTPS
  表示层
  会话层
  传输层:TCP/IP协议
  网络层:IP协议
  数据链路层:ARP协议
  物理层:
TCP/IP五层模型
  应用层、表示层、会话层被整合为应用层

TCP 和 UDP

TCP 面向连接,UDP 无连接。 TCP 可靠,UDP 不可靠。 TCP 保证信息完整,UDP 保证信息实时。 TCP 一对一,UDP 一对多。

TCP 三次握手:

  1. 客户端发送 SYN。
  2. 服务端发送 ACK 和 SYN。
  3. 客户端发送 ACK。

TCP 四次挥手:

  1. 客户端发送 FIN。(客户端申请关闭自己)
  2. 服务端发送 ACK。(然后等服务端发送完)
  3. 服务端发送 FIN。(服务端申请关闭自己)
  4. 客户端发送 ACK。

HTTP 和 HTTPS 协议对比

HTTP 各版本区别:

HTTP/1.0默认不开启长连接,HTTP/1.1默认开启
HTTP/1.1可以只发送header
HTTP/2.0不懂

报文格式:

# 请求
GET /baidu.com HTTP/1.1
header1: value1
header2: value2
connection: keep-alive 建立长连接

body

# 响应
HTTP/1.1 200 OK
header1: value1
header2: value2

body

状态码:

1xx 临时响应,请求继续操作
  100 等待继续操作
  101 要求切换协议
2xx 成功
  200 成功
3xx 重定向
  301 永久移动
  302 临时移动
  304 未修改,使用缓存
  305 使用代理
4xx 请求错误
  400 请求错误
  404 无资源
5xx 服务器错误
  500

HTTP 和 HTTPS 区别:

# 区别
安全性 http明文传输,https需要向CA申请证书,且有TLS/SSL加密协议
端口 http用80端口,https用443端口

# TLS/SSL
TLS是SSL的升级版
1. 客户端向服务端发起https请求,连接到服务端的443端口
2. 服务端将自己的公钥和证书发送给客户端,客户端验证证书的合法性,如果合法,生成密钥,并使用公钥来加密密钥
3. 客户端再次发起https请求,将加密后的密钥发送给服务端,服务端收到后,用私钥解密,获取到密钥
4. 服务端用密钥加密数据,并把数据发送给客户端,客户端用密钥解密,得到数据

GET 和 POST 请求,简单请求和复杂请求

GET 和 POST 请求:

参数传递 get通过url,post通过request body
参数长度限制 get有,post无
安全 get参数暴露在url中,不如post安全
编码 get只能url编码,post可多种(application/x-www-form-urlencode、multiple/form-data)
数据包 本质上都是TCP链接,无差别,get直接一次发送header和data,post先发送一次header,等待100后,再发送data

简单请求和复杂请求:

简单请求:
类型为 GET/POST/HEAD
content-type为text/plain、application/x-www-form-urlencoded、multipart/form-data三者之一

其他为复杂请求

跨域

1.cors
access-control-allow-origin
access-control-allow-methods

2.反向代理
proxy pass:
  server {
    listen       80;
    server_name  www.123.com;
    location / {
      proxy_pass http://127.0.0.1:8080;
      index  index.html index.htm index.jsp;
    }
  }

3.JSONP

缓存

客户端请求资源时(强刷新),会先获取该资源缓存的header信息,然后根据cache-control和expires来判断是否过期
  若无过期,则直接从强缓存中获取资源信息
  若已过期,则会向服务端发送请求
    先通过if-none-match发送先前服务端发送过来的etag,服务端对etag进行比对
      如果相同,则if-none-matchfalse,返回304,客户端使用协商缓存
      如果不同,则if-none-matchfalse,返回200,客户端请求新资源
    再通过if-modified-since发送先前服务端发送过来的last-modified,同理

CSRF 和 WXS

WebSocket

ajax 轮询:让浏览器每隔一段时间就发送一次请求,询问服务器是否有新消息。而利用 ajax 实时的从服务器获取内容,有可能导致大量的请求产生。 ajax 长轮询:采用阻塞模型。也就是说,当客户端发起连接后,如果服务器端内容没有更新,将响应至于挂起状态,一直不回复 response 给客户端,知道有内容更新,再返回响应。 WebSocket:是 HTML5 开始提供的一种浏览器与服务器进行全双工通讯的网络技术,属于应用层协议。它基于 TCP 传输协议,并复用 HTTP 的握手通道。一旦 web 服务器和客户端建立起 websocket 协议的通信连接,之后所有的通信都依靠这个专用连接进行。只需要经过一次 HTTP 请求,就可以做到源源不断的信息传送了。通过在请求首部中设置 Connection: Upgrade 来使用 websocket 协议。

数据结构与算法

计算机通识

Git

设计模式

观察者模式:被观察者管理观察者,观察者被动接受通知。 发布订阅模式:在观察者模式的基础上,添加了一个处理中枢。

参考