✏️ 前端基础知识整理

juejin.cn/post/684490…

一、HTML & CSS

布局,比如单位、盒模型、定位、响应式布局等知识点。

1、HTML

1.1 如何理解 HTML 语义化?

  • 让人更容易读懂(增加代码可读性)。
  • 让搜索引擎更容易读懂,有助于爬虫抓取更多的有效信息,爬虫依赖于标签来确定上下文和各个关键字的权重(SEO)。
  • 在没有 CSS 样式下,页面也能呈现出很好地内容结构、代码结构

1.2 script标签为什么要放在底部

因为浏览器在渲染html的时候,从上到下依次执行,遇到js文件就会停止当前页面的渲染,转而去下载js文件,如果将script标签放在头部,如果文件又很大的情况下,首屏时间就会延长,影响用户体验

1.3 script 标签中 defer 和 async 的区别?

推荐文章:图解 script 标签中的 async 和 defer 属性

  • script :阻碍 HTML 解析,下载好并执行完脚本才会继续解析 HTML。

  • async script :解析 HTML 过程中进行脚本的异步下载,下载成功立马执行,有可能会阻断 HTML 的解析。

  • defer script:完全不会阻碍 HTML 的解析,解析完成之后再按照顺序执行脚本。 image.png

2、CSS

2.1 CSS 选择器、优先级

推荐文章:

内联 > ID选择器 > 类选择器 > 标签选择器

样式的优先级一般为 !important > style > id > class

