面试感悟:当经历所有大厂的实习面试后

七月虽然不是一个丰收的季节,但却是一个十分酷热的月份。不知有多少小伙伴跟我一样,顶着大太阳奔波在各种面试的征途中。面试是一个漫长的过程。但是也是一个让你快速提升的过程。其中包含了无数的血与泪。去面试前首先我们必须有牢固的基础知识,足够丰富的项目经历(就我而言差不多是三个完整项目经历,时间累计差不多接近一年)。然后就是表述能力,你要能把你的答案给面试官描述清楚,注意专业词汇,这将大大提高面试官对你的印象分!

前言

学而不思则罔,思而不学则殆。当走完基本所有大厂之后,发现其实每个公司对基础能力的考察都比较注重,只有基础掌握好了,把前端所有的知识能够一连串的理清。那么不管面试题是什么,都可以游刃有余的去回答。这里就是把我所有面试过的问题的一些底层原理阐述,并不会去描述我在面试中碰到的题目。这样一方面可以帮你过一遍js的基础也可以帮助我加深理解。下面我就分模块的去讲解没一个知识点。篇幅过长,请耐心阅读!!!

一、CSS面试篇

1、盒子模型

css中的盒子模型包括IE盒子模型和标准的W3C盒子模型。其盒子模型还是要归宗于box-sizing的属性,盒子模型对应的分被为border-box,content-box。所谓的标准盒子模型(border-box):width = 左右border+左右padding+contentwidth,而我们的IE盒子模型(border-box): width = content+padding+border 元素指定的任何内边距和边框都将在已设定的宽度和高度内进行绘制。

2、前端一像素问题(画一条0.5px的线)

方法一:transform:scaleY(0.5)使用伪元素设置1px的边框,然后对边框进行缩放(scaleY) 实现思路:

  • 1、设定目标元素的参考位置
  • 2、给目标元素添加一个伪元素before或者after,并设置绝对定位
  • 3、给伪元素添加1px的边框
  • 4、用box-sizing: border-box 属性把边框都包进宽和高里面
  • 5、宽和高设置为 200%
  • 6、整个盒子模型缩小为0.5
  • 7、调整盒子模型的位置,以左上角为基准 transform-origin: 0

方法二: border-image 设置图片的边框

3、transition和animation的区别

Animation和transition大部分属性是相同的,他们都是随时间改变元素的属性值,他们的主要区别是transition需要触发一个事件才能改变属性, 而animation不需要触发任何事件的情况下才会随时间改变属性值,并且transition为2帧,从from …. to,而animation可以一帧一帧的。

4、不定高的DIV居中

1.使用flex

在父盒子设置display: flex; justify-content: center;align-items: center
复制代码

2.使用css的transform

父盒子设置:display:relative
	Div 设置: transform: translate(-50%,-50%);position: absolute;top: 50%;left: 50%;
复制代码

3.display:table-cell

父盒子设置:display:table-cell; text-align:center;vertical-align:middle;
	Div 设置: display:inline-block;vertical-align:middle;
复制代码

5、浮动相应链接

  • 特性:浮动元素影响的不仅是自己,他会影响周围元素对其进行环绕
  • 为什么要清除浮动?(解决父元素高度坍陷问题) 一个块级元素如果没有设置height,其height由子元素撑开,对子元素使用了浮动之后,子元素就会脱离文档流也就是说,父及元素中没有内容可以撑开其高度,这样父级元素height就会被忽略。这就是所谓的高度坍塌
  • 如何清除浮动
1.给父级元素定义高度 
2.让父级元素也浮动 
3.父级定义display:table 
4.父元素设置overflow:hidden 
5.clearfix:使用内容生成的方式清除浮动
	.clearfix:after {  // :after选择器向选定的元素之后插入内容
   		    content:""; // 生成内容为空
   		    display: block; // 块级元素显示
   		    clear:both; // 清除前面元素
	}
不破坏文档流,没有副作用
复制代码

6、css选择器分类

基本的:
	1.id选择器(id="name")
	2.类选择器(class="head")
	3.标签选择器(body, div, ul, li)
	4.全局选择器(*)
