面试题分五部分详解

  • 前端部分
    • 基础知识(html + css + javascript)

前端部分

主要从五个方面来准备,包括基础知识(html + css + javascript)、框架(vue2、vue3)、打包工具(webpack)、协议(http、https、websocket)、其它

基础知识(html + css + javascript)

*参考网站:
参考1
参考2,推荐使用
参考3
参考4,必看网站, 推荐使用

1.一个 div(块级元素) 在不同分辨率屏幕垂直水平居中,用 css 实现

<div class="wrap"><div class="inner"></div>
</div>
/* 定位方法(1) */
.wrap{width: 300px;height: 300px; position: relative;
}
.inner{width: 40px;height: 40px;position: absolute;left: 0;right: 0;top: 0;bottom: 0;margin:auto;
}/* 定位方法(2) */
.wrap{width: 300px;height: 300px;position: relative;
}
.inner{width: 40px;height: 50px;position: absolute;left: 50%;top: 50%;margin-left:-20px;margin-top: -25px;
}/* 改变父元素和子元素的display(不推荐使用) */
.wrap{width: 300px;height: 300px;display: table-cell;text-align: center;vertical-align: middle;
}
.inner{width: 40px;height: 40px;display: inline-block;
}/* css3的弹性盒方法 */
.wrap{width: 300px;height: 300px;display: flex;justify-content: center;align-items: center;
}
.inner{width: 40px;height: 40px;
}/* 使用translate改变位置实现 */
.wrap{width: 300px;height: 300px;position: relative;
}
.inner{width: 40px;height: 40px;position: absolute;top: 50%;left: 50%;transform: translate(-50%, -50%);
}/* 使用grid布局实现 */
.wrap{width: 300px;height: 300px;display: grid;place-items: center;
}
.inner{width: 40px;height: 40px;
}

1.1.盒模型

css盒模型分俩种:IE盒子模型和标准盒子模型在 标准盒子模型中,width 和 height 指的是内容区域的宽度和高度。增加内边距、边框和外边距不会影响内容区域的尺寸,但是会增加元素框的总尺寸。IE盒子模型中,width 和 height 指的是 内容区域 + border + padding 的宽度和高度

1.2.Flex: 1

flex 属性是 flex-grow、flex-shrink、flex-basis 三个属性的缩写flex-grow:定义项目的的放大比例- 默认为0,即 即使存在剩余空间,也不会放大;- 所有项目的flex-grow为1:等分剩余空间(自动放大占位);- flex-grow为 n 的项目,占据的空间(放大的比例)是flex-grow为1的n倍。flex-shrink:定义项目的缩小比例-默认为1,即 如果空间不足,该项目将缩小;-所有项目的flex-shrink为1:当空间不足时,缩小的比例相同;-flex-shrink为0:空间不足时,该项目不会缩小;-flex-shrink为 n 的项目,空间不足时缩小的比例是flex-shrink为1的n倍。flex-basis:定义在分配多余空间之前,项目占据的主轴空间(main size),浏览器根据此属性计算主轴是否有多余空间默认值为auto,即 项目原本大小;设置后项目将占据固定空间

2.阐述清除浮动的几种方式(常见问题)

1.父级 div 定义 height原理:父级 div 手动定义 height,就解决了父级 div 无法自动获取到高度的问题优点:简单、代码少、容易掌握缺点:只适合高度固定的布局,要给出精确的高度,如果高度和父级 div 不一样时,会产生问题2.父级 div 定义 overflow: hidden原理:必须定义 width 或 zoom:1,同时不能定义 height,使用 overflow:hidden 时,浏览器会自动检查浮动区域的高度优点:简单、代码少、浏览器支持好3.额外标签法(在最后一个浮动标签后,新加一个标签,给其设置 clear: both)原理:添加一个空 div,利用 css 提高的 clear:both 清除浮动,让父级 div 能自动获取到高度优点:简单、代码少、浏览器支持好、不容易出现怪问题缺点:不少初学者不理解原理;如果页面浮动布局多,就要增加很多空div,让人感觉很不好4.使用 after 伪元素 清除浮动优点:符合闭合浮动思想,结构语义化正确缺点:ie6-7 不支持伪元素 :after,使用 zoom:1 触发 hasLayout。.clearfix:after{    /* 伪元素是行内元素 正常浏览器清除浮动方法 */content: "";display: block;height: 0;clear:both;visibility: hidden;}.clearfix{*zoom: 1;    /* ie6清除浮动的方式 *号只有IE6-IE7执行,其他浏览器不执行 */}<body><div class="fahter clearfix"><div class="big">big</div><div class="small">small</div><!--<div class="clear">额外标签法</div>--></div><div class="footer"></div></body>

5.使用 before 和 after 双伪元素清除浮动

优点:代码更简洁
缺点:用 zoom:1 触发 hasLayout..clearfix:after,.clearfix:before{content: "";display: table;
}
.clearfix:after{clear: both;
}
.clearfix{*zoom: 1;
}
<div class="fahter clearfix"><div class="big">big</div><div class="small">small</div>
</div>
<div class="footer"></div>

3.解释 css sprites ,如何使用?

概念:将多个小图片拼接到一个图片中。通过 background-position 和元素尺寸调节需要显示的背景图案。
优点:1)减少 HTTP 请求数,极大地提高页面加载速度2)增加图片信息重复度,提高压缩比,减少图片大小3)更换风格方便,只需在一张或几张图片上修改颜色或样式即可实现
缺点:1)图片合并麻烦2)维护麻烦,修改一个图片可能需要重新布局整个图片,样式CSS Sprites其实就是把网页中一些背景图片整合到一张图片文件中,再利用CSS的 "background-image","background-repeat","background-position" 的组合进行背景定位,background-position 可以用数字能精确的定位出背景图片的位置

4.如何用原生 js 给一个按钮绑定两个 onclick 事件?

var btn4 = document.getElementById("btn4")btn4.addEventListener("click",hello1)
btn4.addEventListener("click",hello2)function hello1() {alert("hello 1")
}
function hello2(){alert("hello 2")
}

5.拖拽会用到哪些事件

· dragstart:拖拽开始时在被拖拽元素上触发此事件,监听器需要设置拖拽所需数据,从操作系统拖拽文件到浏览器时不触发此事件· dragenter:拖拽鼠标进入元素时在该元素上触发,用于给拖放元素设置视觉反馈,如高亮· dragover:拖拽时鼠标在目标元素上移动时触发.监听器通过阻止浏览器默认行为设置元素为可拖放元素· dragleave:拖拽时鼠标移出目标元素时在目标元素上触发.此时监听器可以取消掉前面设置的视觉效果· drag:拖拽期间在被拖拽元素上连续触发· drop:鼠标在拖放目标上释放时,在拖放目标上触发.此时监听器需要收集数据并且执行所需操作.如果是从操作系统拖放文件到浏览器,需要取消浏览器默认行为· dragend:鼠标在拖放目标上释放时,在拖拽元素上触发.将元素从浏览器拖放到操作系统时不会触发此事件

6.请列举 jquery 中的选择器

4大类:基本选择器、层次选择器、过滤选择器、表单选择器
1、jquery 基本选择器:基本选择器是 JQuery 最常用的选择器,也是最简单的选择器,它通过元素id、class 和 标签名 来查找 DOM 元素$("#myELement")        选择 id 值等于 myElement 的元素,id 值不能重复,在文档中只能有一个 id 值是 myElement, 所以得到的是唯一元素
$("div")               选择所有的 div 标签元素,返回 div 元素数组
$(".myClass")          选择使用 myClass 类的 css 的所有元素
$("*")                 选择文档中的所有的元素,可以运用多种的选择方式进行联合选择:例如 $("#myELement,div,.myclass")注:在网页中id只能使用一次,即id具有唯一性,但class是允许重复使用的
2、jquery 层次选择器:层次选择器通过 DOM 元素间的层次关系来获取元素,主要的层次关系包括父子、后代、相邻、兄弟关系$("form input")    选择所有的 form 元素中的 input 元素
$("#main > *")     选择 id 值为 main 的所有的子元素
$("label + input") 选择所有的 label 元素的下一个 input 元素节点,经测试选择器返回的是label标签后面直接跟一个 input 标签的所有 input 标签元素
$("#prev ~ div")   同胞选择器,该选择器返回的为 id 为 prev 的标签元素的所有的属于同一个父元素的 div 标签
注:只有这个方法返回的是JQuery对象才能进行链式操作
3、jquery 过滤选择器:主要是通过特定的过滤规则来筛选出所需的DOM元素,过滤规则与CSS中的伪类选择器语法相同,即选择器都以一个冒号(:)开头。按照不同的过滤规则,过滤选择器可以分为 基本过滤,内容过滤,可见性过滤,属性过滤,子元素过滤 和 表单对象属性过滤 选择器共六种选择器(1)jquery基本过滤选择器:过滤选择器是根据某类过滤规则进行元素的匹配,书写时都以(:)开头;简单过滤选择器是过滤选择器中使用最广泛的一种$("tr:first"):选择所有tr元素的第一个$("tr:last"):选择所有tr元素的最后一个$("input:not(:checked) + span") :过滤掉:checked的选择器的所有的input元素$("tr:even"):选择所有的tr元素的第0,2,4... ...个元素(注意:因为所选择的多个元素时为数组,所以序号是从0开始)$("tr:odd"):选择所有的tr元素的第1,3,5... ...个元素$("td:eq(2)"):选择所有的td元素中序号为2的那个td元素$("td:gt(4)") :选择td元素中序号大于4的所有td元素$("td:ll(4)"):选择td元素中序号小于4的所有的td元素$(":header"):匹配如 h1, h2, h3之类的标题元素.这个是专门用来获取h1,h2这样的标题元素$("div:animated"):匹配所有正在执行动画效果的元素(2)jquery内容过滤选择器:内容过滤选择器的过滤规则主要体现在它所包含的子元素和文本内容上$("div:contains('John')") :选择所有div中含有John文本的元素$("td:empty") :选择所有的为空(也不包括文本节点)的td元素的数组$("div:has(p)") :选择所有含有p标签的div元素$("td:parent"):选择所有的以td为父节点的元素数组(3)jquery可见性过滤选择器:可见度过滤选择器是根据元素的可见和不可见状态来选择相应的元素$("div:hidden"):选择所有的被hidden的div元素$("div:visible"):选择所有的可视化的div元素(4)jquery属性过滤选择器:属性过滤选择器的过滤规则是通过元素的属性来获取相应的元素$("div[id]"): 选择所有含有id属性的div元素$("input[name='newsletter']"):选择所有的name属性等于'newsletter'的input元素$("input[name!='newsletter']") :选择所有的name属性不等于'newsletter'的input元素$("input[name^='news']"): 选择所有的name属性以'news'开头的input元素$("input[name$='news']") :选择所有的name属性以'news'结尾的input元素$("input[name*='man']") :选择所有的name属性包含'news'的input元素(5)jquery子元素过滤选择器$("ul li:nth-child(2)"),$("ul li:nth-child(odd)"),$("ul li:nth-child(3n + 1)") :匹配其父元素下的第N个子或奇偶元素.这个选择器和之前说的基础过滤(Basic Filters)中的eq() 有些类似,不同的地方就是前者是从0开始,后者是从1开始。$("div span:first-child"):返回所有的div元素的第一个子节点的数组$("div span:last-child"):返回所有的div元素的最后一个节点的数组$("div button:only-child") :返回所有的div中只有唯一一个子节点的所有子节点的数组(6) jquery表单对象属性过滤选择器:主要对所选择的表单元素进行过滤$(":enabled"):选择所有的可操作的表单元素$(":disabled"):选择所有的不可操作的表单元素$(":checked"):选择所有的被checked的表单元素$("select option:selected"):选择所有的select 的子元素中被selected的元素$(”input[@ name =S_03_22]“).parent().prev().text():选取一个 name 为”S_03_22″的input text框的上一个td的text值$(”input[@ name ^='S_']“).not(”[@ name $='_R']“):名字以”S_”开始,并且不是以”_R”结尾的$(”input[@ name =radio_01][@checked]“).val();:一个名为 radio_01的radio所选的值$("A B"):查找A元素下面的所有子节点,包括非直接子节点$("A>B") :查找A元素下面的直接子节点$("A+B") :查找A元素后面的兄弟节点,包括非直接子节点$("A~B") :查找A元素后面的兄弟节点,不包括非直接子节点
4、jquery 表单选择器:利用表单选择器我们可以极其方便地获取表单的某个或某类型的元素。注意:要选取input中为 hidden 值的方法就是上面例子的用法,但是直接使用 ":hidden" 的话就是匹配页面中所有的不可见元素,包括宽度或高度为 0 的$(":input") :选择所有的表单输入元素,包括input, textarea, select 和 button
$(":text") : 选择所有的text input元素
$(":password"): 选择所有的password input元素
$(":radio") :选择所有的radio input元素
$(":checkbox") :选择所有的checkbox input元素
$(":submit") :选择所有的submit input元素
$(":image") : 选择所有的image input元素
$(":reset") :选择所有的reset input元素
$(":button") :选择所有的button input元素
$(":file") :选择所有的file input元素
$(":hidden"):选择所有类型为hidden的input元素或表单的隐藏域