优先级是由 ABCD 的值来决定的,其中它们的值计算规则如下:

  • 如果存在内联样式,那么 A = 1, 否则 A = 0;
  • B 的值等于 ID选择器(#id) 出现的次数;
  • C 的值等于 类选择器(.class)属性选择器(a[href="https://example.org"])伪类(:first-child) 出现的总次数;
  • D 的值等于 标签选择器(h1,a,div)伪元素(::before,::after) 出现的总次数

比较规则是: 从左至右比较,如果是样式优先级相等,取后面出现的样式

2.2 CSS 盒模型

developer.mozilla.org/zh-CN/docs/…

CSS3 中的盒模型有以下两种:标准盒模型IE(替代)盒模型

两种盒子模型都是由 content + padding + border + margin 构成,其大小都是由 content + padding + border 决定的,但是盒子内容宽/高度(即 width/height)的计算范围根据盒模型的不同会有所不同:

  • 标准盒模型:只包含 content
  • IE(替代)盒模型:content + padding + border

可以通过 box-sizing 来改变元素的盒模型:

  • box-sizing: content-box :标准盒模型(默认值)。
  • box-sizing: border-box :IE(替代)盒模型。

2.3 对 BFC 的理解

推荐文章:

BFC 即块级格式上下文,根据盒模型可知,每个元素都被定义为一个矩形盒子,然而盒子的布局会受到尺寸,定位,盒子的子元素或兄弟元素,视口的尺寸等因素决定,所以这里有一个浏览器计算的过程,计算的规则就是由一个叫做视觉格式化模型的东西所定义的,BFC 就是来自这个概念,它是 CSS 视觉渲染的一部分,用于决定块级盒的布局及浮动相互影响范围的一个区域

BFC 具有一些特性:

  1. 块级元素会在垂直方向一个接一个的排列,和文档流的排列方式一致。
  2. 在 BFC 中上下相邻的两个容器的 margin  会重叠,创建新的 BFC 可以避免外边距重叠。
  3. 计算 BFC 的高度时,需要计算浮动元素的高度。
  4. BFC 区域不会与浮动的容器发生重叠。
  5. BFC 是独立的容器,容器内部元素不会影响外部元素。
  6. 每个元素的左 margin  值和容器的左 border  相接触。

利用这些特性,我们可以解决以下问题:

  • 利用 4  和 6 ,我们可以实现三栏(或两栏)自适应布局。
  • 利用 2 ,我们可以避免 margin  重叠问题。
  • 利用 3 ,我们可以避免高度塌陷。

创建 BFC 的方式:

  • 绝对定位元素(positionabsolutefixed )。
  • 行内块元素,即 displayinline-block
  • overflow 的值不为 visible

2.4 CSS 伪元素和伪类的区别

伪类: 根据文档树中已有元素状态,添加对应样式,如 :hover:link:active:not:first-child

伪元素: 创建一些不在文档树中的元素,并为其添加样式。如 ::before/:before::after/:after::first-letter/:first-letter

伪类的操作对象是文档树中已有的元素,而伪元素则创建了一个文档数外的元素。因此,伪类与伪元素的区别在于:有没有创建一个文档树之外的元素

双冒号 (::) 表示伪元素,伪类使用单冒号 (:)

总结伪类与伪元素 | AlloyTeam

2.5 水平垂直居中多种实现方式

推荐文章:

  1. 利用绝对定位,设置 left: 50%  和 top: 50%  现将子元素左上角移到父元素中心位置,然后再通过 translate  来调整子元素的中心点到父元素的中心。该方法可以不定宽高

    .father {
      position: relative;
    }
    .son {
      position: absolute;
      left: 50%;
      top: 50%;
      transform: translate(-50%, -50%);
    }
    复制代码
  2. 利用绝对定位,子元素所有方向都为 0 ,将 margin  设置为 auto ,由于宽高固定,对应方向实现平分,该方法必须盒子有宽高

    .father {
      position: relative;
    }
    .son {
      position: absolute;
      top: 0;
      left: 0;
      right: 0;
      bottom: 0px;
      margin: auto;
      height: 100px;
      width: 100px;
    }
    复制代码
  3. 利用绝对定位,设置 left: 50%top: 50% 现将子元素左上角移到父元素中心位置,然后再通过 margin-left  和 margin-top  以子元素自己的一半宽高进行负值赋值。该方法必须定宽高

    .father {
      position: relative;
    }
    .son {
      position: absolute;
      left: 50%;
      top: 50%;
      width: 200px;
      height: 200px;
      margin-left: -100px;
      margin-top: -100px;
    }
    复制代码
  4. 利用 flex ,最经典最方便的一种了,不用解释,定不定宽高无所谓的。

    .father {
      display: flex;
      justify-content: center;
      align-items: center;
    }
    复制代码

其实还有很多方法,比如 display: grid  或 display: table-cell  来做

2.6 实现两栏布局(左侧固定 + 右侧自适应布局)

现在有以下 DOM 结构:

<div class="outer">
  <div class="left">左侧</div>
  <div class="right">右侧</div>
</div>
复制代码
复制代码
  1. 利用浮动,左边元素宽度固定 ,设置向左浮动。将右边元素的 margin-left 设为固定宽度 。注意,因为右边元素的 width 默认为 auto ,所以会自动撑满父元素。

    .outer {
      height: 100px;
    }
    .left {
      float: left;
      width: 200px;
      height: 100%;
      background: lightcoral;
    }
    .right {
      margin-left: 200px;
      height: 100%;
      background: lightseagreen;
    }
    复制代码
  2. 同样利用浮动,左边元素宽度固定 ,设置向左浮动。右侧元素设置 overflow: hidden; 这样右边就触发了 BFCBFC 的区域不会与浮动元素发生重叠,所以两侧就不会发生重叠。

    .outer {
      height: 100px;
    }
    .left {
      float: left;
      width: 200px;
      height: 100%;
      background: lightcoral;
    }
    .right {
      overflow: auto;
      height: 100%;
      background: lightseagreen;
    }
    复制代码
  3. 利用 flex 布局,左边元素固定宽度,右边的元素设置 flex: 1

    .outer {
      display: flex;
      height: 100px;
    }
    .left {
      width: 200px;
      height: 100%;
      background: lightcoral;
    }
    .right {
      flex: 1;
      height: 100%;
      background: lightseagreen;
    }
    复制代码
  4. 利用绝对定位,父级元素设为相对定位。左边元素 absolute  定位,宽度固定。右边元素的 margin-left  的值设为左边元素的宽度值。

    .outer {
      position: relative;
      height: 100px;
    }
    .left {
      position: absolute;
      width: 200px;
      height: 100%;
      background: lightcoral;
    }
    .right {
      margin-left: 200px;
      height: 100%;
      background: lightseagreen;
    }
    复制代码
  5. 利用绝对定位,父级元素设为相对定位。左边元素宽度固定,右边元素 absolute  定位, left  为宽度大小,其余方向定位为 0 。

    .outer {
      position: relative;
      height: 100px;
    }
    .left {
      width: 200px;
      height: 100%;
      background: lightcoral;
    }
    .right {
      position: absolute;
      left: 200px;
      top: 0;
      right: 0;
      bottom: 0;
      height: 100%;
      background: lightseagreen;
    }
    复制代码

2.7 实现圣杯布局和双飞翼布局(经典三分栏布局)

圣杯布局和双飞翼布局的目的:

  • 三栏布局,中间一栏最先加载和渲染(内容最重要,这就是为什么还需要了解这种布局的原因)。
  • 两侧内容固定,中间内容随着宽度自适应。
  • 一般用于 PC 网页。

圣杯布局和双飞翼布局的技术总结:

  • 使用 float  布局。
  • 两侧使用 margin 负值,以便和中间内容横向重叠。
  • 防止中间内容被两侧覆盖,圣杯布局用 padding ,双飞翼布局用 margin 。

圣杯布局: HTML 结构:

<div id="container" class="clearfix">
  <p class="center">我是中间</p>
  <p class="left">我是左边</p>
  <p class="right">我是右边</p>
</div>
复制代码
复制代码

CSS 样式:

#container {
  padding-left: 200px;
  padding-right: 150px;
  overflow: auto;
}
#container p {
  float: left;
}
.center {
  width: 100%;
  background-color: lightcoral;
}
.left {
  width: 200px;
  position: relative;
  left: -200px;
  margin-left: -100%;
  background-color: lightcyan;
}
.right {
  width: 150px;
  margin-right: -150px;
  background-color: lightgreen;
}
.clearfix:after {
  content: "";
  display: table;
  clear: both;
}
复制代码
复制代码