复杂的:
	1.组合选择器(.head .head_logo)
	2.后代选择器 (#head .nav ul li 从父集到子孙集)
	3.群组选择器 (div, span, img {color:Red} 具有相同样式的标签分组显示)
	4.继承选择器
	5.伪类选择器(链接样式,a元素的伪类)
	6.子选择器(div>p, 带大于号>)
	7.CSS相邻相邻兄弟选择器(h1+p, 带加号+)
复制代码

优先级:

不同级别:总结排序:!important > 行内样式 > ID选择器 > 类选择器 > 标签 > 通配符 > 继承 > 浏览器默认属性

  • 1.属性后面加!import 会覆盖页面内任何位置定义的元素样式
  • 2.作为style属性写在元素内的样式
  • 3.id选择器
  • 4.类选择器
  • 5.标签选择器
  • 6.通配符选择器(*)
  • 7.浏览器自定义或继承

同一级别:后写的会覆盖先写的

css选择器的解析原则:选择器定位DOM元素是从右往左的方向,这样可以尽早的过滤掉一些不必要的样式规则和元素

7、行内元素和块元素

块元素 行内元素
块元素会独占一行,默认情况下,其宽度自动填满父元素宽度 行元素不会占据一行,会一直排在一行,直到一行排不下 行元素没有宽度和高度属性,块级元素即使设置了宽度,还是会独占一行
块级元素: div p forn ul li h1-h6 行内元素:span img input a i

注意:对于行内元素,font-size指定 他们的content area的高度,由于inline box = 上下的helf-leading,如果leading为0,在这种情况下,font-size指定了inline box的高度font-size指的是字体的高度,但是不能指定每个字形给定字体高度下的实际高度,导致了span的高度大于line-height

8、如何画一个三角形

设置宽高,然后用border去画
  		width: 0;
        	height: 0;
        	border-bottom: 100px solid cyan;
        	border-left: 50px solid transparent;
        	border-right: 50px solid transparent;
复制代码

9、使元素消失的方法

visibility:hidden、display:none、z-index=-1、opacity:0

  • 1.opacity:0,该元素隐藏起来了,但不会改变页面布局,并且,如果该元素已经绑定了一些事件,如click事件也能触发
  • 2.visibility:hidden,该元素隐藏起来了,但不会改变页面布局,但是不会触发该元素已经绑定的事件
  • 3.display:node, 把元素隐藏起来,并且会改变页面布局,可以理解成在页面中把该元素删掉

10、为什么css放在顶部而js写在后面

  • 1.浏览器预先加载css后,可以不必等待HTML加载完毕就可以渲染页面了
  • 2.其实HTML渲染并不会等到完全加载完在渲染页面,而是一边解析DOM一边渲染。
  • 3.js写在尾部,主要是因为js主要扮演事件处理的功能,一方面很多操作是在页面渲染后才执行的。另一方面可以节省加载时间,使页面能够更加的加载,提高用户的良好体验

但是随着JS技术的发展,JS也开始承担页面渲染的工作。比如我们的UI其实可以分被对待,把渲染页面的js放在前面,时间处理的js放在后面

二、布局面试

1、flex弹性布局

可以简单的使一个元素居中(包括水平和垂直居中)栅格式系统布局,bootstrap grid

2、三栏是布局

三栏是布局(两边两栏宽度固定,中间栏宽度自适应)

  • 方案一:position(绝对定位法) center的div需要放在最后面 绝对定位法原理将左右两边使用absolute定位,因为绝对定位使其脱离文档流,后面的center会自然流动到他们的上卖弄,然后margin属性,留出左右两边的宽度。就可以自适应了。
  • 方案二:float 自身浮动法 center的div需要放到后面 自身浮动法的原理就是对左右使用float:left和float:right,float使左右两个元素脱离文档流,中间的正常文档流中,使用margin指定左右外边距对其进行一个定位。
  • 方案三(圣杯布局):原理就是margin负值法。使用圣杯布局首先需要在center元素外部包含一个div,包含的div需要设置float属性使其形成一个BFC,并且这个宽度和margin的负值进行匹配

3、左边定宽,右边自适应

  • 方案一:左边设置浮动,右边宽度设置100% .left{float:left} .right:{width:100%}
  • 方案二:左设置浮动,右用cacl去补宽度计算 .left{float:left} .right:{width:cacl(100vw-200px}
  • 方案三:父容器设置display:flex right部分是设置flex:1
  • 方案四:右边div套个包裹、并前置、左及包裹 双浮动

4、水平居中

行内元素居中(父元素text-align:center)
	块状元素居中(块状元素没发用text-align)
		1.宽度一定:margin:auto
		2.宽度不定:块级变行内,然后在父上text-aligin
复制代码

5、BFC

理解:BFC是css布局的一个概念,是一块独立的渲染区域,一个环境,里面的元素不会影响到外部的元素
如何生成BFC:(脱离文档流)
	     【1】根元素,即HTML元素(最大的一个BFC)
	     【2】float的值不为none
	     【3】position的值为absolute或fixed
	     【4】overflow的值不为visible(默认值。内容不会被修剪,会呈现在元素框之外)
	     【5】display的值为inline-block、table-cell、table-caption
BFC布局规则:1.内部的Box会在垂直方向,一个接一个地放置。
	     2.属于同一个BFC的两个相邻的Box的margin会发生重叠
	     3.BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之也如此, 文字环绕效果,设置float
	     4.BFC的区域不会与float box重叠。
	     5.计算BFC的高度,浮动元素也参与计算
BFC作用:1.自适应两栏布局
	 2.可以阻止元素被浮动元素覆盖
	 3.可以包含浮动元素---清除内部浮动 原理::触发父div的BFC属性,使下面的子div都处在父div的同一个BFC区域之内
	 4.分属于不同的BFC时,可以阻止margin重叠
复制代码

三、js面试篇

1、前端事件流

事件流描述的是从页面中接受事件的顺序,可以分为:事件捕获阶段 处于目标阶段 事件冒泡阶段其中需要主要的是addeventListener这个函数 最后这个布尔值参数如果是true,表示在捕获阶段调用事件处理程序;如果是false,表示在冒泡阶段调用事件处理程序。

  • 1、事件捕获阶段:实际目标div在捕获阶段不会接受事件,也就是在捕获阶段,事件从document到再到就停止了
  • 2、处于目标阶段:事件在div发生并处理,但是事件处理会被看成是冒泡阶段的一部分。
  • 3、冒泡阶段:事件又传播回文档
阻止冒泡事件event.stopPropagation()
 		  function stopBubble(e) {
   		if (e && e.stopPropagation) { // 如果提供了事件对象event 这说明不是IE浏览器
  		e.stopPropagation()
    		} else {
  		window.event.cancelBubble = true //IE方式阻止冒泡
    	      }
  		   }
阻止默认行为event.preventDefault()
	 function stopDefault(e) {
	    if (e && e.preventDefault) {
         e.preventDefault()
        } else {
            // IE浏览器阻止函数器默认动作的行为
            window.event.returnValue = false
        }
    }
复制代码

事件如何先捕获后冒泡:

在DOM标准事件模型中,是先捕获后冒泡。但是如果要实现先冒泡后捕获的效果,对于同一个事件,监听捕获和冒泡,分别对应相应的处理函数,监听到捕获事件,先暂缓执行,直到冒泡事件被捕获后再执行捕获事件。

哪些事件不支持冒泡事件:

鼠标事件:mouserleave  mouseenter
焦点事件:blur focus
UI事件:scroll resize
复制代码

2、事件委托(提高性能)

简介:事件委托指的是,不在事件的(直接dom)上设置监听函数,而是在其父元素上设置监听函数。通过事件冒泡,父元素可以监听到子元素上事件的触发通过判断事件发生元素DOM的类型,来做出不同的响应。

  • 举例子: 最经典的就是ui和li标签的事件监听,比如我们在添加事件的时候,采用事件委托机制,不会在li标签上直接添加,而是在ul父元素上添加
  • 好处:可以比较合适动态元素的绑定,新添加的子元素也会监听函数,也可以有事件触发机制

3、js的new操作符做了什么

new操作符创建了一个空对象,这个对象原型指向构造函数的prototype,执行构造函数后返回这个对象。如果不要父类的属性跟方法,在函数的prototype上去new这个父类。

4、this的指向

  • 1、当函数作为对象的方法被调用时,this就会指向该对象。
  • 2、作为普通函数,this指向window。
  • 3、构造器调用,this指向返回的这个对象。
  • 4、箭头函数 箭头函数的this绑定看的是this所在函数定义在哪个对象下,就绑定哪个对象。如果有嵌套的情况,则this绑定到最近的一层对象上

4.1、箭头函数this的原理:

this指向的固定化,并不是因为箭头函数内部有绑定this的机制,实际原因是箭头函数根本没有自己的this,导致内部的this就是外层代码块的this。正是因为它没有this,所以也就不能用作构造函数。

4.2、怎么改变this的指向呢?

1.使用es6的箭头函数;2.在函数内部使用that = this;3.使用apply,call,bind; 4.new实例化一个对象

4.3、bind,apply,call的区别

通过apply和call改变函数的this指向,他们两个函数的第一个参数都是一样的表示要改变指向的那个对象,第二个参数,apply是数组,而call则是arg1,arg2…这种形式。bind一个是返回一个函数,并不会立即执行第二个是带参数(第一个参数要指向的this,后面的的参数用来传递

5、深浅拷贝参考链接

基本类型 引用类型
基本类型:undefined,null,Boolean,String,Number,Symbol在内存中占据固定大小,保存在栈内存中 引用类型:Object,Array,Date,Function,RegExp等 引用类型的值是对象 保存在堆内存中,栈内存存储的是对象的变量标识符以及对象在堆内存中的存储地址。
基本类型的复制:其实就是创建了一个新的副本给将这个值赋值给新变量, 改变值旧对象不会改变 引用类型的复制:其实就是复制了指针,这个最终都将指向同一个对象,改变其值新对象也会改变

注意:基本类型的比较 == 会进行类型转换

浅拷贝 深拷贝
仅仅就是复制了引用,彼此操作不影响,slice() concat() object.assign 在堆中重新分配内存,不同的地址,相同的值,互不影响的 JSON.parse()将一个js对象序列化为一个json字符串JSON.stringify()将json字符串反序列化为一个js对象 es6的展开 {…}
重新在堆栈中创建内存,拷贝前后对象的基本类型互不影响。只拷贝一层,不能对对象进行子对象进行拷贝 对对象中的子对象进行递归拷贝,拷贝前后两个对象互不影响

6、setTimeout和setInterval的机制

因为js是单线程的。浏览器遇到etTimeout和setInterval会先执行完当前的代码块,在此之前会把定时器推入浏览器的待执行时间队列里面,等到浏览器执行完当前代码之后会看下事件队列里有没有任务,有的话才执行定时器里的代码

7、前端跨域问题

同源策略(协议+端口号+域名要相同)

  • 1、jsonp跨域(只能解决get) 原理:动态创建一个script标签。利用script标签的src属性不受同源策略限制,因为所有的src属性和href属性都不受同源策略的限制,可以请求第三方服务器资源内容
	步骤:1.去创建一个script标签
		      2.script的src属性设置接口地址
		      3.接口参数,必须要带一个自定义函数名,要不然后台无法返回数据
		      4.通过定义函数名去接受返回的数据    	
复制代码
  • 2、document.domain 基础域名相同 子域名不同
  • 3、window.name 利用在一个浏览器窗口内,载入所有的域名都是共享一个window.name
  • 4、服务器设置对CORS的支持 原理:服务器设置Access-Control-Allow-Origin HTTP响应头之后,浏览器将会允许跨域请求
  • 利用h5新特性window.postMessage()
iframe元素创建包含另外一个文档的内联框架(行内框架)(setTimeout进行异步加载)
      解释:浏览器中的浏览器!用于设置文本或者图形的浮动图文框或容器
      它和跨域
        1、document.domain 实现主域名相同,子域名不同的网页通信
          都设置为超域:document.domain = 'demo.com'
        2、window.postMessageht(data, url),h5的API,启动跨域通信
复制代码

8、图片预加载和懒加载

8.1、预加载:

提前加载图片,当用户需要查看是可以直接从本地缓存中渲染

为什么要使用预加载:在网页加载之前,对一些主要内容进行加载,以提供用户更好的体验,减少等待时间。否则,如果一个页面的内容过于庞大,会出现留白。

解决页面留白的方案: 1.预加载

2.使用svg站位图片,将一些结构快速搭建起来,等待请求的数据来了之后,替换当前的占位符

实现预加载的方法:

		1.使用html标签
		2.使用Image对象
		3.使用XMLHTTPRequest对像,但会精细控制预加载过程
复制代码

8.2、懒加载(lazyload)

客户端优化,减少请求数和延迟请求数,提升用户体验,减少无效资源的加载,防止并发加载的资源过多会阻塞js的加载,影响网站的正常使用

原理:首先将页面上的图片的src属性设置为空字符串,而图片的真是路经则设置带data-original属性中,当页面滚动的时候需要去监听scroll事件,在scroll事件的回调中,判断我们的懒加载的图片是否进入到可视区域,如果图片在可视区域将图片的src属性设置为data-original的值,这样就可以实现延迟加载。

9、函数节流和防抖

防抖 节流
短时间内多次触发同一个事件,只执行最后一次,或者在开始时执行,中间不执行。比如公交车上车,要等待最后一个乘客上车 节流是连续触发事件的过程中以一定时间间隔执行函数。节流会稀释你的执行频率,比如每间隔1秒钟,只会执行一次函数,无论这1秒钟内触发了多少次事件

都为解决高频事件而来, scroll mousewhell mousemover touchmove onresize,后面有相应的代码实现函数的节流和防抖。

10、js垃圾回收机制

1.JS具有自动垃圾收集的机制
2.JS的内存生命周期(变量的生命)
	1.分配你所需要的空间 var a = 20
	2.使用分配带的内存(读写) alert(a + 10)
	3.不适用的时候,释放内存空间 a = null 
3.JS的垃圾收集器每隔固定的时间就执行一次释放操作,通用的是通过标记清除的算法
4.在局部作用域中,垃圾回收器很容易做出判断并回收,全局比较难,因此应避免全局变量

   标记清除算法:js最常见的垃圾回收方式,当变量进入执行环境的时候,比如函数中声明一个变量,垃圾回收器将他标记为'进入环境',
		 当变量离开(函数执行完后),就其标记为'离开环境'。垃圾回收器会在运行的时候给存储在内存中的所有变量加上标记,
		 然后去掉环境中的变量以及被环境中该变量所引用的变量(闭包)。在这些完成之后仍存在标记的就是要删除的变量了
复制代码

11、一些检验方法

千万不要使用typeof来判断对象和数组,因为这种类型都会返回object。

  • typeOf()是判断基本类型的Boolean,Number,symbol, undefined, String。 对于引用类型:除function,都返回object null返回object。
  • installOf() 用来判断A是否是B的实例,installof检查的是原型。
  • toString() 是Object的原型方法,对于 Object 对象,直接调用 toString() 就能返回 [Object Object] 。而对于其他对象,则需要通过 call / apply 来调用才能返回正确的类型信息。
  • hasOwnProperty()方法返回一个布尔值,指示对象自身属性中是否具有指定的属性,该方法会忽略掉那些从原型链上继承到的属性。
  • isProperty()方法测试一个对象是否存在另一个对象的原型链上。
  • valueof:所有对象都有valueof,如果存在任意原始值,他就默认将对象转化为表示它的原始值。如果对象是复合值,而却大部分对象无法真正表示一个原始值,因此默认的valueof()方法简单的返回对象本身,而不是返回原始值

12、splice和slice、map和forEach、 filter()、reduce()的区别

 1.slice(start,end):方法可以从已有数组中返回选定的元素,返回一个新数组,包含从start到end(不包含该元素)的数组方法
	注意:该方法不会更新原数组,而是返回一个子数组
 2.splice():该方法想或者从数组中添加或删除项目,返回被删除的项目。(该方法会改变原数组)
	splice(index, howmany,item1,...itemx)
		·index参数:必须,整数规定添加或删除的位置,使用负数,从数组尾部规定位置
		·howmany参数:必须,要删除的数量,
		·item1..itemx:可选,向数组添加新项目
3.map():会返回一个全新的数组。使用于改变数据值的时候。会分配内存存储空间数组并返回,forEach()不会返回数据
4.forEach(): 不会返回任何有价值的东西,并且不打算改变数据,单纯的只是想用数据做一些事情,他允许callback更改原始数组的元素
5.reduce(): 方法接收一个函数作为累加器,数组中的每一个值(从左到右)开始缩减,最终计算一个值,不会改变原数组的值
6.filter(): 方法创建一个新数组,新数组中的元素是通过检查指定数组中符合条件的所有元素。它里面通过function去做处理	
复制代码

13、js\css阻塞

js阻塞 css阻塞
所有浏览器在下载JS的时候,会阻止一切其他活动,比如其他资源的下载,内容的呈现等等。直到JS下载、解析、执行完毕后才开始继续并行下载其他资源并呈现内容。为了提高用户体验,新一代浏览器都支持并行下载JS,但是JS下载仍然会阻塞其它资源的下载(例如.图片,css文件等)。 因为浏览器会维持html中css和js的顺序,样式表必须在嵌入的JS执行前先加载、解析完。而嵌入的JS会阻塞后面的资源加载,所以就会出现上面CSS阻塞下载的情况。

14、类的创建和继承

(es6)中class, extends

14.1、 继承:

  • 原型链继承: function Cat(){ } Cat.prototype = new Animal(); Cat.prototype.name = ‘cat’; 无法实现多继承
  • 构造继承:使用父类的构造函数来增强子类实例。function Cat(name){Animal.call(this);this.name = name || ‘Tom’;} 无法继承父类原型链上的属性跟方法 installof去检验
  • 实例继承:为父类实例添加新特性,作为子类实例的返回
  • 拷贝继承:拷贝父类元素上的属性跟方法
  • 组合继承:构造继承 + 原型继承的组合体
  • 寄生组合继承:通过寄生方式,在构造继承上加一个Super函数(没有实例和方法) 让他的原型链指向父类的原型链 砍掉父类的实例属性,这样,在调用两次父类的构造的时候,就不会初始化两次实例方法/属性

14.2 给两个构造函数A和B,如何实现A继承B (Object.prototype)

	function A(....){} A.prototype...
	function B(....){} B.prototype...
	A.prototype = Object.create(B.prototype)  再A的构造函数里new B(props)		
	
   使用new一个函数的话,函数里的构造函数的参数就为undefined,里面的一些函数可能执行错误,因为this改变了	
	Object.create =  function (o) {
		var F = function () {};
		F.prototype = o;
		return new F();
		};
复制代码

15、闭包和原型

15.1、闭包的理解

  • 1、内部函数可以访问定义他们外部函数的参数和变量。(作用域链的向上查找,把外围的作用域中的变量值存储在内存中而不是在函数调用完毕后销毁)设计私有的方法和变量,避免全局变量的污染
  • 2、函数嵌套函数
  • 3、本质是将函数内部和外部连接起来。优点是可以读取函数内部的变量,让这些变量的值始终保存在内存中,不会在函数被调用之后自动清除

15.2、闭包的缺陷:

1.闭包的缺点就是常驻内存会增大内存使用量,并且使用不当容易造成内存泄漏
2.如果不是因为某些特殊任务而需要闭包,在没有必要的情况下,在其它函数中创建函数是不明智的,因为闭包对脚本性能具有负面影响,包括处理速度和内存消耗。   
复制代码

15.3、内存的理解

内存溢出和内存泄漏(给的不够用| 用了不归还)

  • 1、内存溢出:在程序中申请内存时,没有足够的内存空间供其使用,出现out of memory;比如申请了一个integer,但给它存了long才能存下的数,那就是内存溢出
  • 2、内存泄漏:在程序申请内存后,无法释放已申请的内存空间,一次内存泄漏危害可以忽略,但内存泄漏堆积后果很严重,无论多少内存,迟到会被占光 举列子:闭包中的this,对象函数。匿名函数返回函数return function

15.4、作用域

作用域:(由当前环境与上层环境一系列的变量对象组成!!!保证当先执行环境里,有权访问的变量和函数是有序的,作用域链变量只能被向上访问)

定义:由当前环境与上层环境的一系列变量对象组成(函数嵌套函数,内部一级级往上有序访问变量或对象)

作用是:保证当前执行环境里,有权访问的变量和函数时有序的,作用域链的变量只能被向上访问 变量访问到window对象及被终止,作用域链向下访问是不允许的 1.改变作用域有 with try..中的catch, 2.所有为定义的直接赋值的变量自动声明为全局作用域

作用域:一套规则,管理引擎如何在当前作用域以及嵌套的子作用域中根据标识符名称
	查找变量(标识符就是变量或者函数名)(只用全局作用域和局部作用域)(作用域在它创建的时候就存在了)

代码执行分为两个阶段:
	1.代码编译阶段:有编译器完成,将代码翻译可执行的代码,这个阶段会被确定
	2.代码执行阶段:有js引擎完成,主要执行可执行的大妈,这个阶段执行上下文被创建(对象被创建)

执行上下文:一个看不见得对象,存在若干个属性和变量,它被调用的时候创建的。函数被调用查看的this指向的object,object就是上下文(只有被调用的时候创建)
复制代码

15.5、作用域链参考链接

    · 当代码在一个环境中执行时,会创建变量对象的一个作用域链,
	举例子:var name ="Tom"
		function sayHi () {
		    alert('Hi,'+name)
		}
		sayHi()  //Hi, Tom
	函数sayHi()的执行环境为全局环境,所以它的变量对象为window。当函数执行到name时,先查找局部环境,找到则换回,否则顺着作用域查找,在全局环境中,
	找到name返回,这一查找变量的有序过程的依据就是作用域。

    · 作用域链是保证执行环境有权访问的所有变量和函数的有序访问
复制代码

15.6、原型链

原型链:函数的原型链对象constructor默认指向函数本身,原型对象除了有原型属性外,为了实现继承,还有一个原型链指针_proto_,该指针是指向上一层的原型对象,而上一层的原型对象的结构依然类似。因此可以利用_proto_一直指向Object的原型对象上,而Object原型对象用Object.prototype.proto=null表示原型链顶端。如此形成了js的原型链继承。同时所有的js对象都有Object的基本防范

四、服务器端面试篇

1、状态码

2XX(成功处理了请求状态)
          200 服务器已经成功处理请求,并提供了请求的网页
          201 用户新建或修改数据成功
          202 一个请求已经进入后台
          204 用户删除成功
3XX(每次请求使用的重定向不要超过5次)
          304 网页上次请求没有更新,节省带宽和开销
4XX(表示请求可能出错,妨碍了服务器的处理)
          400 服务器不理解请求的语法
          401 用户没有权限(用户名,密码输入错误)
          403 用户得到授权(401相反),但是访问被禁止
          404 服务器找不到请求的网页,
5XX(表示服务器在处理请求的时候发生内部错误)
          500 服务器遇到错误,无法完成请求
          503 服务器目前无法使用(超载或停机维护)
复制代码

2、304的缓存原理(添加Etag标签.last-modified)

  • 1.服务器首先产生Etag,服务器可在稍后使用它来判断页面是否被修改。本质上,客户端通过该记号传回服务器要求服务器验证(客户端)缓存)
  • 2.304是HTTP的状态码,服务器用来标识这个文件没有被修改,不返回内容,浏览器接受到这个状态码会去去找浏览器缓存的文件
  • 3.流程:客户端请求一个页面A。服务器返回页面A,并在A上加一个Tage客服端渲染该页面,并把Tage也存储在缓存中。客户端再次请求页面A并将上次请求的资源和ETage一起传递给服务器。服务器检查Tage.并且判断出该页面自上次客户端请求之后未被修改。直接返回304

last-modified: 客服端请求资源,同时有一个last-modified的属性标记此文件在服务器最后修改的时间,客服端第二次请求此url时,根据http协议。浏览器会向服务器发送一个If-Modified-Since报头,询问该事件之后文件是否被修改,没修改返回304

 有了Last-Modified,为什么还要用ETag?
  1、因为如果在一秒钟之内对一个文件进行两次更改,Last-Modified就会不正确(Last—Modified不能识别秒单位的修改)
  2、某些服务器不能精确的得到文件的最后修改时间
  3、一些文件也行会周期新的更改,但是他的内容并不改变(仅仅改变修改的事件),这个时候我们并不希望客户端认为文件被修改,而重新Get

ETag,为什么还要用Last-Modified?
  1、两者互补,ETag的判断的缺陷,比如一些图片等静态文件的修改
  2、如果每次扫描内容都生成ETag比较,显然要比直接比较修改时间慢的多。


ETag是被请求变量的实体值(文件的索引节,大小和最后修改的时间的Hash值)
  1、ETag的值服务器端对文件的索引节,大小和最后的修改的事件进行Hash后得到的。
复制代码

3、get/post的区别

  • 1.get数据是存放在url之后,以?分割url和传输数据,参数之间以&相连; post方法是把提交的数据放在http包的Body中
  • 2.get提交的数据大小有限制,(因为浏览器对url的长度有限制),post的方法提交的数据没有限制
  • 3.get需要request.queryString来获取变量的值,而post方式通过request.from来获取变量的值
  • 4.get的方法提交数据,会带来安全问题,比如登录一个页面,通过get的方式提交数据,用户名和密码就会出现在url上

4、http和https的总结

4.1、http协议的理解

1.超文本的传输协议,是用于从万维网服务器超文本传输到本地资源的传输协议
2.基于TCP/IP通信协议来传递数据(HTML,图片资源)
3.基于运用层的面向对象的协议,由于其简洁、快速的方法、适用于分布式超媒体信息系统
4.http请求信息request:
	请求行(request line)、请求头部(header),空行和请求数据四部分构成

	请求行,用来说明请求类型,要访问的资源以及所使用的HTTP版本.
	请求头部,用来说明服务器要使用的附加信息
	空行,请求头部后面的空行是必须的
	请求数据也叫主体,可以添加任意的其他数据。
5.http相应信息Response
	状态行、消息报头、空行和响应正文

	状态行,由HTTP协议版本号, 状态码, 状态消息 三部分组成
	消息报头,用来说明客户端要使用的一些附加信息
	空行,消息报头后面的空行是必须的
	响应正文,服务器返回给客户端的文本信息。
复制代码

4.2、http和https的区别

http https
是以安全为目标的HTTP通道,简单讲是HTTP的安全版本,通过SSL加密 超文本传输协议。是一个客服端和服务器端请求和应答的标准(tcp),使浏览器更加高效,使网络传输减少

4.3、http1.0、1.1、2.0的区别

1.0跟1.1的区别:

长连接:HTTP1.0需要使用keep-alive参数来告知服务器建立一个长连接,而HTP1.1默认支持长连接

节约宽带:HTTP1.1支持只发送一个header信息(不带任何body信息)

host域(设置虚拟站点,也就是说,webserver上的多个虚拟站点可以共享同一个ip端口):HTTP1.0没有host域

1.1跟2.0的区别:

  • 1.http2采用的二进制文本传输数据,而非http1文本格式,二进制在协议的解析和扩展更好
  • 2.数据压缩:对信息头采用了HPACK进行压缩传输,节省了信息头带来的网络流量
  • 3.多路复用:一个连接可以并发处理多个请求
  • 4.服务器推送:我们对支持HTTP2.0的webserver请求数据的时候,服务器会顺便把一些客户端需要的资源一起推送到客户端,免得客户端再次创建连接发送请求到服务器端获取。这种方式非常合适加载静态资源

5、web总结

5.1、web缓存

1.web缓存就是存在于客户端与服务器之间的一个副本、当你第一个发出请求后,缓存根据请求保存输出内容的副本
2.缓存的好处
        (1)减少不必要的请求
	(2)降低服务器的压力,减少服务器的消耗
	(3)降低网络延迟,加快页面打开速度(直接读取浏览器的数)
复制代码

5.2、常见的web安全及防护原理

  • 1.sql注入原理:通郭sql命令插入到web表单递交或者输入活命,达到欺骗服务器执行的恶意sql命令 防范:1.对用户输入进行校验 2.不适用动态拼接sql
  • 2.XSS(跨站脚本攻击):往web页面插入恶意的html标签或者js代码。 举例子:在论坛放置一个看是安全的链接,窃取cookie中的用户信息 防范:1.尽量采用post而不使用get提交表单 2.避免cookie中泄漏用户的隐式
  • 3.CSRF(跨站请求伪装):通过伪装来自受信任用户的请求 举例子:黄轶老师的webapp音乐请求数据就是利用CSRF跨站请求伪装来获取QQ音乐的数据 防范:在客服端页面增加伪随机数,通过验证码
  • XSS和CSRF的区别: 1.XSS是获取信息,不需要提前知道其他用户页面的代码和数据包 2.CSRF代替用户完成指定的动作,需要知道其他页面的代码和数据包

5.3、CDN(内容分发网络)

1.尽可能的避开互联网有可能影响数据传输速度和稳定性的瓶颈和环节。使内容传输的更快更稳定。
2.关键技术:内容存储和分发技术中
3.基本原理:广泛采用各种缓存服务器,将这些缓存服务器分布到用户访问相对的地区或者网络中。当用户访问网络时利用全局负载技术
	    将用户的访问指向距离最近的缓存服务器,由缓存服务器直接相应用户的请求(全局负载技术)
复制代码

6、前端呈现流程(TCP三次握手,DOM树渲染)

6.1、从输入url到获取页面的完整过程 参考链接

1.查询NDS(域名解析),获取域名对应的IP地址  查询浏览器缓存
2.浏览器与服务器建立tcp链接(三次握手)
3.浏览器向服务器发送http请求(请求和传输数据)
4.服务器接受到这个请求后,根据路经参数,经过后端的一些处理生成html代码返回给浏览器
5.浏览器拿到完整的html页面代码开始解析和渲染,如果遇到外部的css或者js,图片一样的步骤
6.浏览器根据拿到的资源对页面进行渲染,把一个完整的页面呈现出来
复制代码

6.2、TCP三次握手

客服端发c起请求连接服务器端s确认,服务器端也发起连接确认客服端确认。

  • 第一次握手:客服端发送一个请求连接,服务器端只能确认自己可以接受客服端发送的报文段
  • 第二次握手: 服务端向客服端发送一个链接,确认客服端收到自己发送的报文段
  • 第三次握手: 服务器端确认客服端收到了自己发送的报文段

6.3、浏览器渲染原理及流程 DOM -> CSSOM -> render -> layout -> print

流程:解析html以及构建dom树 -> 构建render树 ->  布局render树 -> 绘制render树
	概念:1.构建DOM树: 渲染引擎解析HTML文档,首先将标签转换成DOM树中的DOM node(包括js生成的标签)生成内容树
	      2.构建渲染树: 解析对应的css样式文件信息(包括js生成的样式和外部的css)
	      3.布局渲染树:从根节点递归调用,计算每一个元素的大小,位置等。给出每个节点所在的屏幕的精准位置
	      4.绘制渲染树:遍历渲染树,使用UI后端层来绘制每一个节点
   
	重绘:当盒子的位置、大小以及其他属性,例如颜色、字体大小等到确定下来之后,浏览器便把这些颜色都按照各自的特性绘制一遍,将内容呈现在页面上
		触发重绘的条件:改变元素外观属性。如:color,background-color等
		重绘是指一个元素外观的改变所触发的浏览器行为,浏览器会根据元素的新属性重新绘制,使元素呈现新的外观
	注意:table及其内部元素需要多次计算才能确定好其在渲染树中节点的属性值,比同等元素要多发时间,要尽量避免使用table布局
	
	重排(重构/回流/reflow): 当渲染书中的一部分(或全部)因为元素的规模尺寸,布局,隐藏等改变而需要重新构建,这就是回流。
		每个页面都需要一次回流,就是页面第一次渲染的时候
	重排一定会影响重绘,但是重绘不一定会影响重排
复制代码

7、前端储存总结

7.1、存储方式与传输方式

  • 1.indexBD: 是h5的本地存储库,把一些数据存储到浏览器中,没网络,浏览器可以从这里读取数据,离线运用。5m
  • 2.Cookie: 通过浏览器记录信息确认用户身份,最大4kb,这也就限制了传输的数据,请求的性能会受到影响
  • 3.Session: 服务器端使用的一种记录客户状态的机制(session_id存在set_cookie发送到客服端,保存为cookie)
  • 4.localStroage: h5的本地存储,数据永久保存在客服端
    1、cookie,sessionStorage,localStorage是存放在客户端,session对象数据是存放在服务器上
       实际上浏览器和服务器之间仅需传递session id即可,服务器根据session-id找到对应的用户session对象
        session存储数据更安全一些,一般存放用户信息,浏览器只适合存储一般的数据
    2、cookie数据始终在同源的http请求中携带,在浏览器和服务器来回传递,里面存放着session-id
       sessionStorage,localStorage仅在本地保存
    3、大小限制区别,cookie数据不超过4kb,localStorage在谷歌浏览中2.6MB
    4、数据有效期不同,cookie在设置的(服务器设置)有效期内有效,不管窗口和浏览器关闭
      sessionStorage仅在当前浏览器窗口关闭前有效,关闭即销毁(临时存储)
      localStorage始终有效	
复制代码

7.2、SessionStorage和localStorage区别:

1.sessionStorage用于本地存储一个会话(session)中的数据,这些数据只有在用一个会话的页面中才能被访问(也就是说在第一次通信过程中)
   并且在会话结束后数据也随之销毁,不是一个持久的本地存储,会话级别的储存
2.localStorage用于持久化的本地存储,除非主动删除数据,否则不会过期
复制代码

7.3、token、cookie、session三者的理解

  • 1、token就是令牌,比如你授权(登录)一个程序时,他就是个依据,判断你是否已经授权该软件(最好的身份认证,安全性好,且是唯一的)用户身份的验证方式
  • 2、cookie是写在客户端一个txt文件,里面包括登录信息之类的,这样你下次在登录某个网站,就会自动调用cookie自动登录用户名服务器生成,发送到浏览器、浏览器保存,下次请求再次发送给服务器(存放着登录信息)
  • 3、session是一类用来客户端和服务器之间保存状态的解决方案,会话完成被销毁(代表的就是服务器和客户端的一次会话过程)cookie中存放着sessionID,请求会发送这个id。sesion因为request对象而产生。

7.3、基于Token的身份验证:(最简单的token: uid用户唯一的身份识别 + time当前事件戳 + sign签名)

  1、用户通过用户名和密码发送请求
  2、服务器端验证
  3、服务器端返回一个带签名的token,给客户端
  4、客户端储存token,并且每次用于发送请求
  5、服务器验证token并且返回数据
  每一次请求都需要token
 cookie与session区别
  1、cookie数据存放在客户的浏览器上,session数据放在服务器上。
  2、cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗考虑到安全应当使用session。
  3、session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能考虑到减轻服务器性能方面,应当使用COOKIE。
  4、单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie。
复制代码

7.4、session与token区别

  • 1、session认证只是把简单的User的信息存储Session里面,sessionID不可预测,一种认证手段。只存在服务端,不能共享到其他的网站和第三方App
  • 2、token是oAuth Token,提供的是认证和授权,认证针对用户,授权是针对App,目的就是让某APP有权访问某用户的的信息。Token是唯一的,token不能转移到其他的App,也不能转到其他用户上。(适用app)
  • 3、session的状态是存在服务器端的,客户端只存在session id, Token状态是存储在客户端的

7.5、Cookie的弊端有哪些???(优势:保存客户端数据,分担了服务器存储的负担)

  1、数量和长度的限制。每个特定的域名下最多生成20个cookie(chorme和safari没有限制)
  2、安全性问题。
复制代码

五、写在后面

由于篇幅过长,我准备了一个txt文档,里面有更多的前端基础知识。包括这里未曾谈及的Vue,React,node,数据结构等。奉上我的文档地址前端面试武林秘籍,学习总是需要不断的积累和总结的。写此文的目的也很明确,若总结的不好地方欢迎指出并在下方评论,或者你认为很好的知识点,没有归纳到,也希望能够分享出来,帮助大家,也提高自己。

作者:hello等风来
链接:https://juejin.im/post/5b68f384f265da0fa00a3df0
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

赞 (35) 打赏