7.Javascript 中的定时器有哪些?他们的区别及用法是什么?

setTimeout 只执行一次
setInterval 会一直重复执行

8.请描述一下 cookies、sessionStorage 和 localstorage 区别

相同点:都存储在客户端不同点:1.存储大小· cookie 数据大小不能超过4k。· sessionStorage 和localStorage 虽然也有存储大小的限制,但比cookie大得多,可以达到5M或更大。2.有效时间· localStorage    存储持久数据,浏览器关闭后数据不丢失除非主动删除数据;· sessionStorage  数据在当前浏览器窗口关闭后自动删除。· cookie          设置的cookie过期时间之前一直有效,即使窗口或浏览器关闭3. 数据与服务器之间的交互方式· cookie 的数据会自动的传递到服务器,服务器端也可以写 cookie 到客户端· sessionStorage 和 localStorage 不会自动把数据发给服务器,仅在本地保存。

8.1.cookie 和 session 的区别

1.Cookie 数据保存在客户端,session 数据保存在服务端
2.session 中保存的是对象,Cookie 中保存的是字符串
3.Cookie 的安全性一般,可通过分析存放在本地的 Cookie 并进行 Cookie 欺骗。相比较下 session 更优
4.单个 Cookie 保存的数据不超过 4K,很多浏览器都限制一个站点最多保存 20 个 Cookie;session 可以放在文件、数据库或内存中
5.session 不能区分路径,同一个用户在访问一个网站期间,所有的 Session 在任何一个地方都可以访问到;Cookie 中如果设置了路径参数,那么同一个网站中不同路径下的 Cookie 互相是访问不到的
6.session 的运行依赖 session ID,而 Session ID 是存在 Cookie。也就是说,如果浏览器禁用 Cookie,那么 session 也会失效(但是可以通过其他方式实现,比如在 URL 中传递 Session ID)

8.2.防止 Cookie 欺骗

1.网上提供的解决方案:
最简单的是给 cookies 加个加密算法
保险点的是给 cookies 加个时间戳和 IP 戳,实际上就是让 cookies 在同个 IP 下多长时间内失效2.自己的最终解决方案:
username、ip、rndcode,分别为用户名、ip、随机码。数据库中多添加两个字段,分别为当前登录 ip、随机码
实现原理:(1) 加密不可逆,cookies 被获取后不起作用,其中 ip 在起着重大作用(2) 暴力破解成功,ip 换成自己机器的,可正常访问。但前提是此用户一直未登录过,否则数据库中随机码大显身手

9.编写一个方法去掉数组里面 重复的内容 var arr = [1,2,3,4,5,1,2,3]

// 1.Set()const list = [...new Set(arr)]// 2.Array.from() + new Set()const list = Array.from(new Set(arr))// 3.indexOf()let newList = []arr.map((item, index) => {if(newList.indexOf(item) == -1) {newList.push(item)}})// 4.indexOf() + filter()const list = arr.filter((item, index)=> {return arr.indexOf(item) == index})// 5.includes()let newList = []arr.map((item, index) => {!newList.includes(item) && newList.push(item)})

10.document.write 和 innerHTML 的区别

document.write是直接写入到页面的内容流,如果在写之前没有调用document.open, 浏览器会自动调用open。每次写完关闭之后重新调用该函数,会导致页面被重写innerHTML 则是 DOM 页面元素的一个属性,代表该元素的 html 内容。你可以精确到某一个具体的元素来进行更改。如果想修改document的内容,则需要修改document.documentElement.innerElementinnerHTML 将内容写入某个 DOM 节点,不会导致页面全部重绘innerHTML 很多情况下都优于document.write,其原因在于其允许更精确的控制要刷新页面的那一个部分

11.ajax 的步骤