双飞翼布局: HTML 结构:

<div id="main" class="float">
  <div id="main-wrap">main</div>
</div>
<div id="left" class="float">left</div>
<div id="right" class="float">right</div>
复制代码
复制代码

CSS 样式:

.float {
  float: left;
}
#main {
  width: 100%;
  height: 200px;
  background-color: lightpink;
}
#main-wrap {
  margin: 0 190px 0 190px;
}
#left {
  width: 190px;
  height: 200px;
  background-color: lightsalmon;
  margin-left: -100%;
}
#right {
  width: 190px;
  height: 200px;
  background-color: lightskyblue;
  margin-left: -190px;
}
复制代码
复制代码

tips:上述代码中 margin-left: -100%  相对的是父元素的 content  宽度,即不包含 paddig 、 border  的宽度。

其实以上问题需要掌握 margin 负值问题 即可很好理解。

2.8 flex 布局

推荐文章:

用过flex布局吗?都有哪些属性?flex: 1代表什么意思?

这里有个小问题,很多时候我们会用到 flex: 1 ,它具体包含了以下的意思:

  • flex-grow: 1 :该属性默认为 0 ,如果存在剩余空间,元素也不放大。设置为 1  代表会放大。
  • flex-shrink: 1 :该属性默认为 1 ,如果空间不足,元素缩小。
  • flex-basis: 0% :该属性定义在分配多余空间之前,元素占据的主轴空间。浏览器就是根据这个属性来计算是否有多余空间的。默认值为 auto ,即项目本身大小。设置为 0%  之后,因为有 flex-grow  和 flex-shrink  的设置会自动放大或缩小。在做两栏布局时,如果右边的自适应元素 flex-basis  设为 auto  的话,其本身大小将会是 0 。​

2.9 line-height 如何继承

  • 父元素的 line-height 写了具体数值,比如 30px,则子元素 line-height 继承该值。
  • 父元素的 line-height 写了比例,比如 1.5 或 2,则子元素 line-height 也是继承该比例。
  • 父元素的 line-height 写了百分比,比如 200%,则子元素 line-height 继承的是父元素 font-size * 200% 计算出来的值。

2.10 visibility、display、opacity的区别

2.11 transition、transform、translate的区别

单行截断css

如何画一条 0.5px 的边框

怎么画一条0.5px的边(更新)

parent元素宽高不定,实现scale固定宽高比始终为4:3

position的几个属性和含义

CSS position 属性

css和js两种方式实现div右移1000px动画

如何提高动画的渲染性能

这样使用GPU动画

二、网络通信

浏览器缓存、Http2.0、Https通信过程、TCP与UDP、DNS解析、CDN缓存等

1、浏览器

onload 和 DOMContentLoaded的区别

requestAnimationFrame

1.1 从浏览器地址栏输入 url 到请求返回发生了什么

推荐文章:

总体来说分为以下几个过程:

  1. 输入 URL 后解析出协议、主机、端口、路径等信息,并构造一个 HTTP 请求。

    • 强缓存。
    • 协商缓存。
  2. DNS 解析:将域名解析成 IP 地址(字节面试被虐后,是时候搞懂 DNS 了

  3. TCP 连接:TCP 三次握手

    总是要问:为什么需要三次握手,两次不行吗?其实这是由 TCP 的自身特点可靠传输决定的。客户端和服务端要进行可靠传输,那么就需要确认双方的接收和发送能力。第一次握手可以确认客服端的发送能力,第二次握手,确认了服务端的发送能力和接收能力,所以第三次握手才可以确认客户端的接收能力。不然容易出现丢包的现象。

  4. 发送 HTTP 请求

  5. 服务器处理请求并返回 HTTP 报文

  6. 浏览器解析渲染页面 image.png

  7. 断开连接:TCP 四次挥手

1.2 cookie、localStorage 和 sessionStorage

  • JS存储方式?
  • sessionSorage、localstorage、cookie的区别?
  • 同一个系统开两个网页,两个网页的sessionStorage共享吗?

cookie:

  • 本身用于浏览器和 server 通讯。
  • 被“借用”到本地存储来的。
  • 可用 document.cookie = '...' 来修改。
  • 存储大小限制为 4KB
  • http 请求时需要发送到服务端,增加请求数量。
  • cookie设置的过期时间之前一直有效

localStorage 和 sessionStorage:

  • HTML5 专门为存储来设计的,最大可存 5M
  • API 简单易用, setItem getItem。
  • 不会随着 http 请求被发送到服务端。 区别:
  • localStorage 数据会永久存储,浏览器关闭后数据不丢失,除非代码删除或手动删除。
  • sessionStorage 数据只存在于当前会话,浏览器关闭则清空。

1.3 重排(reflow)和重绘(repaint)

推荐文章:

简单地总结下两者的概念:

  • 重排:无论通过什么方式影响了元素的几何信息(元素在视口内的位置和尺寸大小),浏览器需要重新计算元素在视口内的几何属性,这个过程叫做重排。
  • 重绘:通过构造渲染树和重排(回流)阶段,我们知道了哪些节点是可见的,以及可见节点的样式和具体的几何信息(元素在视口内的位置和尺寸大小),接下来就可以将渲染树的每个节点都转换为屏幕上的实际像素,这个阶段就叫做重绘。

如何减少重排和重绘?

  • 最小化重绘和重排,比如样式集中改变,使用添加新样式类名 .classcssText
  • 批量操作 DOM,比如读取某元素 offsetWidth 属性存到一个临时变量,再去使用,而不是频繁使用这个计算属性;又比如利用 document.createDocumentFragment() 来添加要被添加的节点,处理完之后再插入到实际 DOM 中。
  • 使用 **absolute****fixed** 使元素脱离文档流,这在制作复杂的动画时对性能的影响比较明显。
  • 开启 GPU 加速,利用 css 属性 transformwill-change 等,比如改变元素位置,我们使用 translate 会比使用绝对定位改变其 lefttop 等来的高效,因为它不会触发重排或重绘,transform 使浏览器为元素创建⼀个 GPU 图层,这使得动画元素在一个独立的层中进行渲染。当元素的内容没有发生改变,就没有必要进行重绘。

1.5 浏览器的垃圾回收机制

  • 你刚刚提到的标记清除法有什么缺点?怎么解决?
  • 你刚刚提到的引用计数法有什么缺点吗?
  • v8里面的垃圾回收机制是什么?
  • v8是怎么解决循环引用的?

推荐文章:你真的了解垃圾回收机制吗

1.6 宏任务、微任务、EventLoop - 需要再整理

  • EventLoop中为什么要同时存在宏任务和微任务两个队列?设计一个行不行?一段代码在执行时,程序是如何去区分宏任务和微任务的?
  • 微任务的优先级
  • 哪些是宏任务?哪些是微任务?
  • 如何理解script标签是个宏任务

【前端体系】从一道面试题谈谈对EventLoop的理解

【study】宏任务和微任务的区别是什么

整理文章 > juejin.cn/post/705235…

1.7 内存泄露

  • 项目中内存泄漏的场景
  • setTimeout为什么会造成内存泄露?
  • 如何防止setTimeout内存泄露?
  • 清除定时器为什么就不会有内存泄露?

一文带你了解如何排查内存泄漏导致的页面卡顿现象

描述一下同源策略、跨域及其解决方案

DOM事件模型。事件捕获和事件冒泡的使用场景

2、Http

2.1 http 状态码

状态码分类

  • 1xx - 服务器收到请求。
  • 2xx - 请求成功,如 200。
  • 3xx - 重定向,如 302。
  • 4xx - 客户端错误,如 404。
  • 5xx - 服务端错误,如 500。

常见状态码

  • 200 - 成功。
  • 301 - 永久重定向(配合 location,浏览器自动处理)。
  • 302 - 临时重定向(配合 location,浏览器自动处理)。
  • 304 - 资源未被修改。
  • 403 - 没权限。
  • 404 - 资源未找到。
  • 500 - 服务器错误。
  • 504 - 网关超时。

关于协议和规范

  • 状态码都是约定出来的。
  • 要求大家都跟着执行。
  • 不要违反规范,例如 IE 浏览器。

200状态码一定是服务器返回的吗?

不是,命中强缓存的话,会直接从内存或者磁盘中读取资源,并返回一个200状态码,具体操作可以试试浏览器的前进后退键。

2.2 http 缓存

  • 哪些字段用做强缓存?哪些字段用做协商缓存?
  • cache-control、expires、etag等字段的属性值是什么样的?
  • 这些字段都被存放在请求的哪个部分?
  • last-modify和expires这些字段的时间有什么区别?
  • last-modify和expires能共存吗?
  • 如果不想让某个资源使用缓存,那么应该如何设计http缓存?
  • cache-control中的no-cache和no-store的区别
  • 如何设计css、js等文件的缓存

一张图理解http缓存

http协商缓存VS强缓存

www.zhihu.com/question/20…

2.3 HTTP 请求跨域问题

get和post有什么区别?

请求参数:get请求参数是通过url传递的,多个参数以&连接;post请求放在request body中。
请求缓存:get请求会被缓存,而post请求不会,除非手动设置。
相对的安全性:get是将参数通过url传递的,会被浏览器缓存,容易被他人获取,post相对来说,比较安全。
请求参数长度限制:get通过url传参,浏览器会限制url的长度(http不会)。
编码方式:GET请求只能进行url编码,只能接收 ASCII 字符,而POST支持多种编码方式。

====

  • 幂等性的角度,GET 是幂等的,而 POST 不是。(幂等表示执行相同的操作,结果也是相同的)
  • TCP 的角度,GET 请求会把请求报文一次性发出去,而 POST 会分为两个 TCP 数据包,首先发 header 部分,如果服务器响应 100(continue), 然后发 body 部分。(火狐浏览器除外,它的 POST 请求只发一个 TCP 包)

2.4 http1.1和http2.0有什么区别?

http2 的 相 关 特 性 ?

HTTP灵魂之问,巩固你的 HTTP 知识体系

2.5 HTTP 灵魂之问,巩固你的 HTTP 知识体系

HTTP 灵魂之问,巩固你的 HTTP 知识体系

http和https的区别?为什么https是相对安全的?https加密原理?

推荐文章:为什么HTTPS是安全的,一张图告诉你

xss和csrf的概念和防御方式

3、其他

DNS解析具体是怎么个解析过程呢

三次握手、四次挥手讲一下

三、JS 基础

原型与原型链、继承、事件循环、作用域、ES6语法、垃圾回收与内存泄漏等。 juejin.cn/post/694094…

1、数据类型

1.1 基本的数据类型介绍,及值类型和引用类型的理解

在 JS 中共有 8  种基础的数据类型,分别为: Undefined 、 Null 、 Boolean 、 Number 、 String 、 Object 、 Symbol 、 BigInt 。

Symbol  和 BigInt  是 ES6 新增的数据类型:

  • Symbol 代表独一无二的值,最大的用法是用来定义对象的唯一属性名。
  • BigInt 可以表示任意大小的整数。

值类型:是直接存储在 栈(stack) 中的简单数据段,占据空间小、大小固定,属于被频繁使用数据,所以放入栈中存储;

引用类型:是存储在 堆(heap) 中的对象,占据空间大、大小不固定。如果存储在栈中,将会影响程序运行的性能;

1.2 数据类型的判断方式

  • typeof:不可对 null、对象、数组进行精确判断,因为都返回 object ,其他判断都正确

    console.log(typeof undefined); // undefined
    console.log(typeof 2); // number
    console.log(typeof true); // boolean
    console.log(typeof "str"); // string
    console.log(typeof Symbol("foo")); // symbol
    console.log(typeof 2172141653n); // bigint
    console.log(typeof function () {}); // function
    // 不能判别
    console.log(typeof []); // object
    console.log(typeof {}); // object
    console.log(typeof null); // object
    复制代码
  • instanceof:只能判断引用数据类型,不能判断基本数据类型。其内部运行机制是判断在其原型链中能否找到该类型的原型。比如考虑以下代码:

    class People {}
    class Student extends People {}
    
    const vortesnail = new Student();
    
    console.log(vortesnail instanceof People); // true
    console.log(vortesnail instanceof Student); // true
    复制代码

    其实现就是顺着原型链去找,如果能找到对应的 Xxxxx.prototype  即为 true 。比如这里的 vortesnail  作为实例,顺着原型链能找到 Student.prototype  及 People.prototype ,所以都为 true 。

  • Object.prototype.toString.call() :所有原始数据类型都是能判断的,还有 Error 对象,Date 对象等。

    Object.prototype.toString.call(2); // "[object Number]"
    Object.prototype.toString.call(""); // "[object String]"
    Object.prototype.toString.call(true); // "[object Boolean]"
    Object.prototype.toString.call(undefined); // "[object Undefined]"
    Object.prototype.toString.call(null); // "[object Null]"
    Object.prototype.toString.call(Math); // "[object Math]"
    Object.prototype.toString.call({}); // "[object Object]"
    Object.prototype.toString.call([]); // "[object Array]"
    Object.prototype.toString.call(function () {}); // "[object Function]"
    复制代码

1.3 如何判断变量是否为数组

Array.isArray(arr); // true
arr.__proto__ === Array.prototype; // true
arr instanceof Array; // true
arr.constructor === Array; // true
Object.prototype.toString.call(arr); // "[object Array]"
复制代码

ps:通过instanceof和constructor来判断不一定准确,因为可能会被重写。

1.4 什么是深拷贝和浅拷贝? 以及怎么实现深拷贝和浅拷贝?

juejin.cn/post/684490…

1.5 数组的遍历方法有哪些

方法是否改变原数组特点
forEach()数组方法,不改变原数组,没有返回值
map()数组方法,不改变原数组,有返回值,可链式调用
filter()数组方法,过滤数组,返回包含符合条件的元素的数组,可链式调用
for...offor...of遍历具有Iterator迭代器的对象的属性,返回的是数组的元素、对象的属性值,不能遍历普通的obj对象,将异步循环变成同步循环
every() 和 some()数组方法,some()只要有一个是true,便返回true;而every()只要有一个是false,便返回false.
find() 和 findIndex()数组方法,find()返回的是第一个符合条件的值;findIndex()返回的是第一个返回条件的值的索引值
reduce() 和 reduceRight()数组方法,reduce()对数组正序操作;reduceRight()对数组逆序操作

遍历方法的详细解释:《细数JavaScript中那些遍历和循环》

2、原型、原型链

juejin.cn/editor/draf…

总结

  • 当一个对象查找属性和方法时会从自身查找,如果查找不到则会通过__proto__指向被实例化的构造函数的prototype
  • 隐式原型也是一个对象,是指向我们构造函数的原型
  • 除了最顶层的Object对象没有__proto_,其他所有的对象都有__proto__,这是隐式原型
  • 隐式原型__proto__的作用是让对象通过它来一直往上查找属性或方法,直到找到最顶层的Object的__proto__属性,它的值是null,这个查找的过程就是原型链

3、作用域、作用域链含义和使用场景

推荐文章

  • 作用域:规定了如何查找变量,也就是确定当前执行代码对变量的访问权限。换句话说,作用域决定了代码区块中变量和其他资源的可见性。(全局作用域、函数作用域、块级作用域)
  • 作用域链:从当前作用域开始一层层往上找某个变量,如果找到全局作用域还没找到,就放弃寻找 。这种层级关系就是作用域链。(由多个执行上下文的变量对象构成的链表就叫做作用域链,学习下面的内容之后再考虑这句话)

需要注意的是,js 采用的是静态作用域,所以函数的作用域在函数定义时就确定了。

4、函数执行上下文包含了哪些内容

推荐文章:

总结:当 JavaScript 代码执行一段可执行代码时,会创建对应的执行上下文。对于每个执行上下文,都有三个重要属性:

  • 变量对象(Variable object,VO);
  • 作用域链(Scope chain);
  • this。(关于 this 指向问题,在上面推荐的深入系列也有讲从 ES 规范讲的,但是实在是难懂,对于应付面试来说以下这篇阮一峰的文章应该就可以了:JavaScript 的 this 原理

5、箭头函数和普通函数有什么区别?

箭头函数比普通函数更加简洁
如果没有参数,就直接写一个空括号即可
如果只有一个参数,可以省去参数括号
如果有多个参数,用逗号分割
如果函数体的返回值只有一句,可以省略大括号
如果函数体不需要返回值,且只有一句话,可以给这个语句前面加一个void关键字。最常用的就是调用一个函数:
let fn = () => void doesNotReturn()

(2) 箭头函数没有自己的this
箭头函数不会创建自己的this,所以它没有自己的this,它只会在自己作用域的上一层继承this。所以箭头函数中的this的指向在它在定义时一家确定了,之后不会改变。

(3)箭头函数继承来的this指向永远不会改变

(4) call()、apply()、bind()等方法不能改变箭头函数中的this指向 

(5) 箭头函数不能作为构造函数使用

(6) 箭头函数没有自己的arguments

(7) 箭头函数没有prototype

(8) 箭头函数不能用作Generator函数,不能使用yeild关键字

ES6

Typescript

框架通识

框架的底层原理,React 的知识点有 React diff、生命周期、Fiber 架构、Hooks 等;Vue 的知识点有Vue diff、响应式原理、Vue3.0新特性等

React

✏️ 知识整理以及学习 - React 篇

Vue

✏️ 知识整理以及学习 - Vue 篇

打包工具

Webpack

模块化

前端模块化详解(完整版) 

可能是最详细的 UMD 模块入门指南

性能优化

代码层面:

  • 防抖和节流(resize,scroll,input)。
  • 减少回流(重排)和重绘。
  • 事件委托。
  • css 放 ,js 脚本放 最底部。
  • 减少 DOM 操作。
  • 按需加载,比如 React 中使用 React.lazyReact.Suspense ,通常需要与 webpack 中的 splitChunks 配合。

构建方面:

  • 压缩代码文件,在 webpack 中使用 terser-webpack-plugin 压缩 Javascript 代码;使用 css-minimizer-webpack-plugin 压缩 CSS 代码;使用 html-webpack-plugin 压缩 html 代码。
  • 开启 gzip 压缩,webpack 中使用 compression-webpack-plugin ,node 作为服务器也要开启,使用 compression
  • 常用的第三方库使用 CDN 服务,在 webpack 中我们要配置 externals,将比如 React, Vue 这种包不打倒最终生成的文件中。而是采用 CDN 服务。

其它:

  • 使用 http2。因为解析速度快,头部压缩,多路复用,服务器推送静态资源。
  • 使用服务端渲染。
  • 图片压缩。
  • 使用 http 缓存,比如服务端的响应中添加 Cache-Control / Expires

前端性能优化24条建议(2020)

常见手写题 & 算法

手写深拷贝

文章推荐:如何写出一个惊艳面试官的深拷贝?

/**
 * 深拷贝
 * @param {Object} obj 要拷贝的对象
 * @param {Map} map 用于存储循环引用对象的地址
 */

function deepClone(obj = {}, map = new Map()) {
  if (typeof obj !== "object") {
    return obj;
  }
  if (map.get(obj)) {
    return map.get(obj);
  }

  let result = {};
  // 初始化返回结果
  if (
    obj instanceof Array ||
    // 加 || 的原因是为了防止 Array 的 prototype 被重写,Array.isArray 也是如此
    Object.prototype.toString(obj) === "[object Array]"
  ) {
    result = [];
  }
  // 防止循环引用
  map.set(obj, result);
  for (const key in obj) {
    // 保证 key 不是原型属性
    if (obj.hasOwnProperty(key)) {
      // 递归调用
      result[key] = deepClone(obj[key], map);
    }
  }

  // 返回结果
  return result;
}
复制代码

防抖(debounce) 和 节流(throttle)

算法常见:排序、递归、链表、动态规划

参考文章

不断更新ing,如有错误请指正~

分类:
前端
标签: