变量提升
var
声明的变量存在变量提升,即变量可以在声明之前调用,值为undefined
let
和const
不存在变量提升,即它们所声明的变量一定要在声明后使用,否则报错暂时性死区
let
和const
存在暂时性死区,只有等到声明变量的那一行代码出现,才可以获取和使用该变量块级作用域
var
不存在块级作用域,let
和const
存在块级作用域重复声明
var
允许重复声明变量,let
和const
在同一作用域不允许重复声明变量修改声明的变量
var
和let
可以,const
声明一个只读的常量。一旦声明,常量的值就不能改变作用域链:全局作用域、函数作用域、块级作用域
作用域决定了代码区块中变量的可用性
Set
是es6
新增的数据结构,类似于数组,但是成员的值都是唯一的,没有重复的值,我们一般称为集合
Map
类型是键值对的有序列表,而键和值都可以是任意类型扩展:es6中map和object的区别是什么
Map Object 键的类型 一个 Map的键可以是任意值,包括函数、对象或任意基本类型。 一个Object 的键必须是一个 String 或是Symbol。 键的顺序 Map 中的 key 是有序的。因此,当迭代的时候,一个 Map 对象以插入的顺序返回键值。 一个 Object 的键是无序的。注意:自ECMAScript 2015规范以来,对象确实保留了字符串和Symbol键的创建顺序; 因此,在只有字符串键的对象上进行迭代将按插入顺序产生键。 Size Map 的键值对个数可以轻易地通过size 属性获取 Object 的键值对个数只能手动计算 迭代 Map 是 iterable 的,所以可以直接被迭代。 迭代一个Object需要以某种方式获取它的键然后才能迭代。 性能 在频繁增删键值对的场景下表现更好。 在频繁添加和删除键值对的场景下未作出优化。
Promise
,是异步编程的一种解决方案,比传统的解决方案(回调函数)更加合理和更加强大,解决了回调地域。
链式操作减低了编码难度
代码可读性明显增强
promise
对象仅有三种状态
pending
(进行中)
fulfilled
(已成功)
rejected
(已失败)对象的状态不受外界影响,只有异步操作的结果,可以决定当前是哪一种状态
一旦状态改变(从
pending
变为fulfilled
和从pending
变为rejected
),就不会再变,任何时候都可以得到这个结果用法:
Promise
对象是一个构造函数,用new方法来生成Promise
实例,Promise
构造函数接受一个函数作为参数,该函数的两个参数分别是resolve
和reject
Promise
构建出来的实例存在以下方法:
then()
catch()
finally()
Promise
构造函数存在以下方法:
all()
promise.all(并发,一起执行),不用promise.all(先完成第一个,在完成第二个)
race()
allSettled()
resolve()
reject()
try()
扩展:Promise.any
和 Promise.race 方法的区别
Promise.race 返回参数中最快的那个承诺,无论它是成功还是失败
而 Promise.any 关注的是参数中最快同时还必须成功的那个承诺
和 Promise.all 方法的区别
Promise.any 和 Promise.all 是完全相反的
Promise.any 参数中全部承诺都失败了才会失败,Promise.all 参数中全部承诺都成功了才会成功
Promise.any 参数中一旦有一个承诺成功了返回的新承诺就会成功,Promise.all 参数中一旦有一个承诺失败了返回的新承诺就会失败
形式上,
Generator
函数是一个普通函数,但是有两个特征:
function
关键字与函数名之间有一个星号函数体内部使用
yield
表达式,定义不同的内部状态通过
next
方法才会遍历到下一个内部状态。
基本数据类型:String、Number、Boolean、Null、Undefined、Symbol、BigInt
引用数据类型:Object【Object是个大类,function函数、array数组、date日期、RegExp、Map、Set...等都归属于Object】
数组的方法有很多,可以根据是否改变原数组来进行分类
改变原数组的有:pop、push、shift、unshift、sort、reverse、splice
不改变原数组:toString、join、concat、slice、forEach、map、filter、find、findIndex等
无返回值:forEach
返回值为新数组:splice、concat、slice、sort、reverse、map、filter
浅拷贝,指的是创建新的数据,这个数据有着原始数据属性值的一份精确拷贝,如果属性是基本类型,拷贝的就是基本类型的值。如果属性是引用类型,拷贝的就是内存地址。
深拷贝是开辟一个新的栈,两个对象属性完成相同,但是对应两个不同的地址,修改一个对象的属性,不会改变另一个对象的属性
即
浅拷贝是拷贝一层,属性为对象时,浅拷贝是复制,两个对象指向同一个地址,深拷贝是递归拷贝深层次,属性为对象时,深拷贝是新开栈,两个对象指向不同的地址
闭包就是一个函数嵌套一个函数,让你可以在一个内层函数中访问到其外层函数的作用域。
创建私有变量,延长变量的生命周期。
应用场景:柯里化函数、延时函数
我们需要牢记两点:①proto和constructor属性是对象所独有的;② prototype属性是函数所独有的,因为函数也是一种对象,所以函数也拥有proto和constructor属性。
proto属性的作用就是当访问一个对象的属性时,如果该对象内部不存在这个属性,那么就会去它的proto属性所指向的那个对象(父对象)里找,一直找,直到proto属性的终点null,再往上找就相当于在null上取值,会报错。通过proto属性将对象连接起来的这条链路即我们所谓的原型链。
prototype属性的作用就是让该函数所实例化的对象们都可以找到公用的属性和方法,即f1.proto === Foo.prototype。
constructor属性的含义就是指向该对象的构造函数,所有函数(此时看成对象了)最终的构造函数都指向Function。
下面给出
JavaScripy
常见的继承方式:
原型链继承
构造函数继承(借助 call)
组合继承
原型式继承
寄生式继承
寄生组合式继承
Ajax
的原理简单来说通过XmlHttpRequest
对象来向服务器发异步请求,从服务器获得数据,然后用JavaScript
来操作DOM
而更新页面实现过程: 自己去看看
apply
接受两个参数,第一个参数是this
的指向,第二个参数是函数接受的参数,以数组的形式传入,改变this
指向后原函数会立即执行,且此方法只是临时改变this
指向一次
call
方法的第一个参数也是this
的指向,后面传入的是一个参数列表,跟apply
一样,改变this
指向后原函数会立即执行,且此方法只是临时改变this
指向一次bind方法和call很相似,第一参数也是
this
的指向,后面传入的也是一个参数列表(但是这个参数列表可以分多次传入),改变this
指向后不会立即执行,而是返回一个永久改变this
指向的函数从上面可以看到,
apply
、call
、bind
三者的区别在于:
三者都可以改变函数的
this
对象指向三者第一个参数都是
this
要指向的对象,如果如果没有这个参数或参数为undefined
或null
,则默认指向全局window
三者都可以传参,但是
apply
是数组,而call
是参数列表,且apply
和call
是一次性传入参数,而bind
可以分为多次传入
bind
是返回绑定this之后的函数,apply
、call
则是立即执行
创建节点(createElement)
查询节点
更新节点(innerHTML)
添加节点(appendChild、parentElement.insertBefore(newElement, referenceElement))
删除节点(调用父节点的
removeChild
把自己删掉)
navigator
对象主要用来获取浏览器的属性location.hash utl中#后面的字符
screen
history
内存泄漏(Memory leak)是由于疏忽或错误造成程序未能释放已经不再使用的内存
对于持续运行的服务进程,必须及时释放不再用到的内存。否则,内存占用越来越高,轻则影响系统性能,重则导致进程崩溃
垃圾回收
Javascript 具有自动垃圾回收机制(GC:Garbage Collecation)
通常情况下有两种实现方式:
标记清除(标记这个变量为“进入环境”,清除标记)
引用计数(如果一个值的引用次数是
0
,就表示这个值不再用到了)
javaScript
本地缓存的方法我们主要讲述以下四种:
cookie
sessionStorage
localStorage
indexedDB
关于
cookie
、sessionStorage
、localStorage
三者的区别主要如下:
存储大小:
cookie
数据大小不能超过4k
,sessionStorage
和localStorage
虽然也有存储大小的限制,但比cookie
大得多,可以达到5M或更大有效时间:
localStorage
存储持久数据,浏览器关闭后数据不丢失除非主动删除数据;sessionStorage
数据在当前浏览器窗口关闭后自动删除;cookie
设置的cookie
过期时间之前一直有效,即使窗口或浏览器关闭数据与服务器之间的交互方式,
cookie
的数据会自动的传递到服务器,服务器端也可以写cookie
到客户端;sessionStorage
和localStorage
不会自动把数据发给服务器,仅在本地保存
节流: n 秒内只运行一次,若在 n 秒内重复触发,只有一次生效
防抖: n 秒后在执行该事件,若在 n 秒内被重复触发,则重新计时
分片上传,就是将所要上传的文件,按照一定的大小,将整个文件分隔成多个数据块(Part)来进行分片上传,上传完之后再由服务端对所有上传的文件进行汇总整合成原始的文件
大致流程如下:
将需要上传的文件按照一定的分割规则,分割成相同大小的数据块;
初始化一个分片上传任务,返回本次分片上传唯一标识;
按照一定的策略(串行或并行)发送各个分片数据块;
发送完成后,服务端根据判断数据上传是否完整,如果完整,则进行数据块合成得到原始文件
断点续传指的是在下载或上传时,将下载或上传任务人为的划分为几个部分
每一个部分采用一个线程进行上传或下载,如果碰到网络故障,可以从已经上传或下载的部分开始继续上传下载未完成的部分,而没有必要从头开始上传下载。用户可以节省时间,提高速度
一般实现方式有两种:
服务器端返回,告知从哪开始
浏览器端自行处理
上传过程中将文件在服务器写为临时文件,等全部写完了(文件上传完),将此临时文件重命名为正式文件即可
如果中途上传中断过,下次上传的时候根据当前临时文件大小,作为在客户端读取文件的偏移量,从此位置继续读取文件数据块,上传到服务器从此偏移量继续写入文件即可
上拉加载的本质是页面触底,或者快要触底时的动作
判断页面触底我们需要先了解一下下面几个属性
scrollTop
:滚动视窗的高度距离window
顶部的距离,它会随着往上滚动而不断增加,初始值是0,它是一个变化的值
clientHeight
:它是一个定值,表示屏幕可视区域的高度;
scrollHeight
:页面不能滚动时也是存在的,此时scrollHeight等于clientHeight。scrollHeight表示body
所有元素的总长度(包括body元素自身的padding)下拉刷新的本质是页面本身置于顶部时,用户下拉时需要触发的动作
关于下拉刷新的原生实现,主要分成三步:
监听原生
touchstart
事件,记录其初始位置的值,e.touches[0].pageY
;监听原生
touchmove
事件,记录并计算当前滑动的位置值与初始位置值的差值,大于0
表示向下拉动,并借助CSS3的translateY
属性使元素跟随手势向下滑动对应的差值,同时也应设置一个允许滑动的最大值;监听原生
touchend
事件,若此时元素滑动达到最大值,则触发callback
,同时将translateY
重设为0
,元素回到初始位置从上面可以看到,在下拉到松手的过程中,经历了三个阶段:
当前手势滑动位置与初始位置差值大于零时,提示正在进行下拉刷新操作
下拉到一定值时,显示松手释放后的操作提示
下拉到达设定最大值松手时,执行回调,提示正在进行更新操作
Web攻击(WebAttack)是针对用户上网行为或网站服务器等设备进行攻击的行为,如植入恶意代码,修改网站权限,获取网站用户隐私信息等等
常见的Web攻击方式有:
XSS (Cross Site Scripting) 跨站脚本攻击
CSRF(Cross-site request forgery)跨站请求伪造
SQL注入攻击
XSS,跨站脚本攻击,允许攻击者将恶意代码植入到提供给其它用户使用的页面中
XSS
的攻击目标是为了盗取存储在客户端的cookie
或者其他网站用于识别客户端身份的敏感信息。一旦获取到合法用户的信息后,攻击者甚至可以假冒合法用户与网站进行交互根据攻击的来源,
XSS
攻击可以分成:
存储型
反射型
DOM 型
CSRF(Cross-site request forgery)跨站请求伪造:攻击者诱导受害者进入第三方网站,在第三方网站中,向被攻击网站发送跨站请求
利用受害者在被攻击网站已经获取的注册凭证,绕过后台的用户验证,达到冒充用户对被攻击的网站执行某项操作的目的
防止
csrf
常用方案如下:
阻止不明外域的访问
同源检测
Samesite Cookie
提交时要求附加本域才能获取的信息
CSRF Token
双重Cookie验证
Sql 注入攻击,是通过将恶意的
Sql
查询或添加语句插入到应用的输入参数中,再在后台Sql
服务器上解析执行进行的攻击
标准盒子模型
盒子总宽度 = width + padding + border + margin;
盒子总高度 = height + padding + border + margin
怪异盒子模型
盒子总宽度 = width + margin;
盒子总高度 = height + margin;
box-sizing: content-box|border-box|inherit
CSS单位 | |
---|---|
相对长度单位 | em、ex、ch、rem、vw、vh、vmin、vmax、% |
绝对长度单位 | cm、mm、in、px、pt、pc |
BFC
(Block Formatting Context),即块级格式化上下文,它是页面中的一块渲染区域,并且有一套属于自己的渲染规则
BFC
目的是形成一个相对于外界完全独立的空间,让内部的子元素不会影响到外部的元素触发
BFC
的条件包含不限于:
根元素,即HTML元素
浮动元素:float值为left、right
overflow值不为 visible,为 auto、scroll、hidden
display的值为inline-block、inltable-cell、table-caption、table、inline-table、flex、inline-flex、grid、inline-grid
position的值为absolute或fixed
应用场景:
防止margin重叠(高度塌陷)
清除内部浮动
利用定位+margin:auto
position: absolute; top:0; left:0; right:0; bottom:0; margin:auto;
利用定位+margin:负值
position: absolute; top: 50%; left: 50%; margin-left:-50px; margin-top:-50px;
利用定位+transform
position: absolute; top: 50%; left: 50%; transform: translate(-50%,-50%);
flex布局
display: flex; justify-content: center; align-items: center;
css
实现动画的方式,有如下几种:
transition 实现渐变动画
transform 转变动画
animation 实现自定义动画
animation: rotate 2s; @keyframes rotate{ 0%{ transform: rotate(0deg); } 50%{ transform: rotate(180deg); } 100%{ transform: rotate(360deg); } }
根据生成的渲染树,进行回流(Layout),得到节点的几何信息(位置,大小),在渲染树中的一部分(或者全部)因为元素的规模尺寸、布局 、显隐等改变而需要重新构建,这就称为回流。
重绘(Painting):根据渲染树以及回流得到的几何信息,得到节点的绝对像素(像素,背景色,外观等)。在渲染树中的一些元素需要更新属性,而这些属性只是影响元素的外观、风格,不影响布局,就称为重绘。
何时发生回流?
添加或者删除可见的DOM元素
元素的位置发生变化
元素的尺寸发生变化(包括外边距、内边距、边框大小、高度和宽度等)
内容发生变化,文本或者图片被另一个不同尺寸的图片所代替
页面开始渲染的时候
浏览器的窗口尺寸变化(回流是根据视口的大小来计算元素的位置和大小的)
什么时候发生重绘?
背景色改变
样式发生改变的时候
区别
回流必定会引起重绘,重绘一定不会引起回流
回流会导致页面重排,影响性能
单行
text-overflow:规定当文本溢出时,显示省略符号来代表被修剪的文本
white-space:设置文字在一行显示,不能换行
overflow:文字长度超出限定宽度,则隐藏超出的内容
text-overflow
属性值有如下:
clip:当对象内文本溢出部分裁切掉
ellipsis:当对象内文本溢出时显示省略标记(...)
text-overflow
只有在设置了overflow:hidden
和white-space:nowrap
才能够生效的多行 看文档
zoom
的字面意思是“变焦”,可以改变页面上元素的尺寸,属于真实尺寸其支持的值类型有:
zoom:50%,表示缩小到原来的一半
zoom:0.5,表示缩小到原来的一半
transform:scale() 比较万能
Css
预编译语言在前端里面有三大优秀的预编处理器,分别是:
sass
less
stylus
三者区别:
less
声明的变量必须以@
开头,sass
声明的变量必须以$
开头,stylus
直接使用等号即可基本使用:less必须使用{},sass和stylus可用可不用
单页面应用(SPA) | 多页面应用(MPA) | |
---|---|---|
组成 | 一个主页面和多个页面片段 | 多个主页面 |
刷新方式 | 局部刷新 | 整页刷新 |
url模式 | 哈希模式 | 历史模式 |
SEO搜索引擎优化 | 难实现,可使用SSR方式改善 | 容易实现 |
数据传递 | 容易 | 通过url、cookie、localStorage等传递 |
页面切换 | 速度快,用户体验良好 | 切换加载资源,速度慢,用户体验差 |
维护成本 | 相对容易 | 相对复杂 |
单页应用优缺点:
优点:
具有桌面应用的即时性、网站的可移植性和可访问性
用户体验好、快,内容的改变不需要重新加载整个页面
良好的前后端分离,分工更明确
缺点:
不利于搜索引擎的抓取
首次渲染速度相对较慢
看面试官系列(见底部网址)
git fetch 命令用于从另一个存储库下载对象和引用
git pull 命令用于从另一个存储库或本地分支获取并集成(整合)
相同点:
在作用上他们的功能是大致相同的,都是起到了更新代码的作用
不同点:
git pull是相当于从远程仓库获取最新版本,然后再与本地分支merge,即git pull = git fetch + git merge
相比起来,git fetch 更安全也更符合实际要求,在 merge 前,我们可以查看更新情况,根据实际情况再决定是否合并
从上面可以看到,
merge
和rebasea
都是合并历史记录,但是各自特性不同:merge
通过
merge
合并分支会新增一个merge commit
,然后将两个分支的历史联系起来其实是一种非破坏性的操作,对现有分支不会以任何方式被更改,但是会导致历史记录相对复杂
rebase
rebase
会将整个分支移动到另一个分支上,有效地整合了所有分支上的提交主要的好处是历史记录更加清晰,是在原有提交的基础上将差异内容反映进去,消除了
git merge
所需的不必要的合并提交
git reset
用于回退版本,可以遗弃不再使用的提交
git revert
在当前提交后面,新增一次提交,抵消掉上一次提交导致的所有变化,不会改变过去的历史,主要是用于安全地取消过去发布的提交
git revert是用一次新的commit来回滚之前的commit,git reset是直接删除指定的commit
git reset 是把HEAD向后移动了一下,而git revert是HEAD继续前进,只是新的commit的内容和要revert的内容正好相反,能够抵消要被revert的内容
在回滚这一操作上看,效果差不多。但是在日后继续 merge 以前的老版本时有区别
git revert是用一次逆向的commit“中和”之前的提交,因此日后合并老的branch时,之前提交合并的代码仍然存在,导致不能够重新合并
但是git reset是之间把某些commit在某个branch上删除,因而和老的branch再次merge时,这些被回滚的commit应该还会被引入
如果回退分支的代码以后还需要的情况则使用
git revert
, 如果分支是提错了没用的并且不想让别人发现这些错误代码,则使用git reset
loader 是文件加载器,能够加载资源文件,并对这些文件进行一些处理,诸如编译、压缩等,最终一起打包到指定的文件中
plugin 赋予了 webpack 各种灵活的功能,例如打包优化、资源管理、环境变量注入等,目的是解决 loader 无法实现的其他事
两者在运行时机上的区别:
loader 运行在打包文件之前
plugins 在整个编译周期都起作用
在
Webpack
运行的生命周期中会广播出许多事件,Plugin
可以监听这些事件,在合适的时机通过Webpack
提供的API
改变输出结果对于
loader
,实质是一个转换器,将A文件进行编译形成B文件,操作的是文件,比如将A.scss
或A.less
转变为B.css
,单纯的文件转换过程
初始化流程:从配置文件和
Shell
语句中读取与合并参数,并初始化需要使用的插件和配置插件等执行环境所需要的参数编译构建流程:从 Entry 发出,针对每个 Module 串行调用对应的 Loader 去翻译文件内容,再找到该 Module 依赖的 Module,递归地进行编译处理
输出流程:对编译后的 Module 组合成 Chunk,把 Chunk 转换成文件,输出到文件系统
配置文件要背过
通过
webpack
优化前端的手段有:
JS代码压缩
CSS代码压缩
Html文件代码压缩
文件大小压缩
图片压缩
Tree Shaking
代码分离
内联 chunk
常见的提升构建速度的手段有如下:
优化 loader 配置
合理使用 resolve.extensions
优化 resolve.modules
优化 resolve.alias
使用 DLLPlugin 插件
使用 cache-loader
terser 启动多线程
合理使用 sourceMap
HTTP
(HyperText Transfer Protocol),即超文本运输协议,是实现网络通信的一种规范HTTPS = HTTP + SSL/TLS
区别:
HTTPS是HTTP协议的安全版本,HTTP协议的数据传输是明文的,是不安全的,HTTPS使用了SSL/TLS协议进行了加密处理,相对更安全
HTTP 和 HTTPS 使用连接方式不同,默认端口也不一样,HTTP是80,HTTPS是443
HTTPS 由于需要设计加密以及多次握手,性能方面不如 HTTP
HTTPS需要SSL,SSL 证书需要钱,功能越强大的证书费用越高
SSL
的实现这些功能主要依赖于三种手段:
对称加密:采用协商的密钥对数据加密(对称加密指的是加密和解密使用的秘钥都是同一个,是对称的。)
非对称加密:实现身份认证和密钥协商(非对称加密,存在两个秘钥,一个叫公钥,一个叫私钥。两个秘钥是不同的,公钥可以公开给任何人使用,私钥则需要保密。公钥和私钥都可以用来加密解密,但公钥加密后只能用私钥解 密,反过来,私钥加密后也只能用公钥解密)
对称加密+非对称加密,也就是混合加密
摘要算法:验证信息的完整性
数字签名:身份验证
七层划分为:应用层、表示层、会话层、传输层、网络层、数据链路层、物理层。(记忆口诀:物联网传输,会话表示应用)
五层划分为:应用层、传输层、网络层、数据链路层、物理层。
四层划分为:应用层、传输层、网络层、网络接口层。
HTTP1.0:
浏览器与服务器只保持短暂的连接,浏览器的每次请求都需要与服务器建立一个TCP连接
HTTP1.1:
引入了持久连接,即TCP连接默认不关闭,可以被多个请求复用
在同一个TCP连接里面,客户端可以同时发送多个请求
虽然允许复用TCP连接,但是同一个TCP连接里面,所有的数据通信是按次序进行的,服务器只有处理完一个请求,才会接着处理下一个请求。如果前面的处理特别慢,后面就会有许多请求排队等着
新增了一些请求方法
新增了一些请求头和响应头
HTTP2.0:
采用二进制格式而非文本格式
完全多路复用,而非有序并阻塞的、只需一个连接即可实现并行
使用报头压缩,降低开销
服务器推送
1 表示消息
2 表示成功
3 表示重定向
4 表示请求错误
5 表示服务器错误
GET在浏览器回退时是无害的,而POST会再次提交请求。
GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留。
GET请求在URL中传送的参数是有长度限制的,而POST没有。
GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。
GET参数通过URL传递,POST放在Request body中
从输入
URL
到回车后发生的行为如下:
URL解析
DNS 查询
TCP 连接
HTTP 请求
响应请求
页面渲染
关于页面的渲染过程如下:
解析HTML,构建 DOM 树
解析 CSS ,生成 CSS 规则树
合并 DOM 树和 CSS 规则,生成 render 树
布局 render 树( Layout / reflow ),负责各元素尺寸、位置的计算
绘制 render 树( paint ),绘制页面像素信息
浏览器会将各层的信息发送给 GPU,GPU 会将各层合成( composite ),显示在屏幕上
前端需要知道的http系列(二)三次握手和四次挥手 - 知乎
进程是对正在运行中的程序的一个抽象,线程是进程中的一个执行任务(控制单元),负责当前进程中程序的执行,一个进程至少有一个线程,一个进程可以运行多个线程。
区别:
本质区别:进程是操作系统资源分配的基本单位,而线程是任务调度和执行的基本单位
在开销方面:每个进程都有独立的代码和数据空间(程序上下文),程序之间的切换会有较大的开销;线程可以看做轻量级的进程,同一类线程共享代码和数据空间,每个线程都有自己独立的运行栈和程序计数器(PC),线程之间切换的开销小
所处环境:在操作系统中能同时运行多个进程(程序);而在同一个进程(程序)中有多个线程同时执行(通过CPU调度,在每个时间片中只有一个线程执行)
内存分配方面:系统在运行的时候会为每个进程分配不同的内存空间;而对线程而言,除了CPU外,系统不会为线程分配内存(线程所使用的资源来自其所属进程的资源),线程组之间只能共享资源
包含关系:没有线程的进程可以看做是单线程的,如果一个进程内有多个线程,则执行过程不是一条线的,而是多条线(线程)共同完成的;线程是进程的一部分,所以线程也被称为轻权进程或者轻量级进程。举个例子:进程=火车,线程=车厢
栈(stack)又名堆栈,它是一种运算受限的线性表,限定仅在表尾进行插入和删除操作的线性表(
先进后出
)跟栈十分相似,队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作(
先进先出
)
二叉树满足以下两个条件:
本身是有序树
树中包含的各个结点的不能超过 2,即只能是 0、1 或者 2
关于二叉树的遍历,常见的有:
看根的位置
前序遍历(根左右)
中序遍历(左根右)
后序遍历(左右根)
自己看
参考文献:web前端面试 - 面试官系列