什么是ajax?
ajax(异步javascript xml) 能够刷新局部网页数据而不是重新加载整个网页如何使用ajax?第一步,创建 xmlhttprequest 对象,var xmlhttp = new XMLHttpRequest(); XMLHttpRequest 对象用来和服务器交换数据var xhttpif (window.XMLHttpRequest) {//现代主流浏览器xhttp = new XMLHttpRequest()} else {// 针对浏览器,比如IE5或IE6xhttp = new ActiveXObject("Microsoft.XMLHTTP")}第二步,使用 xmlhttprequest 对象的open()和send()方法发送资源请求给服务器第三步,使用xmlhttprequest对象的responseText或responseXML属性获得服务器的响应第四步,onreadystatechange函数,当发送请求到服务器,我们想要服务器响应执行一些功能就需要使用onreadystatechange函数,每次xmlhttprequest对象的readyState发生改变都会触发onreadystatechange函数

12.xml 和 json 的区别

·  JSON 相对于 XML 来讲,数据的体积小,传递的速度更快些
·  JSON 与 JavaScript 的交互更加方便,更容易解析处理,更好的数据交互
·  XML 对数据描述性比较好
·  JSON 的速度要远远快于 XML

13.box-sizing 常用的属性有哪些?分别有什么作用?

box-sizing: content-box|border-box|inherit;content-box:宽度和高度分别应用到元素的内容框。在宽度和高度之外绘制元素的内边距和边框(元素默认效果)
border-box:元素指定的任何内边距和边框都将在已设定的宽度和高度内进行绘制。通过从已设定的宽度和高度分别减去边框和内边距才能得到内容的宽度和高度

14.css选择器有哪些,选择器的权重的优先级

选择器类型1、ID  #id2、class  .class3、标签  p4、通用  *5、属性  [type="text"]6、伪类  :hover7、伪元素  ::first-line8、子选择器、相邻选择器三、权重计算规则第一等:代表内联样式,如: style="",权值为 1000第二等:代表ID选择器,如:#content,权值为 0100第三等:代表类,伪类和属性选择器,如.content,权值为 0010第四等:代表类型选择器和伪元素选择器,如div p,权值为 0001通配符、子选择器、相邻选择器等的。如*、>、+,权值为 0000继承的样式没有权值

14.1.CSS样式覆盖规则

内联样式的权值>>ID选择器>>类选择器>>标签选择器规则一:由于继承而发生样式冲突时,最近祖先获胜
规则二:继承的样式和直接指定的样式冲突时,直接指定的样式获胜
规则三:直接指定的样式发生冲突时,样式权值高者获胜
规则四:样式权值相同时,后者获胜
规则五:!important 的样式属性不被覆盖

14.2.请简要描述 margin 重合问题,及解决方式

1.同向margin的重叠:图片1 的 margin-top 与 图片3 的 margin-top 发生重叠,图片2的 margin-bottom 与图片3 的 margin-bottom 发生重叠。这时候重叠之后的 margin 值由发生重叠两片的最大值决定;如果其中一个出现负值,则由最大的正边距减去绝对值最大的负边距,如果没有最大正边距,则由0减去绝对值最大的负边距。
解决同向重叠的方法:
(1)在最外层的div中加入 overflow:hidden; zoom:1
(2)在最外层加入padding:1px; 属性
(3)在最外层加入:border: 1px solid #cacbcc;2.异向重叠问题:图片1的 margin-bottom 与图片2的 margin-top 发生重叠,这时候重叠之后的 margin 值由发生重叠两图片的最大值的决定的。解决异向重叠问题:float:left(只能解决IE6浏览器中的异向重叠问题,可以解决IE8以上、chorme、firefox、opera下的同向重叠问题)

15.js 有几种数据类型,其中基本数据类型有哪些

五种基本类型: Undefined、Null、Boolean、Number 和 String一种复杂的数据类型:Object,Object 本质上是由一组无序的名值对组成的Object、Array 和 Function 则属于引用类型

15.1.字符串与数字的互相转换

隐式类型转换:当字符串与数字同时存在时,加号运算符转化为字符串,其他远算符(减/乘/除)都优先转化为数字显示类型转换(强制转换):Number()、Boolean()、parseInt()、parseFloat()转字符串:val.toString()String(val)val + ''val.toFixed(0)转数字:parseInt(val)parseFloat(val)val - ''Number(val)

15.1.JavaScript 中如何检测一个变量是一个 String 类型

typeof(obj) === "string"
typeof obj === "string"
obj.constructor === Stringtypeof求解的可能值有:Number、String、boolean、undefined、Object、function、Symbol
注:Array 和 Null 返回的都是 object

15.2. 如何判断JS变量的数据类型

1、最常见的判断方法:typeofconsole.log(typeof a)   ------------> string、Number、undefined、boolean、Object、function、symbol其中typeof返回的类型都是字符串形式,需注意,例如:console.log(typeof a == "string") -------------> trueconsole.log(typeof a == String) ---------------> false另外typeof 可以判断function的类型;在判断除Object类型的对象时比较方便。2、判断已知对象类型的方法: instanceofA instanceof B --------------> 如果B函数的显示原型对象在A对象的原型链上,返回true,否则返回falsealert(c instanceof Array) ---------------> truealert(d instanceof Date)alert(f instanceof Function) ------------> true注意:instanceof 后面一定要是对象类型,并且大小写不能错,该方法适合一些条件选择或分支3、根据对象的 constructor 判断: constructoralert(c.constructor === Array) ----------> truealert(d.constructor === Date) -----------> truealert(e.constructor === Function) -------> true注意: constructor 在类继承时会出错eg:function A(){};function B(){};A.prototype = new B(); //A继承自Bvar aObj = new A();alert(aobj.constructor === B) -----------> true;alert(aobj.constructor === A) -----------> false;而instanceof方法不会出现该问题,对象直接继承和间接继承的都会报true:alert(aobj instanceof B) ----------------> true;言归正传,解决construtor的问题通常是让对象的constructor手动指向自己:aobj.constructor = A; // 将自己的类赋值给对象的constructor属性alert(aobj.constructor === A) -----------> true;alert(aobj.constructor === B) -----------> false; //基类不会报true了;4、通用但很繁琐的方法: prototype【对所有基本的数据类型都能进行判断】alert(Object.prototype.toString.call(a) === '[object String]') -------> true;alert(Object.prototype.toString.call(b) === '[object Number]') -------> true;
大小写不能写错,比较麻烦,但胜在通用。5、无敌万能的方法:jquery.type()
如果对象是undefined或null,则返回相应的“undefined”或“null”。jQuery.type( undefined ) === "undefined"jQuery.type() === "undefined"jQuery.type( window.notDefined ) === "undefined"jQuery.type( null ) === "null"
  1. SASS 和 LESS 是什么?为什么要使用它们?
都是 CSS 预处理器,通过编程的方式来开发CSS,可实现代码简写与复用等原因:结构清晰,便与拓展、减少无意义的机械劳动、可以轻松实现多重继承

17.主流框架实现双向绑定(响应式)的做法

1. 脏值检查:angular.js 是通过脏值检测的方式比对数据是否有变更,来决定是否更新视图。angular 只有在指定的事件触发时进入脏值检测。大致如下:DOM事件,譬如用户输入文本,点击按钮等。( ng-click )XHR响应事件 ( $http )浏览器Location变更事件 ( $location )Timer事件( $timeout , $interval ) 。
执行 $digest() 或 $apply()在 Angular 中组件是以树的形式组织起来的,相应地,检测器也是一棵树的形状。当一个异步事件发生时,脏检查会从根组件开始,自上而下对树上的所有子组件进行检查,这种检查方式的性能存在很大问题。2.观察者-订阅者(数据劫持):Observer 数据监听器,把一个普通的 JavaScript 对象传给 Vue 实例的 data 选项,Vue 将遍历此对象所有的属性,并使用Object.defineProperty()方法把这些属性全部转成setter、getter方法。当data中的某个属性被访问时,则会调用getter方法,当 data 中的属性被改变时,则会调用setter方法。Compile 指令解析器,它的作用对每个元素节点的指令进行解析,替换模板数据,并绑定对应的更新函数,初始化相应的订阅。Watcher 订阅者,作为连接 Observer 和 Compile 的桥梁,能够订阅并收到每个属性变动的通知,执行指令绑定的相应回调函数。Dep 消息订阅器,内部维护了一个数组,用来收集订阅者(Watcher),数据变动触发notify 函数,再调用订阅者的 update 方法。

当执行 new Vue() 时,Vue 就进入了初始化阶段,一方面Vue 会遍历 data 选项中的属性,并用 Object.defineProperty 将它们转为 getter/setter,实现数据变化监听功能;另一方面,Vue 的指令编译器Compile 对元素节点的指令进行解析,初始化视图,并订阅Watcher 来更新视图, 此时Wather 会将自己添加到消息订阅器中(Dep),初始化完毕。当数据发生变化时,Observer 中的 setter 方法被触发,setter 会立即调用Dep.notify(),Dep 开始遍历所有的订阅者,并调用订阅者的 update 方法,订阅者收到通知后对视图进行相应的更新。
因为 VUE 使用 Object.defineProperty 方法来做数据绑定,而这个方法又无法通过兼容性处理,所以Vue 不支持 IE8 以及更低版本浏览器。
查看 vue 原代码,发现在 vue 初始化实例时, 有一个 proxy 代理方法,它的作用就是遍历 data 中的属性,把它代理到 vm 的实例上,这也就是我们可以这样调用属性:vm.aaa 等于 vm.data.aaa。

18.px、em、rem、rpx 之间的区别

px 像素(Pixel):相对长度单位。像素 px 是相对于显示器屏幕分辨率而言的。
px 特点:1.IE无法调整那些使用 px 作为单位的字体大小2.国外的大部分网站能够调整的原因在于其使用了 em 或 rem 作为字体单位3.Firefox 能够调整 px、em 和 rem,但是有很多人使用IE浏览器(或内核)em:是相对长度单位。相对于当前对象内文本的字体尺寸。如当前对行内文本的字体尺寸未被人为设置,则相对于浏览器的默认字体尺寸。
em 特点:1.em 的值并不是固定的2.em 会继承父级元素的字体大小rem:是 CSS3 新增的一个相对单位(root em,根em),这个单位与em有什么区别呢?区别在于使用 rem 为元素设定字体大小时,仍然是相对大小,但相对的只是 HTML 根元素。通过它既可以做到只修改根元素就成比例地调整所有字体大小,又可以避免字体大小逐层复合的连锁反应。由于设计稿使用的屏幕宽度为 750,所以此时 rem 与设计稿上 px 的换算关系为 1rem = 100px
缺点:1.需要动态设置 html 的 font-size2.rem 布局会有小数问题,这就会导致页面达不到预期效果rpx(responsive pixel): 可以根据屏幕宽度进行自适应,规定屏幕宽为 750rpx
如在 iPhone6 上,屏幕宽度为 375px,共有 750 个物理像素,则 750rpx = 375px = 750 物理像素,1rpx = 0.5px = 1 物理像素
rpx 为小程序中使用的相对单位,用法和 rem 类似, 1rpx = 屏幕宽度 / 750 px, 所以在屏幕宽度为 750 的设计稿中,1rpx = 1px

18.1.物理像素、设备独立像素(px)、设备像素比

物理像素:又称为设备像素、设备物理像素,它是显示器最小的物理显示单位,每个物理像素由颜色值和亮度值组成,所谓的一倍屏,二倍屏,三倍屏,指的是设备以多少物理像素来显示一个 css 像素,也就是说,多倍屏以更多精细的物理像素点来显示一个 css 像素点,在普通屏幕下 1 个 css 像素对应 1 个物理像素,而在 Retina 屏幕下,1 个 css 像素对应的却是 4 个物理像素设备独立像素:又被称为 CSS 像素,是我们写 CSS 时所用的像素,它是一个抽像的单位,主要使用在浏览器上,用来精确度量 Web 页面上的内容设备像素比:简称为 dpr,定义了物理像素和设备独立像素的对应关系:设备像素比 = 物理像素 / 设备独立像素

19.优雅降级和渐进增强

渐进增强(Progressive Enhancement):一开始就针对低版本浏览器进行构建页面,完成基本的功能,然后再针对高级浏览器进行效果、交互、追加功能达到更好的体验。优雅降级(Graceful Degradation):一开始就构建站点的完整功能,然后针对浏览器测试和修复。比如一开始使用 CSS3 的特性构建了一个应用,然后逐步针对各大浏览器进行 hack 使其可以在低版本浏览器上正常浏览。其实渐进增强和优雅降级并非什么新概念,只是旧的概念换了一个新的说法。在传统软件开发中,经常会提到向上兼容和向下兼容的概念。渐进增强相当于向上兼容,而优雅降级相当于向下兼容

20.eval() 的作用

// 把字符串参数解析成JS代码并运行eval("2+3")    //执行加运算,并返回运算值。
eval("varage=10")    //声明一个age变量eval的作用域
function a(){  eval("var x=1")    //等效于 var x=1console.log(x)    //输出1
}
a()console.log(x)    //错误 x没有定

21.JS 哪些操作会造成内存泄露

1)意外的全局变量引起的内存泄露function leak(){leak="xxx"    //leak成为一个全局变量,不会被回收}
2)闭包引起的内存泄露
3)没有清理的DOM元素引用
4)被遗忘的定时器或者回调
5)子元素存在引起的内存泄露

21.1. 提高 JS 性能

一:在浏览器中缓存
二:定义执行的上下文
三:删除未使用的 JavaScript
四:避免使用太多内存
五:推迟不必要的 JS 加载
六:避免内存泄漏
七:适当的使用 Web worker
八:适当将 DOM 元素保存在局部变量中
九:优先访问局部变量
十:避免使用全局变量
十一:实施一些优化方案始终使用计算复杂度最低的算法和最佳的数据结构来解决任务。重写算法以获得相同的结果和更少的计算。避免递归调用。给重复的函数加入变量、计算和调用。分解和简化数学公式。使用搜索数组:用它们来获取基于另一个的值,而不是使用 switch/case 语句。使条件总是更有可能为真,以更好地利用处理器的推测执行。如果可以,请使用位级运算符替换某些操作,因为这些运算符的处理周期较短。

21.2.如何进行网站性能优化

1. 从用户角度而言,优化能够让页面加载得更快、对用户的操作响应得更及时,能够给用户提供更为友好的体验。
2. 从服务商角度而言,优化能够减少页面请求数、或者减小请求所占带宽,能够节省可观的资源。总之,恰当的优化不仅能够改善站点的用户体验并且能够节省相当的资源利用。
前端优化的途径有很多,按粒度大致可以分为两类,第一类是页面级别的优化,例如 HTTP请求数、脚本的无阻塞加载、内联脚本的位置优化等 ;第二类则是代码级别的优化,例如 Javascript中的DOM 操作优化、CSS选择符优化、图片优化以及 HTML结构优化等等。另外,本着提高投入产出比的目的,后文提到的各种优化策略大致按照投入产出比从大到小的顺序排列。一、页面级优化1. JavaScript 压缩和模块打包2. 按需加载资源3. 在使用 DOM 操作库时用上 array-ids4. 缓存5. 启用 HTTP/26. 应用性能分析7. 使用负载均衡方案8. 为了更快的启动时间考虑一下同构9. 使用索引加速数据库查询10. 使用更快的转译方案11. 避免或最小化 JavaScript 和 CSS 的使用而阻塞渲染12. 用于未来的一个建议:使用 service workers + 流13. 图片编码优化

21.3.Web 前端优化策略

(1) 减少 HTTP 请求数
(2) 从设计实现层面简化页面
(3) 合理设置 HTTP 缓存
(4) 资源合并与压缩
(5) CSS Sprites
(6) Inline Images
(7) Lazy Load Images

22.浏览器缓存

浏览器缓存(Brower Caching):是浏览器在本地磁盘对用户最近请求过的文档进行存储,当访问者再次访问同一页面时,浏览器就可以直接从本地磁盘加载文档优点:
1.减少了冗余的数据传输,节省了网费
2.减少了服务器的负担,大大提升了网站的性能
3.加快了客户端加载网页的速度浏览器缓存主要有两类:缓存协商和彻底缓存,也有称之为协商缓存和强缓存。
1.强缓存:不会向服务器发送请求,直接从缓存中读取资源,在 chrome 控制台的 network选项中可以看到该请求返回200的状态码
2.协商缓存:向服务器发送请求,服务器会根据这个请求的 request header 的一些参数来判断是否命中协商缓存,如果命中,则返回 304 状态码并带上新的 response header 通知浏览器从缓存中读取资源
3.共同点是:都是从客户端缓存中读取资源,都只针对静态资源
4.区别是:· 强缓存不会发请求,协商缓存会发请求· 强缓存在前,协商缓存在后· 资源未过期触发强缓存,资源过期后再触发协商缓存。判断过期的方法expires(绝对时间)、cache-control(相对时间);判断资源是否有更新(Last-Modified 和 ETag)浏览器缓存种类:1.http:缓存是基于 HTTP 协议的浏览器文件级缓存机制2.websql:这种方式只有较新的 chrome 浏览器支持,并以一个独立规范形式出现3.indexDB:是一个为了能够在客户端存储可观数量的结构化数据,并且在这些数据上使用索引进行高性能检索的 API4.Cookie:一般网站为了辨别用户身份、进行 session 跟踪而储存在用户本地终端上的数据(通常经过加密)5.Localstorage:html5 的一种新的本地缓存方案,目前用的比较多,一般用来存储 ajax 返回的数据,加快下次页面打开时的渲染速度6.Sessionstorage:和 localstorage 类似,但是浏览器关闭则会全部删除,api 和 localstorage 相同,实际项目中使用较少7.application cache:是将大部分图片资源、js、css 等静态资源放在 manifest 文件配置中8.cacheStorage:是在 ServiceWorker 的规范中定义的,可以保存每个 serverWorker 申明的 cache 对象9.flash缓存:这种方式基本不用,这一方法主要基于 flash 有读写浏览器端本地目录的功能

23.bootstrap 响应式实现的原理:百分比布局+媒体查询

24.关于JS事件冒泡与JS事件代理(事件委托)

1.事件冒泡:通俗易懂的来讲,就是当一个子元素的事件被触发的时候(如onclick事件),该事件会从事件源(被点击的子元素)开始逐级向上传播,触发父级元素的点击事件。2.事件委托:就是将子元素的事件通过冒泡的形式交由父元素来执行。(利用的DOM事件的事件捕获阶段。把具体dom上发生的事件,委托给更大范围的dom去处理)

24.1.阻止 事件冒泡 和 浏览器默认事件

JS的事件流(事件处理的流程):事件捕获、处理目标、事件冒泡事件捕获:从祖先元素依次向事件源元素做事件传播的行为在DOM树中,沿着DOM树结构,从顶层向底层传播事件的行为。从最不确定的元素到最确定的元素事件传播的行为。处理目标:对目标元素进行操作。事件冒泡:从事件源元素依次向祖先元素做事件传播的行为在 DOM 树中,沿着DOM树结构,从底层向顶层传播事件的行为。从最确定的元素到最不确定的元素做事件传播的行为注:现代浏览器中事件处理的方式都默认按照事件冒泡的方式处理。(即所有浏览器中事件都是默认先按事件冒泡的方式来处理的)
如果想用事件捕获的方式处理请使用addEventListener阻止事件冒泡的方法(阻止事件捕获也是用这个方法):// W3C标准://阻止事件传播行为event.stopPropagation();// IE:event.cancelBubble = true;// 兼容写法:event.stopPropagation ? event.stopPropagation() : (event.cancelBubble = true);浏览器默认事件行为:浏览器中点击右键弹出快捷菜单点击超级链接跳转刷新页面表单中点击提交按钮能够提交表单阻止浏览器默认行为的方法:// 标准event.preventDefault();// 非标准event.returnValue = false;// 兼容写法:event.preventDefault ? event.preventDefault() : (event.returnValue = false);超级链接阻止跳转的方法:在a标签的点击事件中加上event.preventDefault()改造a标签的href属性:<a href = "javascript: void(0);">

24.2. JS 原生事件如何绑定

HTML 事件处理程序:在 HTML 各种标签上直接添加事件DOM0 级事件处理程序:先获取 DOM 元素,然后直接给 DOM 元素添加事件(PC端)
let btn = document.getElementById('id元素')
btn.onclick = () => {}DOM2 级事件处理程序:提供专门的绑定和移除方法(移动端)
let btn = document.getElementById('id元素')
btn.addEventListenter('click', () => {})

24.3. JS 原生常用 DOM 操作方法

查找getElementById、getElementsByTagName、querySelector、querySelectorAll
插入appendChild、insertBefore
删除removeChild
克隆cloneNode
设置属性setAttribute("属性名", "值")
获取属性getAttribute("属性名")

25.什么是闭包,如何使用它,为什么要使用它?

闭包就是能够读取其他函数内部变量的函数。由于在 Javascript 语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成"定义在一个函数内部的函数"。所以,在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。闭包的用途
闭包可以用在许多地方。它的最大用处有两个,一个是前面提到的可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中。使用闭包主要是为了设计私有的方法和变量。
闭包的优点:延长局部变量的生命周期;让函数外部能够操作内部的局部变量(可以避免全局变量的污染)缺点:闭包会常驻内存,会增大内存使用量,使用不当很容易造成内存泄露
在js中,函数即闭包,只有函数才会产生作用域的概念闭包有三个特性:1.函数嵌套函数2.函数内部可以引用外部的参数和变量3.参数和变量不会被垃圾回收机制回收

26.请解释 JSONP 的工作原理,以及它为什么不是真正的 AJAX

JSONP (JSON with Padding)是一个简单高效的跨域方式,HTML中的script标签可以加载并执行其他域的javascript,于是我们可以通过script标记来动态加载其他域的资源。例如我要从域A的页面pageA加载域B的数据,那么在域B的页面pageB中我以JavaScript的形式声明pageA需要的数据,然后在 pageA中用script标签把pageB加载进来,那么pageB中的脚本就会得以执行。JSONP在此基础上加入了回调函数,pageB加载完之后会执行pageA中定义的函数,所需要的数据会以参数的形式传递给该函数。JSONP易于实现,但是也会存在一些安全隐患,如果第三方的脚本随意地执行,那么它就可以篡改页面内容,截获敏感数据。但是在受信任的双方传递数据,JSONP是非常合适的选择。AJAX是不跨域的,而JSONP是一个是跨域的,还有就是二者接收参数形式不一样!

27.请解释一下 JavaScript 的同源策略

同源策略是一个很重要的安全理念,它在保证数据的安全性方面有着重要的意义。同源策略规定跨域之间的脚本是隔离的,一个域的脚本不能访问和操作另外一个域的绝大部分属性和方法。当两个域具有相同的协议, 相同的端口,相同的host,那么我们就可以认为它们是相同的域。

27.1.前端跨域的六种解决方法

1.JSONP 跨域(目前已基本不用)JSONP只支持get请求、不支持post请求(类似往页面添加一个script标签,通过src属性去触发对指定地址的请求,故只能是Get请求)2.CORS跨域(常用)服务器设置响应头header('Access-Control-Allow-Origin: *');    // 允许访问的网址header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");    // 允许访问的方式3.webpackdevServer 里配置 proxy: {api: '地址'}4.nginx反向代理(nginx.conf)upstream tomcatServer {server 192.168.72.49:1339  // 找到代理服务器的 IP 地址进行请求}server {listen    10010;server_name    8081.max.com    // 客户端调用名location / {proxy_pass http://tomcatServer;  // 代理服务器index index.html index.htm;}}5.document.domain
跨域分为俩种,一种xhr不能访问不同源的文档,另一种是不同window之间不能进行交互操作
document.domain主要解决第二种情况,且只能适用于主域相同子域不同的情况
document.domain的设置是有限制的,我们只能把document.domain设置成自身或更高一级的父域,且主域必须相同。例如: a.b.example.com 中某个文档的document.domain可以设成a.b.example.com、b.example.com、example.com中的任意一个,但是不可以设成c.a.b.example.com,因为这是当前域的子域,也不可以设成baidu.com,因为主域已经不相同了兼容性:所有浏览器都支持
优点:可以实现不同window之间的相互访问和操作
缺点:只适用于window之间的通信,不能用于xhr只能在主域相同且子域不同的情况下使用6.window.name
关键点:window.name在页面的生命周期里共享一个window.name
兼容性:所有浏览器都支持
优点:最简单的利用了浏览器的特性来做到不同域之间的数据传递不需要前端和后端的特殊配置
缺点:大小限制:window.name最大size是2M左右,不同浏览器中会有不同约定
安全性:当前页面所有window都可以修改,很不安全
数据类型:传递数据只能限于字符串,如果是对象或者其他会自动被转化为字符串。
使用方式:修改window.name的值即可7.window.postMessage
兼容性:移动端可以放心用,但是pc端需要做降级处理
优点:不需要后端介入就可以做到跨域,一个函数外加俩个参数(请求url,发送数据)就可以搞定移动端兼容性好
缺点:无法做到一对一的传递方式:监听中需要做很多消息的识别,由于postMessage发出的消息对于同一个页面的不同功能相当于一个广播的过程,该页面的所有onmessage都会收到,所以需要做消息的判断
安全性问题:三方可以通过截获,注入html或者脚本的形式监听到消息,从而能够做到篡改的效果,所以在postMessage和onMessage中一定要做好这方面的限制发送的数据会通过结构化克隆算法进行序列化,所以只有满足该算法要求的参数才能够被解析,否则会报错,如function就不能当作参数进行传递
使用方式:通信的函数,sendMessage负责发送消息,bindEvent负责消息的监听并处理,

28.怎样添加、移除、移动、复制、创建和查找节点

1)创建新节点document.createElement('tagName')    // 创建元素节点document.createTextNode(text)    // 创建文本节点element.innerHTML    // 获取/设置元素内部的HTML文本element.innerText    // 获取/设置元素内部的纯文本// 设置attrName属性element.setAttribute(attrName, attrValue)element.<attrName> = attrValue// 获取attrName属性element.getAttribute(attrName)element.<attrName>// 将element添加到parentElement内部末尾(appendChild()会把dom之前所在的位置移除掉)parentElement.appendChild(element);// 将element添加到parentElement内部oldNode节点之前,如果oldNode不存在,则追加到parentElement内部末尾parentElement.insertBefore(element, oldNode);2)添加、移除、替换、插入appendChild()    // 添加removeChild()    // 移除replaceChild()    // 替换insertBefore()    // 插入node.cloneNode(boolean)    // boolean 表示是否克隆后代节点 //true表示克隆后代,false不克隆后代,默认为false3)查找document.getElementById()    // 根据元素的Id查找document.getElementsByTagName()    // 根据标签名查找document.getElementsByClassName()    // 根据类名查找document.getElementsByName()    // 根据元素的name属性值查找document.querySelector(selector)    // 查找满足条件的第一个选择器document.querySelectorAll(selector)    // 查找满足条件的所有选择器// 在指定的element元素后代中根据标签/类名查找element.getElementsByTagName()element.getElementsByClassName()4)节点筛选// 查找父节点:node.parentNode// 查找子节点://会包括所有的孩子文本节点与元素节点element.childNodes// 只包括所有孩子元素节点element.children// 元素的第一个孩子节点,回车换行也会被算为文本节点element.firstChild// 元素的最后一个孩子节点,回车换行也会被算为文本节点element.lastChild// 兄弟节点:previousSiblingnextSibling5)节点属性// 节点名称:node.nodeName// 文本节点:#text// 元素节点:// 标签名大写状态,例如:DIV// 节点类型:node.nodeType    // 返回数字:1 --元素节点    3 -- 文本节点// 节点值:node.nodeValue    // 文本节点:文本值    元素节点:null

29.浏览器是如何渲染页面的

1.解析 HTML 文件,创建 DOM 树自上而下,遇到任何样式(link、style)与脚本(script)都会阻塞(外部样式不阻塞后续外部脚本的加载)
2.解析 CSS。优先级:浏览器默认设置 < 用户设置 < 外部样式 < 内联样式 < HTML中的style样式
3.将 CSS 与 DOM 合并,构建渲染树(Render Tree)
4.布局和绘制,重绘(repaint)和重排(reflow)

29.0.浏览器输入一个地址到页面展示,中间经历了什么

1.浏览器输入 URL。解析 URL 地址是否合法
2.浏览器检查是否有缓存(浏览器缓存、系统缓存、路由缓存)。若有,直接显示,页面全部渲染完毕;若无,则执行第三步
3.在发送 HTTP 请求前,需要域名解析(DNS 解析),解析获取对应过的 IP 地址
4.浏览器向服务器发起 TCP 连接,浏览器与服务器建立 TCP 三次握手
5.握手成功后,浏览器向服务器发送 HTTP 请求,请求数据包
6.服务器收到处理的请求,将数据返回至浏览器
7.浏览器收到 HTTP 响应并解析。如果响应可以缓存,则存入缓存
8.浏览器发送请求获取嵌入在 HTML 中的资源(html、css、JavaScript、图片等等)。对于未知类型,会弹出对话框
9.浏览器发送异步请求(ajax 请求)
10.页面全部渲染完毕

29.1.浏览器如何解析 CSS选择器

从右到左解析,根据选择器遍历 DOM 树,将样式加到对应的 DOM 元素上

29.2.重绘和重排

重排:若渲染树的一部分更新,且尺寸变化,就会发生重排,可以理解为渲染树需要重新计算;(比如width, height, display:none / block, left, top...)
重绘:一个元素外观的改变所触发的浏览器行为,例如改变visibility、outline、font-size、color、background等属性重排必定会引发重绘,但重绘不一定会引发重排

29.3.减少重绘与回流

CSS1.使用 transform 替代 top2.使用 visibility 替换 display: none ,因为前者只会引起重绘,后者会引发回流3.避免使用table布局,可能很小的一个小改动会造成整个 table 的重新布局。4.尽可能在DOM树的最末端改变class,回流是不可避免的,但可以减少其影响。尽可能在DOM树的最末端改变class,可以限制了回流的范围,使其影响尽可能少的节点。5.避免设置多层内联样式,CSS 选择符从右往左匹配查找,避免节点层级过多JavaScript1.避免频繁操作样式,最好一次性重写style属性,或者将样式列表定义为class并一次性更改class属性。2.避免频繁操作DOM,创建一个documentFragment,在它上面应用所有DOM操作,最后再把它添加到文档中。3.避免频繁读取会引发回流/重绘的属性,如果确实需要多次使用,就用一个变量缓存起来。4.对具有复杂动画的元素使用绝对定位,使它脱离文档流,否则会引起父元素及后续元素频繁回流

30.CSS3 新增了很多的属性,下面一起来分析一下新增的一些属性:【比较全】

1.CSS3边框:
· border-radius:CSS3圆角边框。在 CSS2 中添加圆角矩形需要技巧,我们必须为每个圆角使用不同的图片,在 CSS3 中,创建圆角是非常容易的,在 CSS3 中,border-radius 属性用于创建圆角。border:2px solid;
· box-shadow:CSS3边框阴影。在 CSS3 中,box-shadow 用于向方框添加阴影。box-shadow:10px 10px 5px #888888;
· border-image:CSS3边框图片。通过 CSS3 的 border-image 属性,您可以使用图片来创建边框。border-image:url(border.png) 30 30 round;2.CSS3背景:
· background-size: 属性规定背景图片的尺寸。在 CSS3 之前,背景图片的尺寸是由图片的实际尺寸决定的。在 CSS3 中,可以规定背景图片的尺寸,这就允许我们在不同的环境中重复使用背景图片。您能够以像素或百分比规定尺寸。如果以百分比规定尺寸,那么尺寸相对于父元素的宽度和高度。
· background-origin :属性规定背景图片的定位区域。背景图片可以放置于 content-box、padding-box 或 border-box 区域。3.CSS3文字效果:
· text-shadow:在 CSS3 中,text-shadow 可向文本应用阴影。text-shadow:5px 5px 5px #FFFFFF;
· word-wrap :单词太长的话就可能无法超出某个区域,允许对长单词进行拆分,并换行到下一行:p{word-wrap:break-word;}4.CSS3 2D转换:
transform:通过 CSS3 转换,我们能够对元素进行移动、缩放、转动、拉长或拉伸。
· translate():元素从其当前位置移动,根据给定的 left(x 坐标) 和 top(y 坐标) 位置参数:transform:translate(50px,100px);值 translate(50px,100px) 把元素从左侧移动 50 像素,从顶端移动 100 像素。
· rotate():元素顺时针旋转给定的角度。允许负值,元素将逆时针旋转。transform:rotate(30deg);值 rotate(30deg) 把元素顺时针旋转 30 度。
· scale():元素的尺寸会增加或减少,根据给定的宽度(X 轴)和高度(Y 轴)参数:transform:scale(2,4);值 scale(2,4) 把宽度转换为原始尺寸的 2 倍,把高度转换为原始高x()5.CSS3 3D转换:
· rotateX():元素围绕其 X 轴以给定的度数进行旋转。transform:rotateX(120deg);
· rotateY():元素围绕其 Y 轴以给定的度数进行旋转。transform:rotateY(120deg);6.CSS3 过渡:当元素从一种样式变换为另一种样式时为元素添加效果7.CSS3动画:通过 CSS3,我们能够创建动画,这可以在许多网页中取代动画图片、Flash 动画以及 JavaScript8.CSS3多列:
· column-count:属性规定元素应该被分隔的列数
· column-gap:属性规定列之间的间隔
· column-rule :属性设置列之间的宽度、样式和颜色规则9.CSS3用户界面:
· resize:属性规定是否可由用户调整元素尺寸
· box-sizing:属性允许您以确切的方式定义适应某个区域的具体内容
· outline-offset :属性对轮廓进行偏移,并在超出边框边缘的位置绘制轮廓

31.h5 新特性

HTML5新特性 —— 新特性(1)新的语义标签和属性(2)表单新特性
placeholder:文本框处于未输入状态时文本框中显示的输入提示
autofocus:给文本框、选择框或者按钮控件加上该属性,当打开页面时,该控件自动获得国标焦点,一个页面只能有一个
required:验证输入不能为空
list:结合 datalist 元素使用
自动验证:min、max、step为包含数字或日期的 input 类型规定限定(约束)
不自动验证:novalidate属性规定当提交表单时不对其进行验证。给 form 添加(3)视频和音频(4)Canvas绘图(5)SVG绘图(6)地理定位(7)拖放API

31.1.H5、CSS3 新特性

1. 语义化标签
2. 本地存储
3. Canvas,audio,video
4. C3新增选择器

32.display: none,visibility: hidden 区别

display: none;DOM 结构:浏览器不会渲染 display 属性为 none 的元素,不占据空间;事件监听:无法进行 DOM 事件监听;性能:动态改变此属性时会引起重排,性能较差;继承:不会被子元素继承,毕竟子类也不会被渲染;transition:transition 不支持 display。visibility: hidden;DOM 结构:元素被隐藏,但是会被渲染不会消失,占据空间;事件监听:无法进行 DOM 事件监听;性 能:动态改变此属性时会引起重绘,性能较高;继 承:会被子元素继承,子元素可以通过设置 visibility: visible; 来取消隐藏;transition:visibility 会立即显示,隐藏时会延时opacity: 0;DOM 结构:透明度为 100%,元素隐藏,占据空间;事件监听:可以进行 DOM 事件监听;性 能:提升为合成层,不会触发重绘,性能较高;继 承:会被子元素继承,且,子元素并不能通过 opacity: 1 来取消隐藏;transition:opacity 可以延时显示和隐藏1.display:none 是彻底消失,不在文档流中占位,浏览器也不会解析该元素;visibility:hidden 是视觉上消失了,可以理解为透明度为0的效果,在文档流中占位,浏览器会解析该元素;2.使用visibility:hidden 比 display:none 性能上要好,display:none 切换显示时,页面产生回流(当页面中的一部分元素需要改变规模尺寸、布局、显示隐藏等,页面重新构建,此时就是回流。所有页面第一次加载时需要产生一次回流),而 visibility 切换是否显示时则不会引起回流。


33. 数组的常用API你知道哪些?

改变原数组:push、pop、shift、unshift、splice、reverse、sort
不改变原数组:join、concat、slice、some、every、map、forEach、filter、find、indexOf、toString、reduceforEach(): 遍历数组,没有返回值
map(): 遍历数组每一个元素,并返回新数组
filter(): 过滤掉不符合条件的元素,返回新数组
reduce():  对数组中的所有元素调用指定的回调函数。该回调函数的返回值为累积结果,并且此返回值在下一次调用该回调函数时作为参数提供。
some(): 遍历数组的每一项,若是遇到符合条件的,返回true,并停止循环;若全部不符合则返回false
every(): 遍历数组每一项,若是遇到不符合条件的,则返回false,并停止循环;若全部都符合则返回true

34.深拷贝 与 浅拷贝

深拷贝和浅拷贝是只针对 Object 和 Array 这样的引用数据类型的浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存。
深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。浅拷贝的实现方式
1. Object.assign():可以把任意多个的源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象。拷贝的是对象的属性的引用,而不是对象本身。var obj = { a: {a: "kobe", b: 39} };var initalObj = Object.assign({}, obj);initalObj.a.a = "wade";console.log(obj.a.a); // wade
注:当object只有一层的时候,是深拷贝let obj = {username: 'kobe'};let obj2 = Object.assign({},obj);obj2.username = 'wade';console.log(obj);    //{username: "kobe"}2. Array.prototype.concat()let arr = [1, 3, {username: 'kobe'}];let arr2=arr.concat();    arr2[2].username = 'wade';console.log(arr);  // [1, 3, {username: 'wade'}]3. Array.prototype.slice()let arr = [1, 3, {username: ' kobe'}];let arr3 = arr.slice();arr3[2].username = 'wade'console.log(arr);  // [1, 3, {username: 'wade'}]关于Array的slice和concat方法的补充说明:Array的slice和concat方法不修改原数组,只会返回一个浅复制了原数组中的元素的一个新数组原数组的元素会按照下述规则拷贝:1. 如果该元素是个对象引用(不是实际的对象),slice 会拷贝这个对象引用到新的数组里。两个对象引用都引用了同一个对象。如果被引用的对象发生改变,则新的和原来的数组中的这个元素也会发生改变。2. 对于字符串、数字及布尔值来说(不是 String、Number 或者 Boolean 对象),slice 会拷贝这些值到新的数组里。在别的数组里修改这些字符串或数字或是布尔值,将不会影响另一个数组。let arr = [1, 3, {username: ' kobe'}];let arr3 = arr.slice();arr3[1] = 2console.log(arr,arr3);  // [1, 3, {username: ' kobe'}]    [1, 2, {username: ' kobe'}]深拷贝的实现方式
1. JSON.parse(JSON.stringify())let arr = [1, 3, {username: ' kobe'}];let arr4 = JSON.parse(JSON.stringify(arr));arr4[2].username = 'duncan';console.log(arr, arr4)  // [1, 3, {username: ' kobe'}]    [1, 3, {username: 'duncan'}]原理: 用JSON.stringify将对象转成JSON字符串,再用JSON.parse()把字符串解析成对象,一去一来,新的对象产生了,而且对象会开辟新的栈,实现深拷贝。
注:这种方法虽然可以实现数组或对象深拷贝,但不能处理函数let arr = [1, 3, {username: ' kobe'},function(){}];let arr4 = JSON.parse(JSON.stringify(arr));arr4[2].username = 'duncan';console.log(arr, arr4);    //  [1, 3, {username: ' kobe'}, function(){}]    [1, 3, {username: ' kobe'}, null]2.手写递归方法:递归方法实现深度克隆原理:遍历对象、数组直到里边都是基本数据类型,然后再去复制,就是深度拷贝。3.函数库 lodash:该函数库也有提供 _.cloneDeep 用来做 Deep Copyvar _ = require('lodash');var obj1 = {a: 1,b: { f: { g: 1 } },c: [1, 2, 3]};var obj2 = _.cloneDeep(obj1);console.log(obj1.b.f === obj2.b.f);    // false


35. 一个页面上有大量的图片(大型电商网站),加载很慢,你有哪些方法优化这些图片的加载,给用户更高的体验

1.使用精灵图,将小规格的图片整合为一张精灵图,减少浏览器请求次数2.使用图片懒加载原理:没有在展示区域的图片不给他设置 src 属性,即将展示那个图片的时候去设置它的 src 属性

36.img 的 alt 与 title 有何异同?strong 与 em 的异同?

alt:用来指定替换文字【图片加载失败展示】。
title:用来提供建议性文字【移入显示】。
strong:粗体强调标签。
em:斜体强调标签

37.css中的 z-index 的权重问题请讲讲你所了解的一些规则

1.定位的元素在没定位的元素上面
2.同样定位了后面的元素在前面的元素上面
3.同级的父级都定位了【就不看子级了】,谁的z-index高谁在上面
4.一个父级定位了,另一个父级没定位,没定位的元素的子级定位了,那就按照定位的子级和定位的父级看谁的z-index高谁在上面eg:父A(子a)定位,父B(子b定位)不定位,且父A的z-index比子b的小。由里向外的顺序:父B -> 父A -> 子a -> 子b

38.CSS的 link 和 import 的区别是什么?

区别1:link是Xhtml标签,除了加载CSS外,还可以定义RSS等其他事务;@import属于CSS范畴,只能加载CSS。
区别2:link引用CSS时,在页面载入时同时加载;@import需要页面网页完全载入以后加载。
区别3:link是XHTML标签,无兼容问题;@import是在CSS2.1提出的,低版本的浏览器不支持。
区别4:link支持使用JavaScript控制DOM去改变样式;而@import不支持。或:1.link是 HTML 方式, @import是 CSS 方式
2.link最大限度支持并行下载,@import过多嵌套导致串行下载,出现FOUC
3.link可以通过rel="alternate stylesheet"指定候选样式
4.浏览器对link支持早于@import,可以使用@import对老浏览器隐藏样式
5.@import必须在样式规则之前,可以在 css 文件中引用其他文件
6.总体来说:link 优于 @import

39.前端页面有哪三层构成?分别是什么?作用是什么?

结构层(HTML - - 设置页面的基本结构)
样式层(CSS - - 修改页面展示给用户的样式加一些小交互)
行为层(JS - - 使用户与页面完美交互)

40.“" 和 "=” 还有 “!=” 和 "!== " 的区别?

"==" 和 "!=" 会做数据隐式类型转换,转换完数据类型再做比较"===" 和 "!==" 会先判断数据类型,如果俩者的数据类型不一致直接返回 false,就不会再去做值的比较了

41.讲一讲“ || ” 和 “ && ”

短路运算符||:如果说俩个条件都不满足那么就不会走进这个执行语句当中去从前至后的顺序去遍历表达式,遇到true的表达式停止并返回此表达式。如果全都为false,那么就返回最后一个。&&:只有全部的表达式满足条件了才会进入到if的执行语句中从前至后的顺序去遍历表达式,遇到false的表达式停止并返回此表达式。如果全都为true,那么就返回最后一个

42.break,return,continue 三者的区别

一:return在函数体中遇到return语句,则结束函数执行(函数体未执行完部分不再执行),将表达式的值返回到函数调用处。使用return最多只能返回一个值!二:breakbreak主要用在循环语句或者switch语句中,用来退出整个语句块。break跳出最里层的循环,并且继续执行该循环下面的语句。break当用于循环结构时,表示退出其所在的整个循环结构,当前次循环未完成任务及未完成循环次数将不再执行!三:continuecontinue适用于任何循环控制结构中。作用是让程序立即跳转到下一次循环的迭代。在for循环中,continue语句使程序立即跳转到更新语句。在while或者do...while循环中,程序立即跳转到布尔表达式的判断语句。continue只能用于循环结构,表示结束当前次循环,还会判断条件进行下一次循环。break             可用作于switch和循环
continue          只可用作于循环
return 表达式      只可用作于函数

43.数组与伪数组的区别

数组 是用来存储一系列值的一个集合,而每个值在数组里面都有一个对应的索引,也可以叫做下标,索引是从0开始的,依次递增
伪数组 我们可以理解为类似数组的一个集合,我们常见的有俩个,一个是arguments还有一个是DOM的children属性,获取回来的子节点集合。他们与数组一样,具有索引(下标)和length属性。可以通过for循环写循环语句去循环遍历伪数组与数组的区别:1.它们的_proto_2.普通数组有很多数组的方法,而伪数组却没有将伪数组变成真数组的方法:// 假设我们获取到了一个页面的所有div,这就是一个伪数组。const fakeArr = document.getElementsByTagName('div');// 我们可以进行重新赋值也可以用一个新变量接收或者在上方就进行转换简写都可以,笔者拿个新变量接收他。// 如果你要重新赋值别忘了将const变成let。const realArr = Array.prototype.slice.call(fakeArr);

44.对面向对象编程(OOP)的理解 ★

面向对象特征:1.封装(Encapsulation)封装给对象提供了隐藏内部特性和行为的能力。对象提供一些能被其他对象访问的方法来改变它内部的数据。一般来讲有三种修饰符:public、private和protected。每一种修饰符给其他的位于同一个包或者不同包下面对象赋予了不同的访问权限。优点:1)通过隐藏对象的属性来保护对象内部的状态2)提高了代码的可用性和可维护性,因为对象的行为可以被单独的改变或者是扩展3)禁止对象之间的不良交互提高模块化2.继承(Inheritance)继承给对象提供了从基类获取字段和方法的能力。继承提供了代码的重用性,也可以在不修改类的情况下给现存的类添加新特性。3.多态(Polymorphism)多态是编程语言给不同的底层数据类型做相同的接口展示的一种能力。一个多态类型上的操作可以应用到其他类型的值上面。4.抽象(Abstraction)抽象是把想法从具体的实例中分离出来的步骤,因此,要根据他们的功能而不是实现细节来创建类。这种抽象技术的主要目的是把类的行为和实现细节分离开。

45.原型链 ★

原型链的核心:就是依赖对象的 __proto__ 的指向。当自身有不存在的属性时,就一层层的扒出创建对象的构造函数,直到 Object 时就没有 __proto__ 指向原型链就是多个对象通过 __proto__ 的方式连接了起来1.Object 是所有对象的爸爸,所有对象都可以通过 __proto__ 找到它2.Function 是所有函数的爸爸,所有函数都可以通过 __proto__ 找到它3.函数的 prototype 是一个对象4.对象的 __proto__ 属性指向原型, __proto__ 将对象和原型连接起来组成了原型链作用:1.实例对象可以使用原型链上对象的方法或者属性;2.查找顺序:从自身往上查找(先到先得)


46. 继承的方法 ★★

原型链继承优点:1)非常纯粹的继承关系,实例是子类的实例,也是父类的实例2)父类新增原型方法/原型属性,子类都能访问的到3)简单缺点:1)要想为子类新增属性和方法,必须要在new Animal()这样的语句之后执行,不能放到构造器中2)无法实现继承多个3)来自原型对象的所有属性被所有实例共享4)创建子类实例时,无法向父类构造函数传参构造继承优点:1)创建子类实例时,可以向父类传递参数2)可以实现多继承(call多个父类对象)缺点:1)实例并不是父类的实例,只是子类的实例2)只能继承父类的实例属性和方法,不能继承原型属性/方法3)无法实现函数复用,每个子类都有父类实例函数的副本,影响性能实例继承优点:1)不限制调用方式,不管是 new子类() 还是 子类(),返回的对象都具有相同的效果缺点:1)实例是父类的实例,不是子类的实例2)不支持多继承拷贝继承优点:1)支持多继承缺点:1)效率极低,内存占用高(因为要拷贝父类的属性)2)无法获取父类不可枚举的方法(for..in 不能访问到的)组合继承优点:1)弥补了方式2的缺陷,可以继承实例属性/方法,也可以继承原型属性/方法2)既是子类的实例,也是父类的实例3)不存在引用属性共享问题4)函数可复用5)可传参缺点:1)调用了两次构造函数,生成了俩份实例(子类实例将子类原型上的那份屏蔽了)寄生组合继承优点:基本上是完美的缺点:实现起来较为复杂class - extends -- ES6(语法糖 -- 底层仍然是原型链继承的方式)父类
//构造函数
function Animal(name) {this.name = name || 'Animal'this.sleep = function() {console.log(this.name + '正在睡觉!')}
}
//原型上面的方法:
Animal.prototype.eat = function(food) {console.log(this.name + '正在吃:' + food)
}1.原型链继承/* 核心:将父类的实例作为子类的原型 */function Dog() { }Dog.prototype = new Animal()  //将 Animal 的实例挂载到了 Dog 的原型链上/*或:Dog.prototype = Object.create(Animal.prototype)*/Dog.prototype.name = 'dog'var dog = new Dog()console.log(dog.name)        //dogdog.eat('bone')        //dog正在吃:bonedog.sleep()        //dog正在睡觉!console.log(dog instanceof Animal)        //trueconsole.log(dog instanceof Dog)        //true2.构造继承
/* 核心:使用父类的构造函数增强子类实例,等于是复制父类的实例属性给子类(没用到原型) */function Cat(name) {Animal.call(this);this.name = name || 'Tom'}var cat = new Cat()console.log(cat.name)        //Tomcat.sleep()        //Tom正在睡觉!console.log(cat instanceof Animal)        //falseconsole.log(cat instanceof Cat)        //true3.拷贝继承function Cat(name){var animal = new Animal()for(let i in animal) {Cat.prototype[i] = animal[i]}Cat.prototype.name = name || 'Tom'}var cat = new Cat()console.log(cat.name)    //Tomcat.sleep()    //Tom正在睡觉!console.log(cat instanceof Animal)     // falseconsole.log(cat instanceof Cat)     // true4.组合继承
/* 核心:通过调用父类构造,继承父类的属性并保留传参的优点,然后通过将父类实例作为子类原型,实现函数复用 */function Cat(name) {Animal.call(this)this.name = name || 'Tom'}Cat.prototype = new Animal()Cat.prototype.constructor = Catvar cat = new Cat()console.log(cat.name)    //Tomcat.sleep()        //Tom正在睡觉console.log(cat instanceof Animal) // trueconsole.log(cat instanceof Cat) // true5.寄生组合继承
/* 核心:通过寄生方式,砍掉父类的实例属性,这样,在调用两次父类的构造的时候,就不会初始化两次实例方法/属性,避免了组合继承的缺点。 */function Cat(name) {Animal.call(this)this.name = name || 'Tom'}(function() {var Super = function(){}        //创建一个没有实例的方法类。Super.prototype = Animal.prototypeCat.prototype = new Super()      //将实例作为子类的原型。})()let cat = new Cat()console.log(cat.name)                //Tomcat.sleep()                          //Tom正在睡觉console.log(cat instanceof Animal)   //trueconsole.log(cat instanceof Cat)      //trueCat.prototype.constructor = Cat      //修复构造函数

47.作用域

作用域是变量(对象、函数)的可访问范围,是变量在脚本代码中的可读写的有效范围;作用域可以控制变量的可见性和生命周期1.全局作用域定义在所有函数之外的变量,其作用范围是在整个脚本中2.局部作用域(函数作用域)使用var定义在函数内部的变量,其作用范围是整个函数结构,超出函数 {} 花括号的范围则不能使用3.块级作用域ES6声明变量的方式:let / const注意: 使用 const 修饰的变量,赋值确定后,不允许再重新赋值(一般修饰常量或者数组对象之类的)。而且必须给予初始值。const 修饰数组对象后虽然不可以再对变量进行等号赋值了,但是还是可以用数组和对象的方法去改变它的内部结构。
  1. ES5/6 新特性
1.ES51)数组尾逗号    Array.length2)严格模式启动严格模式use strict;    // 注意:必须作为其作用范围内的第一条语句范围/*为<script>开启严格模式作用范围是整个其所在的<script>元素为function开启严格模式作用范围是整个其所在的函数*/严格模式下:变量必须先声名后赋值不允许直接使用以0开头的八进制表示,如果要表示八进制数字,以 0o 为前缀如果直接使用函数名调用函数,则函数体中的 this 为 undefined。
2.ES61)模板字符串作用:拼接字符串与变量,可换行let name = 'wuxiaodi'let res = `hello ${name}!`2)块级作用域特点: let/const 没有声明提升,在变量定义前使用,会报错(暂存性死区)3)箭头函数4)解构赋值5)对象字面量改进const name = 'wuxiaodi';const age = 8;const user = { name, age};6)Spread Operator(即 3 个点 …)可用于组装数组const todos = ['Learn dva'];[...todos, 'Learn antd'];    // ['Learn dva', 'Learn antd']可用于获取数组的部分项const arr = ['a', 'b', 'c'];const [first, ...rest] = arr;rest;    //['b', 'c']// With ignoreconst [first, , ...rest] = arr;rest;  // ['c']可收集函数参数为数组function directions(first, ...rest) {console.log(rest);}directions('a', 'b', 'c');  // ['b', 'c'];代替applyfunction foo(x, y, z){}const args = [1, 2, 3];// 下面两句效果相同foo.apply(null, args);foo(...args);对于 Object 而言,用于组合成新的 Objectconst foo = {a: 1,b: 2,};const bar = {b: 3,c: 2,};const d = 4;const ret = { ...foo, ...bar, d };  // { a:1, b:3, c:2, d:4 }   PS:如果有相同的key,后面的会覆盖前面的7)Promise8)函数默认参数function logActivity(activity = 'skiing') {console.log(activity);}logActivity();    //skiing9)模块的 Import 和 Exportimport用于引入模块,export用于导出模块// 引入部分import dva from 'dva';import { Link, Route } from 'dva/router';// 引入全部并作为 github 对象import * as github from './services/github';// 导出默认export default App// 部分导出,需 import { App } from './file';引入export class App extend Component {};10)内置对象新增 APIArray:Array.from()    // 返回数组,该方法可以将类数组对象转换为数组结构Array.prototype.fill()    // 数组的填充方法Array.prototype.includes()    // 判断数组是否包含某值String:String.prototype.startsWith()    // 判断字符串是否以括号里的内容开头的,返回值是boolean值String.prototype.endsWith()    // 判断字符串是否以括号里的内容结尾,返回值是boolean值11)新增 Map集合12)新增 Set 集合13)Symbol 符号

48.1.伪数组,伪数组转化为标准数组

伪数组:其实就是一个拥有 length 属性的对象。更严格点,这个对象的属性也是数字,但这个对象不具备数组的方法转为标准数组的方法:Array.from()、Array.prototype.slice.call()

48.2. ES5 的继承和 ES6 的继承有什么区别

ES5 的继承时通过 prototype 或构造函数机制来实现。ES5 的继承实质上是先创建子类的实例对象,然后再将父类的方法添加到 this 上(Parent.apply(this))ES6 的继承是先创建父类的实例对象 this(所以必须先调用父类的 super() 方法),然后再用子类的构造函数修改 this
ES6 通过 class 关键字定义类,里面有构造方法,类之间通过 extends 关键字实现继承。子类必须在 constructor 方法中调用 super 方法,否则新建实例报错。因为子类没有自己的 this 对象,而是继承了父类的 this 对象,然后对其进行加工。如果不调用 super 方法,子类得不到 this 对象
注:super 关键字指代父类的实例,即父类的 this 对象。在子类构造函数中,调用 super 后,才可使用 this 关键字,否则报错

49.列举浏览器对象模型BOM里常用的至少四个对象,并列举window对象的常用方法至少五个

window 对象:代表浏览器打开的窗口,是一个全局对象,可以使用 window 来引用该对象常用方法:alert()、confirm()、prompt()、open()、close()Location 对象:代表URL,使用window.location 或 location 来获取该对象常用方法:reload() 重新加载当前文档History 对象:代表访问历史记录,使用 window.history 或 history 来获取该对象常用方法:back() – 后退forward() – 前进go(num) – 前进/后退Navigator 对象:代表浏览器自身,使用window.navigator或navigator来获取该对象常用方法:userAgentDocument 对象 - - DOM:代表浏览器中打开的文档

49.1. document.load 和 jquery.ready 的区别

Document.onload:它是在结构和样式加载完才执行js。【就是在html和css都完事以后才执行】Window.onload:它不仅仅要在结构和样式加载完,还要执行完所有的样式、图片这些资源文件,全部加载完才会触发window.onload事件。jquery中的ready:指定在DOM完全加载时要执行的函数。$().ready(function() {// do something...})

50.创建函数的几种方式

直接调用
事件驱动
自执行【IIFE】(function() {})()(function() {}())+function(){}()

51.iframe的优缺点

优点:解决加载缓慢的第三方内容,如图标和广告等的加载问题Security sandbox 【安全的一个小盒子】并行加载脚本缺点:iframe会阻塞主页面的onload事件即使内容为空,加载也需要时间没有语意常见开发场景:反爬虫【增加爬取难度】、典型系统结构、嵌入页面、跨域加载资源

52.JS延迟加载的方式有哪些

1.script标签的defer和async属性
2.动态创建DOM方式(创建script,插入到DOM中,加载完毕之后callback)
3.按需异步载入js
  1. async,promise,settimeout 的执行顺序
/*任务队列里有先进先出的概念setTimeout 的优先级没有 async 和 Promise 级别高(其实 async 和 Promise 是一样的,因为调用 async 方法时就是返回一个 Promise 对象)
*//* setTimeout 是一个计时器,异步的,所以被扔到任务队列里面 */
setTimeout(() => {                // 任务队列console.log('setTimeout')
}, 0)console.log('t1')/* fetch 是进行数据的请求,调用服务端的内容,这个的不确定性就特别高,主要是看服务端的响应速度与客户端的网速 */
fetch('http://dict.qq.com').then(function(response) {return response.json();
}).then(function(myJson) {console.log('myJson');
}).catch(function(err) {console.log(err)
})console.log('fetch zhi hou')/*当调用 async 函数的时候会返回一个 Promise 对象。Promise对象是立即执行的在 async 里遇到 await,它会使 async 函数暂停执行,执行完 async 里面的内容后,将后续的内容扔入到浏览器的任务队列里面
*/
async function async1() {console.log('async1 start')await async2()console.log('async1 end')    // 任务队列
}
async1()console.log('t2')/*Promise是立即执行,执行成功的话会走 .then 方法,可是它是异步的回调函数,所以会被丢入到任务队列里
*/
new Promise((resolve) => {console.log('promise')resolve()
}).then(() => {console.log('promise.then')    // 任务队列
})console.log('t3')async function async2() {console.log('async2')
}
console.log('t4')执行顺序:
console.log('t1')
console.log('fetch zhi hou')
console.log('async1 start')
console.log('async2')
console.log('t2')
console.log('promise')
console.log('t3')
console.log('t4')console.log('async1 end')
console.log('promise.then')
console.log('setTimeout')console.log('myJson');    /* console.log(err) */const p = Promise.resolve()
(async () => {await pconsole.log('await end')
})()
p.then(() => {console.log('then 1')
}).then(() => {console.log('then 2')
})执行顺序:
then 1
then 2
await end

54.async/await 和 promise 的区别
参考1
参考2,推荐
参考3

promise 和 async/await 都是处理异步请求Promise,简单来说就是一个容器,里面保存着某个未来才会结束的时间(通常是一个异步操作的结果)
async/await 将异步强行转换为同步处理,是寄生于Promise,Generater的语法糖
async/await 和 Promise 都是非阻塞的1 promise是ES6,async/await是ES7
2 async/await相对于promise来讲,写法更加优雅
3 reject状态:1)promise错误可以通过catch来捕捉,建议尾部捕获错误2)async/await既可以用.then又可以用try-catch捕捉

54.1.Promise 通常会解决 3 种问题

1.链式回调
2.同时发起几个异步请求,谁先有结果就拿谁的
3.发起多个请求,等到所有请求后再做下一步处理

55.节流和防抖

防抖一定会节流,但节流不止是防抖节流和防抖是用来处理什么问题的:待解决问题1:如果实现了 dom 拖拽功能,但是在绑定拖拽事件的时候发现每当元素稍微移动一点便触发了大量的回调函数,导致浏览器直接卡死,这个时候怎么办。待解决问题2:如果给一个按钮绑定了表单提交的 post 事件,但是用户有些时候在网络情况极差的情况下多次点击按钮造成表单重复提交,如何防止多次提交的发生?节流和防抖 是在时间轴上控制函数的执行次数防抖:在事件被触发 n 秒后再执行回调,如果在这 n 秒内又被触发,则重新计时【每次触发事件时,都取消之前的延时调用方法】
生活中的事例:如果有人进电梯(触发事件),那电梯将在10秒钟后出发(执行事件监听器),这时如果又有人进电梯了(在10秒内再次触发该事件),我们又得等10秒再出发(重新计时)。
应用场景:给按钮加函数防抖阻止表单多次提交对于输入框连续输入进行AJAX验证时,用函数防抖能有效减少请求次数判断scroll是否滑倒底部,滚动事件+函数防抖
总结:函数防抖适合多次事件一次响应的情况函数防抖是指一定时间内js方法只跑一次。前一次没结束,后一次触发会按后一次的新间隔时间计算。比如按钮持续点击的限速let timeout = null;// 防抖函数,延迟一段时间后执行函数,如果时间内又触发了那么从新计时function debounce(fn, wait) {return (args) => {if (timeout !== null) {clearTimeout(timeout)}timeout = setTimeout(() => fn(args), wait)}}function handle(args) {console.log(args)console.log('处理函数', Math.random())}debounce(handle, 1000)({ id: 'name' });节流:规定一个单位时间,在这个单位时间内,只能有一次触发事件的回调函数执行,如果在同一个单位时间内某事件被触发多次,只有一次能生效【每次触发事件时,都判断当前是否有等待执行的延时函数】
应用场景:游戏中的刷新率DOM元素拖拽Canvas画笔功能
总结:函数节流适合大量事件按时间做平均分配触发函数节流是指一定时间内js方法只跑一次。前一次没结束,后一次不会跑。比如滚动条这种持续按频率触发let _lastTime = null;// 节流函数,规定时间内只触发一次function throttle(fn, gapTime) {return (args) => {let _nowTime = + new Date();if (_nowTime - _lastTime > gapTime || !_lastTime){fn(args);_lastTime = _nowTime}}}throttle(handle, 1500)({ 1: 2 });

56.this、this 指向

this:表示当前对象的一个引用this 指向:this 不是固定不变的,是根据调用的上下文(执行时环境)改变而改变
· 全局环境就是在 <script></script> 里面,这里的 this 始终指向的是 window 对象<script>console.log(this); // 全局环境,即window对象下,this -> window</script>
· 在全局作用域下直接调用函数,this 指向 windowfunction fun() {console.log(this);}fun(); // fun() 实际上是window.fun(), 所以this -> window
· 对象函数调用,哪个对象调用就指向哪个对象var obj1 = {a: 1,fun1: function() {console.log(this);},obj2: {fun2: function() {console.log(this);}}}obj1.fun1(); // fun1 由 obj 调用,所以 this -> obj1obj1.obj2.fun2(); // fun2 由 obj2 调用,所以 this -> obj2
· new 实例化对象,构造函数中的 this 指向实例对象var Person = function() {this.name = "小刘"; // 这里的this -> obj对象}var obj = new Person();
· 在 HTML 事件句柄中,this指 向了接收事件的 HTML 元素<button onclick="this.style.display='none'">点我我就消失</button>

56.1.call、apply、bind 区别

相同点:1.都是改变 this 指向的2.第一个参数都是 this 要指向的对象3.都可以利用后续参数传参不同点:1.call 和 bind 的参数都是依次传参的,且一一对应2.applay 只有两个参数,第二个参数为数组3.call 和 applay 都是对函数进行直接调用;bind 返回的仍是一个函数
eg:var a ={name:'一一',age:'22',sex:'女',hobby:'写代码'say:function(sex,hobby) {         console.log(this.name,this.age,sex,hobby)      }
}
var b = {name:'二二',age:'23',
}
a.say.call(b,'男','学习');
a.say.apply(b,['男','学习'])
bind可以向cally一样传参:
例如:
a.say.bind(b,'男','学习')();
但由于bind返回的仍然是一个函数,所以我们还可以在调用的时候再进行传参。
例如:
a.say.bind(b)('男','学习');
//结果为:"二二","23","男","学习"

57.创建空对象/数组/函数的方式

1.构造对象:使用 new 运算符调用构造函数,可以构造一个实例对象
const object_name = new function_name(args)object_name:返回的示例对象function_name:构造函数,与普通函数基本相同,但是不需要 return 返回值。返回实例对象,在函数内可以使用 this 预先访问args:实例对象初始化配置参数列表// 定义一个空对象
var o = new Object()
// 定义一个空数组
var a = new Array()
// 定义一个空函数
var f = new Function()2.对象直接量:使用直接量可以快速创建对象,也是最高效、最简便的方法
const objectName = {属性名1 : 属性值1,属性名2 : 属性值2,...属性名n : 属性值n
}// 定义一个空对象
var o = {}
// 定义一个空数组
var a = []
// 定义一个空函数
var f = () => {}3.Object.create:是 ES5 新增的一个静态方法,用来创建一个实例对象。该方法可以指定对象的原型和对象特性
Object.create(prototype, descriptors)prototype:必须参数,指定原型对象,可以为 null。descriptors:可选参数,包含一个或多个属性描述符的 JavaScript 对象。属性描述符包含数据特性和访问器特性,其中数据特性说明如下:value:指定属性值writable:默认为 false,设置属性值是否可写enumerable:默认为 false,设置属性是否可枚举(for/in)configurable:默认为 false,设置是否可修改属性特性和删除属性访问器特性包括两个方法:set():设置属性值get():返回属性值eg1:使用 Object.create定义一个对象,继承 null,包含两个可枚举的属性 size 和 shape,属性值分别为 "large" 和 "round"var newObj = Object.create (null, {size : {  // 属性名value : "large",  // 属性值enumerable : true  // 可以枚举},shape : {  // 属性名value : "round",  // 属性值enumerable : true  // 可以枚举}});console.log(newObj.size)  // largeconsole.log(newObj.shape)  // roundconsole.log(Object.getPrototypeOf(newObj))  // nulleg2:使用 Object.create 定义一个与对象直接量具有相同原型的对象var obj = Object.create(Object.prototype, {  // 继承 Obj.prototype 原型对象x : {value : undefined,  // 属性值writable : true,  // 可写configurable : true,  // 可以配置enumerable : true  // 可以枚举}})console.log("obj.prototype = " + Object.getPrototypeOf(obj))  //"obj.prototype =[object, Object]"Object.getPrototypeOf() 函数可获取原始对象的原型。如果要获取对象的属性描述符,可以使用 Object.getOwnPropertyDescriptor() 函数eg3:定义一个对象,使用访问器属性 b 来读写数据属性 avar obj = Object.create(Object.prototype, {a : {  // 数据属性awritable : true,value : "a"},b : {  // 访问器属性bget : function () {return this.a;},set : function (value) {this.a = value;},}});console.log(obj.a);  // "a"console.log(obj.b);  // "a"obj.b = 20;console.log(obj.b);  // 20console.log(obj.a);  // 20

58.改变函数的上下文

1.将函数挂载在对象上
function getdata(fn,obj){obj.fn = fnreturn obj.fn()
}2.call
function getdata(fn,obj){return fn.call(obj)
}3.apply
function getdata(fn,obj){return fn.apply(obj)
}4.bind
function getdata(fn,obj){return fn.bind(obj)()
}

59.匿名函数、普通函数、箭头函数

匿名函数:简单点说就是没有名字的函数,在声明函数时不写函数名称,(将函数赋值给变量)叫匿名函数1.匿名函数可以有效的保证在页面上写入Javascript,而不会造成全局变量的污染2.没有名字的函数会报错,这时候用一个括号把它包起来就不会报错了,然后在最后面加一个括号就可以马上执行这个函数了——直接调用,也叫自执行函数作用: 避免多人开发时变量冲突,自执行函数只能调用一次普通函数1.this 指向直接调用者,非严格模式下没有找到直接调用者就指向 window(严格模式下this是undefined)箭头函数:相当于匿名函数,并且简化了函数定义。箭头函数有两种格式:一种只包含一个表达式,连 { ... } 和 return 都省略掉了。还有一种可以包含多条语句,这时候就不能省略 { ... } 和 return1.箭头函数是匿名函数,不能作为构造函数,不能使用 new2.箭头函数不绑定arguments,取而代之用 rest 参数 ...args 解决3.箭头函数不绑定this,会捕获其所在的上下文的this值,作为自己的this值4.箭头函数通过 call() 或 apply() 方法调用一个函数时,只传入了一个参数,对 this 并没有影响5.箭头函数没有原型属性6.箭头函数不能当做 Generator 函数,不能使用 yield 关键字

前端面试题【背完最低10k】相关推荐

  1. 前端面试题(背题中)

  2. 初中级前端面试题—完整版

    前言 从前端学习到找一份合适的工作,大大小小的面试必不可少,所以我对初级前端面试题进行了初步整理,也方便自己查阅,也希望对小伙伴们有所帮助! HTML HTML语义化 HTML语义化就是让页面内容结构 ...

  3. 阿里web前端面试题到底有多可怕?看完就全明白了!

    今天给大家找来了阿里巴巴的前端面试题,让大家感受一下 大企业的风度,看看你自己距离阿里巴巴这样的大型互联网工资还有多远?里面包含前端面试知识的方方面面,目前本人已经拿到阿里offer,希望能对后面找工 ...

  4. 前端面试题之CSS篇

    前端面试题之CSS篇 一.CSS基础 1. CSS选择器及其优先级 2. CSS中可继承与不可继承属性有哪些 3. display的属性值及其作用 4. display的block.inline和in ...

  5. 【前端】前端面试题整理

    前端和计算机相关知识 你能描述一下渐进增强和优雅降级之间的不同吗 浏览器兼容问题 如何对网站的文件和资源进行优化? 怎么学习前端?怎么接触前端新知识? 关于前后端分离 关于浏览器内核(渲染引擎) 浏览 ...

  6. 前端面试题汇总(JavaScript面试纯干货)

    前端面试题汇总(JavaScript面试纯干货) 1 闭包 闭包就是能够读取其他函数内部变量的函数 闭包是指有权访问另⼀个函数作⽤域中变量的函数,创建闭包的最常⻅的⽅式就是在⼀个函数内创建另⼀个函数, ...

  7. 金三银四,磨砺锋芒;剑指大厂,扬帆起航(2020年最全大厂WEB前端面试题精选)上

    引言 元旦匆匆而过,2020年的春节又接踵而来,大家除了忙的提着裤子加班.年底冲冲冲外,还有着对于明年的迷茫和期待!2019年有多少苦涩心酸,2020年就有更多幸福美好,加油,奥利给!怀着一颗积极向上 ...

  8. 2018最新Web前端经典面试试题及答案-史上最全前端面试题(含答案)--转载

    版权声明:本文为转载文章,感谢博主小胖梅的博客,如有侵权,请联系我删除,谢谢 转载链接: https://blog.csdn.net/xm1037782843/article/details/8070 ...

  9. 前端面试题(HTML、JS、Vue、React、小程序)

    前端面试题 HTML && CSS HTML 1.Div 里面有个一个div ***** Q:有几种方法可以水平,垂直居中 2.doctype的作用 * 3.link标签和import ...

最新文章

  1. 面试官:来说说单点登录的三种实现方式
  2. ViewPager 详解(三)---PagerTabStrip与PagerTitleStrip添加标题栏的异同
  3. OV5640全景模式预览倒180度,拍照正常的问题
  4. 台湾游戏企业抢滩大陆 研发成竞争核心
  5. 怎么用java跟数据库建立关系,java – 关系和构建数据库
  6. 手写tomcat监控工具---宕机重启
  7. 最新安徽省二c语言题型_2020年成人高考考试考前1个月最新最全备考攻略+资料,考生必看,建议收藏!...
  8. JavaScript事件冒泡和事件委托
  9. 数据经济时代大数据四大发展趋势
  10. Ubuntu安装使用(一)
  11. 几个炫酷且实用的CSS动画效果
  12. Wiz.Editor.md 为知笔记 Markdown 插件
  13. 走进tensorflow第九步——WARNING(警告)也值得关注
  14. 什么是千兆交换机和万兆交换机?它们有什么区别?
  15. 同步、异步 阻塞、非阻塞
  16. 基于python的多因子分析
  17. ubuntu14.04+cuda6.5+opencv2.4.9+cuda-convnet2配置
  18. 互联网诞生前,苏联最流行的11台个人电脑
  19. 管道定位83KHZ地下电子信标器|电子标识器的应用与安装说明
  20. 虚拟机 RHEL8 配置软件仓库

热门文章

  1. 常网小站 骗子网站 大家小心别上当
  2. git基于某个Tag修改提交
  3. Windows10清理预留存储
  4. 自然语言处理(基于预训练模型)01FMM分词算法
  5. 作为技术负责人,如何从0搭建公司后端技术栈
  6. ScrollPic.js——图片左右滚动插件(单一功能)
  7. 安卓学习专栏——安卓报错android.support.v4.widget.SwipeRefreshLayout飘红
  8. 犹太人:赚钱能培养孩子独立责任奋进多种能力!
  9. leetcode简单之597.好友申请I:总体通过率
  10. 单片机led灯闪烁实验总结_新款LED型便携式实验室高强度紫外线灯对比说明