整理
一.HTML
1、HTML5新特性,语义化
(1)什么是HTML语义化?
基本上都是围绕着几个主要的标签,像标题(H1~H6)、列表(li)、强调(strong em)等等>
根据内容的结构化(内容语义化),选择合适的标签(代码语义化)便于开发者阅读和写出更优雅的代码 的同时让浏览器的爬虫和机器很好地解析。
(2)为什么要语义化?
为了在没有CSS的情况下,页面也能呈现出很好地内容结构、代码结构:为了裸奔时好看;
用户体验:例如title、alt用于解释名词或解释图片信息、label标签的活用;
有利于SEO:和搜索引擎建立良好沟通,有助于爬虫抓取更多的有效信息:爬虫依赖于标签来确定上下文和各个关键字的权重;
方便其他设备解析(如屏幕阅读器、盲人阅读器、移动设备)以意义的方式来渲染网页;
便于团队开发和维护,语义化更具可读性,是下一步吧网页的重要动向,遵循W3C标准的团队都遵循这个标准,可以减少差异化。
(3)写HTML代码时应注意什么?
尽可能少的使用无语义的标签div和span;
在语义不明显时,既可以使用div或者p时,尽量用p, 因为p在默认情况下有上下间距,对兼容特殊终端有利;
不要使用纯样式标签,如:b、font、u等,改用css设置。
需要强调的文本,可以包含在strong或者em标签中(浏览器预设样式,能用CSS指定就不用他们),strong默认样式是加粗(不要用b),em是斜体(不用i);
使用表格时,标题要用caption,表头用thead,主体部分用tbody包围,尾部用tfoot包围。表头和一般单元格要区分开,表头用th,单元格用td;
表单域要用fieldset标签包起来,并用legend标签说明表单的用途;
每个input标签对应的说明文本都需要使用label标签,并且通过为input设置id属性,在lable标签中设置for=someld来让说明文本和相对应的input关联起来。
(4)HTML5新增了哪些语义标签,详述之。
1、<section></section>
定义文档中的主体部分的节、段。
2、<article></article>
一个特殊的section标签,比section有更明确的语义。定义来自外部的一个独立的、完整的内容块,例如什么论坛的文章,博客的文本。。。
3、<aside></aside>
用来装载页面中非正文的内容,独立于其他模块。例如广告、成组的链接、侧边栏。
4、<header></header>
定义文档、页面的页眉。通常是一些引导和导航信息,不局限于整个页面头部,也可以用在内容里。
5、<footer></footer>
定义了文档、页面的页脚,和header类似。
6、<nav></nav>
定义了一个链接组组成的导航部分,其中的链接可以链接到其他网页或者当前页面的其他部分。
7、<hgroup></hgroup>
用于对网页或区段(section)的标题元素(h1~h6)进行组合。
8、<figure></figure>
用于对元素进行组合。
9、<figcaption></figcaption>
为figure元素加标题。一般放在figure第一个子元素或者最后一个。
10、<details></details>
定义元素的细节,用户可以点击查看或者隐藏。
11、<summary></summary>和details连用,用来包含details的标题。
12、<canvas></canvas>
用来进行canvas绘图。
13、<video></video>
定义视频。
14、<audio></audio>
定义音频。
15、<embed></embed>
定义嵌入网页的内容。比如插件。
16、<source></source>
该标签为媒介元素(比如video、audio)定义媒介元素。
17、<datalist id='dl'></datalist>
定义可选数据的列表,与input配合使用(<input list='dl'>)可制作输入值的下拉列表。
18、<mark></mark>
在视觉上向用户展现出那些想要突出的文字。比如搜索结果中向用户高亮显示搜索关键词。
19、<meter [min/max/low/high/optimum/value]></meter>
度量衡,用红黄绿表示出一个数值所在范围。
20、<output></output>
定义不同类型的输出,样式与span无异。
21、<progress></progress>
进度条,运行中的进度。
22、<time></time>
定义日期或者时间。
23、<keygen></keygen>
定义加密内容。
24、<command></command>
定义命令行为。
2、浏览器的标准模式和怪异模式
(1)盒模型的处理差异:
元素溢出的处理
标准模式下,overflow取值默认为visible;在怪异模式在,该溢出会被当做扩展box来对待,即元素的大小由内容决定,溢出不会裁剪,元素框自动调整,包含溢出内容。
元素的百分比高度
CSS中对于元素的百分比高度规定:百分比为元素包含块的高度,不可为负值;如果包含块的高度没有显示给出,该值等同于auto,所以百分比的高度必须是在元素有高度声明的情况下使用。
当一个元素使用百分比高度时,标准模式下,高度取决于内容变化,怪异模式下,百分比高度被准确应用
内联元素的尺寸
标准模式下,non-replaced inline元素无法自定义大写;
怪异模式下,定义这些元素的width、height属性可以影响这些元素显示的尺寸。
行内元素的垂直对齐
元素中的字体
CSS中,对于font的属性都是可以继承的。怪异模式下,对于table元素,字体的某些元素将不会从body等其他封装元素继承中的得到,特别是font-size属性。
3、xhtml和html的区别
1、XHTML 要求正确嵌套
2、XHTML 所有元素必须关闭
3、 XHTML 区分大小写
4、 XHTML 属性值要用双引号
5、XHTML 用 id 属性代替 name 属性
6、XHTML 特殊字符的处理
https://blog.csdn.net/liaozhongping/article/details/47031783
4、使用data-的好处
data-* 属性用于存储页面或应用程序的私有自定义数据。
data-* 属性赋予我们在所有 HTML 元素上嵌入自定义 data 属性的能力。
存储的(自定义)数据能够被页面的 JavaScript 中利用,以创建更好的用户体验(不进行 Ajax 调用或服务器端数据库查询)。
H5的新属性
5、meta标签(http://www.cnblogs.com/libin-1/p/5979300.html)
<meta> 元素可提供有关页面的元信息(meta-information),比如针对搜索引擎和更新频度的描述和关键词。
<meta> 标签位于文档的头部,不包含任何内容。<meta> 标签的属性定义了与文档相关联的名称/值对。
标签永远位于 head 元素内部。
元数据总是以名称/值的形式被成对传递的。
meta标签根据属性的不同,可分为两大部分:http-equiv 和 name 属性。
http-equiv:相当于http的文件头作用,它可以向浏览器传回一些有用的信息,以帮助浏览器正确地显示网页内容。
name属性:主要用于描述网页,与之对应的属性值为content,content中的内容主要是便于浏览器,搜索引擎等机器人识别,等等。
6、canvas
7、HTML废弃的标签
8、IE6 bug,和一些定位写法
9、css js放置位置和原因
10、什么是渐进式渲染
一开始先加载首屏显示的内容
之后再随着时间或者滚动页面才进行后面的加载
11、html模板语言
Ejs jsx html jade jsp
12、meta viewport原理
meta viewport 的6个属性:
属性 |
值 |
width |
设置layout viewport 的宽度,为一个正整数,或字符串”width-device” |
initial-scale |
设置页面的初始缩放值,为一个数字,可以带小数 |
minimum-scale |
允许用户的最小缩放值,为一个数字,可以带小数 |
maximum-scale |
允许用户的最大缩放值,为一个数字,可以带小数 |
height |
设置layout viewport 的高度,这个属性并不重要,很少使用 |
user-scalable |
是否允许用户进行缩放,值为”no”或”yes”, no 代表不允许,yes代表允许 |
devicePixelRatio = 物理像素 / 独立像素
layout viewport :通过 document.documentElement.clientWidth 来获取。
visual viewport:通过window.innerWidth 来获
ideal viewport的宽度等于移动设备的屏幕宽度,只要在css中把某一元素的宽度设为ideal viewport的宽度(单位用px),那么这个元素的宽度就是设备屏幕的宽度了,也就是宽度为100%的效果。
二.CSS
1、盒模型,box-sizing
在标准模型中,盒模型的宽高只是内容(content)的宽高,
而在IE模型中盒模型的宽高是内容(content)+填充(padding)+边框(border)的总宽高。
/* 标准模型 */ box-sizing:content-box;
/*IE模型*/ box-sizing:border-box;
请解释*{box-sizing:border-box;}的作用,并说明使用它的好处
固定的盒子大小 padding增加不改变大小至改变内部位置 border改变也不会改变他的大小
省略号:
一、单行
overflow: hidden;
text-overflow:ellipsis;
white-space: nowrap;
多行
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
overflow: hidden;
注:
- -webkit-line-clamp用来限制在一个块元素显示的文本的行数。 为了实现该效果,它需要组合其他的WebKit属性。常见结合属性:
- display: -webkit-box; 必须结合的属性 ,将对象作为弹性伸缩盒子模型显示 。
- -webkit-box-orient 必须结合的属性 ,设置或检索伸缩盒对象的子元素的排列方式 。
实现方法:
p{position: relative; line-height: 20px; max-height: 40px;overflow: hidden;}
p::after{content: "..."; position: absolute; bottom: 0; right: 0; padding-left: 40px;
background: -webkit-linear-gradient(left, transparent, #fff 55%);
background: -o-linear-gradient(right, transparent, #fff 55%);
background: -moz-linear-gradient(right, transparent, #fff 55%);
background: linear-gradient(to right, transparent, #fff 55%);
}
效果如图:
适用范围:
该方法适用范围广,但文字未超出行的情况下也会出现省略号,可结合js优化该方法。
注:
- 将height设置为line-height的整数倍,防止超出的文字露出。
- 给p::after添加渐变背景可避免文字只显示一半。
- 由于ie6-7不显示content内容,所以要添加标签兼容ie6-7(如:<span>…<span/>);兼容ie8需要将::after替换成:after。
2、CSS3新特性,伪类,伪元素,锚伪类
3、CSS3的选择器
4、@Font-face
5、圆角
6、多列布局 (multi-column layout)
7、阴影(Shadow)
8、CSS3 的渐变效果
9、css弹性盒子模型
10、CSS3制作特效
Transition 对象变换时的过渡效果
Transforms
Animation动画特效
11、CSS实现隐藏页面的方式
Display:none Opacity:0 position:absolute (z-index)
12、如何实现水平居中和垂直居中。
13、说说position,display
14、浮动元素引起的问题和解决办法?绝对定位和相对定位,元素浮动后的display值
1.使用空标签清除浮动。这种方法是在所有浮动标签后面添加一个空标签定义css clear:both.弊端就是增加了无意义标签。
2.使用overflow。给包含浮动元素的父标签添加css属性overflow:auto;zoom:1;zoom:1用于兼容IE6。
3.使用after伪对象清除浮动。该方法只适用于非IE浏览器。具体写法可参照以下示例。使用中需注意以下几点。一、该方法中必须为需要清除浮动元素的伪对象中设置height:0,否则该元素会比实际高出若干像素;二、content属性是必须的,但其值可以为空,content属性的值设为”.”,空亦是可以的。
4.浮动外部元素
15、link和@import引入css的区别
差别1 :适用范围不同 @import可以在网页页面中使用,也可以在css文件中使用,用来将多个css文件引入到一个css文件中;而link只能将css文件引入到网页页面中。
差别2: 功能范围不同 link属于XHTML标签,而@import是CSS提供的一种方式,link标签除了可以加载CSS外,还可以定义RSS,定义rel连接属性等,@import就只能加载CSS。
差别3: 加载顺序不同 当一个页面被加载的时候,link引用的CSS会同时被加载,而@import引用的CSS会等到页面全部被下载完再被加载。所以有时候浏览@import加载CSS的页面时开始会没有样式(就是闪烁),网速慢的时候还挺明显。
差别4: 兼容性 由于@import是css2.1提出的,所以老的浏览器不支持,@import只有在IE5以上的才能识别,而link标签无此问题。
差别5: 控制样式时的差别 使用link方式可以让用户切换CSS样式.现代浏览器如Firefox,Opera,Safari都支持rel=”alternate stylesheet”属性(即可在浏览器上选择不同的风格),当然你还可以使用Javascript使得IE也支持用户更换样式。
16、解释一下css3的flexbox,以及适用场景
17、inline和inline-block的区别
18、哪些是块级元素那些是行级元素,各有什么特点
19、布局
流式布局如何实现,响应式布局如何实现
移动端布局方案
实现三栏布局(圣杯布局,双飞翼布局,flex布局)
静态布局:给页面元素设置固定的宽度和高度,单位用px,当窗口缩小,会出现滚动条,拉动滚动条显示被遮挡内容。针对不同分辨率的手机端,分别写不同的样式文件。
自适应布局:创建多个静态布局,每个静态布局对应一个屏幕分辨率范围,使用@media媒体查询技术。
流式布局:元素的宽高用百分比做单位,元素宽高按屏幕分辨率调整,布局不发生变化。屏幕尺度跨度过大的情况下,页面不能正常显示。
响应式布局:采用自适应布局和流式布局的综合方式,为不同屏幕分辨率范围创建流式布局。
弹性布局:要点在于使用em和rem单位来定义元素宽度,与流式布局有极大的相似性,但也有不同之处,主要区别在于弹性布局的尺寸主要根据字体大小而变化。
grid布局
table布局的作用
20、css dpi
每英寸包含点的数量(dots per inch)
普通屏幕通常包含96dpi,一般将2倍于此的屏幕称之为高分屏,即大于等于192dpi的屏幕,比如Mac视网膜屏就达到了192dpi(即2dppx),打印时一般会需要更大的dpi;
21、你知道attribute和property的区别么
Attribute就是dom节点自带的属性,例如html中常用的id、class、title、align等:
而Property是这个DOM元素作为对象,其附加的内容,例如childNodes、firstChild等:
css布局问题?css实现三列布局怎么做?如果中间是自适应又怎么做?
22、清除浮动的原理
23、overflow:hidden有什么缺点?
24、padding百分比是相对于父级宽度还是自身的宽度
25、css3动画,transition和animation的区别,animation的属性,加速度,重力的模拟实现
26、CSS 3 如何实现旋转图片(transform: rotate)
27、sass less
28、对移动端开发了解多少?(响应式设计、Zepto;@media、viewport、JavaScript 正则表达式判断平台。)
29、什么是bfc,如何创建bfc?解决什么问题?
首先要明确BFC是什么意思,其全英文拼写为 Block Formatting Context 直译为“块级格式化上下文”
BFC的原理
内部的box会在垂直方向,一个接一个的放置
每个元素的margin box的左边,与包含块border box的左边相接触(对于从做往右的格式化,否则相反)
box垂直方向的距离由margin决定,属于同一个bfc的两个相邻box的margin会发生重叠
bfc的区域不会与浮动区域的box重叠
bfc是一个页面上的独立的容器,外面的元素不会影响bfc里的元素,反过来,里面的也不会影响外面的
计算bfc高度的时候,浮动元素也会参与计算
怎么取创建bfc
float属性不为none(脱离文档流)
position为absolute或fixed
display为inline-block,table-cell,table-caption,flex,inine-flex
overflow不为visible
根元素
应用场景
自适应两栏布局
清除内部浮动
防止垂直margin重叠
30、CSS中的长度单位(px,pt,rem,em,ex,vw,vh,vh,vmin,vmax)
31、CSS 选择器的优先级是怎样的?
32、雪碧图
33、Svg
34、媒体查询的原理是什么?
35、窗口的onresize事件,得到窗口大小匹配对应的样式修改
36、CSS 的加载是异步的吗?表现在什么地方?
37、常遇到的浏览器兼容性问题有哪些?常用的hack的技巧
38、外边距合并
39、解释一下“::before”和“:after”中的双冒号和单冒号的区别
单冒号(:)用于CSS3伪类,双冒号(::)用于CSS3伪元素。
三. JS
javascript中offsetWidth、clientWidth、width、scrollWidth、clientX、screenX、offsetX、pageX
offsetWidth //返回元素的宽度(包括元素宽度、内边距和边框,不包括外边距)
offsetHeight //返回元素的高度(包括元素高度、内边距和边框,不包括外边距)
clientWidth //返回元素的宽度(包括元素宽度、内边距,不包括边框和外边距)
clientHeight //返回元素的高度(包括元素高度、内边距,不包括边框和外边距)
style.width //返回元素的宽度(包括元素宽度,不包括内边距、边框和外边距)
style.height //返回元素的高度(包括元素高度,不包括内边距、边框和外边距)
scrollWidth //返回元素的宽度(包括元素宽度、内边距和溢出尺寸,不包括边框和外边距),无溢出的情况,与clientWidth相同
scrollHeigh //返回元素的高度(包括元素高度、内边距和溢出尺寸,不包括边框和外边距),无溢出的情况,与clientHeight相同
1. style.width 返回的是字符串,如28px,offsetWidth返回的是数值28;
2. style.width/style.height与scrollWidth/scrollHeight是可读写的属性,clientWidth/clientHeight与offsetWidth/offsetHeight是只读属性
3. style.width的值需要事先定义,否则取到的值为空。而且必须要定义在html里(内联样式),如果定义在css里,style.height的值仍然为空,但元素偏移有效;而offsetWidth则仍能取到。
//---------------------------------------------------------------------------offsetTop //返回元素的上外缘距离最近采用定位父元素内壁的距离,如果父元素中没有采用定位的,则是获取上外边缘距离文档内壁的距离。所谓的定位就是position属性值为relative、absolute或者fixed。返回值是一个整数,单位是像素。此属性是只读的。
offsetLeft //此属性和offsetTop的原理是一样的,只不过方位不同,这里就不多介绍了。
scrollLeft //此属性可以获取或者设置对象的最左边到对象在当前窗口显示的范围内的左边的距离,也就是元素被滚动条向左拉动的距离。返回值是一个整数,单位是像素。此属性是可读写的。
scrollTop //此属性可以获取或者设置对象的最顶部到对象在当前窗口显示的范围内的顶边的距离,也就是元素滚动条被向下拉动的距离。返回值是一个整数,单位是像素。此属性是可读写的。
//---------------------------------------------------------------------------
当鼠标事件发生时(不管是onclick,还是omousemove,onmouseover等)
clientX 鼠标相对于浏览器(这里说的是浏览器的有效区域)左上角x轴的坐标; 不随滚动条滚动而改变;
clientY 鼠标相对于浏览器(这里说的是浏览器的有效区域)左上角y轴的坐标; 不随滚动条滚动而改变;
pageX 鼠标相对于浏览器(这里说的是浏览器的有效区域)左上角x轴的坐标; 随滚动条滚动而改变;
pageY 鼠标相对于浏览器(这里说的是浏览器的有效区域)左上角y轴的坐标; 随滚动条滚动而改变;
screenX 鼠标相对于显示器屏幕左上角x轴的坐标;
screenY 鼠标相对于显示器屏幕左上角y轴的坐标;
offsetX 鼠标相对于事件源左上角X轴的坐标
offsetY 鼠标相对于事件源左上角Y轴的坐标
1、js的基本类型有哪些?引用类型有哪些?引用类型和基本类型有什么区别?哪个是存在堆哪一个是存在栈上面的?null和undefined的区别。
基本类型:Number,String,Boolean,Null,undefined。
引用类型:Object,Array,Date,RegExp,Function
if (!undefined) console.log('undefined is false'); // undefined is false if (!null) console.log('null is false'); // null is false undefined == null // true
null 是对象Number(null) //0
Number(undefined)// NaN
null表示"没有对象",即该处不应该有值。典型用法是:
(1) 作为函数的参数,表示该函数的参数不是对象。
(2) 作为对象原型链的终点。
undefined表示"缺少值",就是此处应该有一个值,但是还没有定义。典型用法是:
(1)变量被声明了,但没有赋值时,就等于undefined。
(2) 调用函数时,应该提供的参数没有提供,该参数等于undefined。
(3)对象没有赋值的属性,该属性的值为undefined。
(4)函数没有返回值时,默认返回undefined。
区别:
基本类型:(1)基本类型的值是不可变得。(2)基本类型的比较是值的比较:(3)基本类型的变量是存放在栈区的(栈区指内存里的栈内存)
引用类型:(1)引用类型的值是可变的(2)引用类型的比较是引用的比较(3)引用类型的值是同时保存在栈内存和堆内存中的对象
2、如何判断一个变量是Array类型?如何判断一个变量是Number类型?(都不止一种)
(1)instanceof操作符
(2)对象的constructor属性
(3)Object.prototype.toString.call(o) === '[object Array]'; (4)Array.isArray()
(5)function isArrayFn(value){
if (typeof Array.isArray === "function") {
return Array.isArray(value);
}else{
return Object.prototype.toString.call(value) === "[object Array]"; }}
3、请说出三种减少页面加载时间的方法。(加载时间指感知的时间或者实际加载时间)
1.优化图片
2.图像格式的选择(GIF:提供的颜色较少,可用在一些对颜色要求不高的地方)
3.优化CSS(压缩合并css,如margin-top,margin-left...)
4.网址后加斜杠(如www.campr.com/目录,会判断这个“目录是什么文件类型,或者是目录。)
5.标明高度和宽度(如果浏览器没有找到这两个参数,它需要一边下载图片一边计算大小,如果图片很多,浏览器需要不断地调整页面。这不但影响速度,也影响浏览体验。当浏览器知道了高度和宽度参数后,即使图片暂时无法显示,页面上也会腾出图片的空位,然后继续加载后面的内容。从而加载时间快了,浏览体验也更好了。)
6.减少http请求(合并文件,合并图片)。
4、线程与进程的区别
一个程序至少有一个进程,一个进程至少有一个线程。线程的划分尺度小于进程,使得多线程程序的并发性高。
另外,进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。
线程在执行过程中与进程还是有区别的。每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。
从逻辑角度来看,多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。但操作系统并没有将多个线程看做多个独立的应用,来实现进程的调度和管理以及资源分配。这就是进程和线程的重要区别。
5、JS中的类
一般使用函数作为载体而存在,而JS中函数又是对象,所以这里cifer请大家回忆一下对象的定义:
//对象的直接量
var Biology_1 = {};
//new来创建
var Biology_2 = new Object();
//Object.create()创建,es5以上支持
var Biology_3 = Object.create(null);
与此同时,顺便提下三个词:
prototype 实例指向原型,构造函数指向原型。
construtor 原型指向构造函数。该构造函数的原型指向Object,而该Object的的construtor 又指回该构造函数。或者又说,属性返回对创建此对象的数组函数的引用。
proto 实例指向构造函数的原型(其中,如果原型是Object,则它的proto 指向function,而该function的proto 又指向Object)。
听着有点绕,看看实例就明白了。
工厂模式
function Biology(name) {
var tempObj = new Object();
tempObj.name = name;
tempObj.printName = function(){
console.log(this.name);
};
return tempObj;
}
var animals = Biology('animals');
var plants = Biology('plants');
animals.printName();//animals
plants.printName();//plants
animals.constructor;//function Object() { [native code] }
其实是实例化Object,缺点是无法识别对象类型
构造模式
function Biology(name) {
this.name = name;
this.printName = function(){
console.log(this.name);
};
}
var animals = new Biology('animals');
var plants = new Biology('plants');
animals.printName();//animals
plants.printName();//plants
animals.constructor;//function Biology(name){...}
构造函数的方式,实现对象类型识别,不过性能或封装性差
原型模式
function Biology() {};
Biology.prototype.name = 'biology';
Biology.prototype.printName = function(){
console.log(this.name);
};
var animals = new Biology();
animals.printName();//biology
var plants = new Biology();
plants.printName();//biology
console.log(animals.name);//biology
animals.name = 'animals';
console.log(animals.name);//animals
console.log(plants.name);//biology
animals.printName = function(){
console.log('animals');
};
animals.printName();//animals
plants.printName();//biology
原型的属性方法是所有实例共享的,而如果实例属性(方法)与原型属性(方法)重复时,优先实例属性(方法),其中有个hasOwnProperty用来判断是否实例属性。
因为上述例子中,使用Biology.prototype.name,Biology.prototype.printName这样的直接修改,过于分散与重复,于是我们进行一个合并:
function Biology() {};
Biology.prototype = {
name : 'biology',
printName : function(){
console.log(this.name);
}
};
var biology = new Biology();
console.log(biology.name);//biology
console.log(biology.constructor);//function Object() {}
合并后,看起来没什么问题,不过biology的构建函数不再是Biology,那并不是我们想要的。所以把构建函数指回Biology:
function Biology() {};
Biology.prototype = {
constructor : Biology,
name : 'biology',
printName : function(){
console.log(this.name);
}
};
var biology = new Biology();
console.log(biology.name);//biology
console.log(biology.constructor);//function Biology() {}
已经如我们所愿,这是因为创建一个函数,同是会创建他的prototype对象,同时这对象自动获得constructor,重写prototype时,constructor不再指向原Biology
那如果实例化之后修改原型,会发生什么?
function Biology() {};
var biology = new Biology();
Biology.prototype = {
constructor : Biology,
name : 'biology',
printName : function(){
console.log(this.name);
}
};
console.log(biology.name);//undefined
undefined!,你没有看错。
如之前所说,同时,因为实例指向的是原型,而不是构造函数,所以,如果在实例化之后原型有变化,原来的实例指向的还是旧原型
不过总的来说,原型模式如果修改的原型属性或方法,之后的创建的实例都会变化,没有隐私而言,所以还有改进空间
构造模式与原型模式组合
function Biology(age) {
this.age = age;
};
Biology.prototype = {
constructor : Biology,
name : 'biology',
printAll : function(){
console.log(this.name + ':' + this.age);
}
};
var biology_1 = new Biology(16);
var biology_2 = new Biology(18);
biology_1.printAll();//biology:16
biology_2.printAll();//biology:18
把共享部分使用原型,不公享部分使用构造,本方法比较常见。
其他像的模式还有很多,像什么动态原型模式、寄生构造函数模式,原理上都是使用上述方式自由组合,就不一一列举了。
类的属性与方法
比较Java,类有私有属性,公共属性,私有方法,公共方法,原型属性,原型方法,可惜在JS没有这些好东西,不过,我们知道JS中var有作用域以及原型的概念,所以我们可以模拟出这些东西。
function Biology(){
//私有方法
function privateMethod(){
return '私有方法';
}
//私有属性
var privateProperty = '私有属性';
//实例属性
this.publicProperty = '实例属性';
//原型属性
Biology.prototype.staticProperty = '原型属性';
var privateMethod = function(){
return '私有方法';
};
//实例方法
this.publicMethod = function(){
return '实例方法';
};
//原型方法
Biology.prototype.staticMethod = function(){
return '原型方法';
};
//获得私有属性
this.getPrivateProperty = function(){
return privateProperty;
};
//设置私有属性
this.setPrivateProperty = function(property){
privateProperty = property;
};
//执行私有方法
this.getPrivateMethod = function(){
return privateMethod();
};
}
var biology = new Biology();
var biology_2 = new Biology();
console.log(biology.privateProperty);//undefined
console.log(biology.publicProperty);//实例属性
biology.publicProperty = '修改后的实例属性';
console.log(biology.publicProperty);//修改后的实例属性
console.log(biology_2.publicProperty);//实例属性
console.log(biology.getPrivateProperty());//私有属性
biology.setPrivateProperty('改变后的私有属性');
console.log(biology.getPrivateProperty());//改变后的私有属性
console.log(biology_2.getPrivateProperty());//私有属性
console.log(privateProperty);//undefined
console.log(biology.privateProperty);//underfined
console.log(biology.staticProperty);
Biology.prototype.staticProperty = '修改后的原型属性';
console.log(biology.staticProperty);
console.log(biology_2.staticProperty);
console.log(biology.privateMethod);//undefined
console.log(biology.publicMethod());//实例方法
console.log(biology.getPrivateMethod());//私有方法
console.log(biology.staticMethod());
Biology.prototype.staticMethod = function(){
return '修改后的原型方法';
};
console.log(biology.staticMethod());//修改后的原型方法
console.log(biology_2.staticMethod());//修改后的原型方法
类的继承
原型继承
function Biology(name) {
this.name = name;
}
Biology.prototype = {
constructor : Biology,
printName : function(){
console.log(this.name);
}
};
function Animals(){};
Animals.prototype = new Biology('animals');
var animals = new Animals();
animals.printName();//animals
不过,为了便于使用与理解,我们一般会换成形式写:
var Biology = {
name : 'I am Biology'
};
//继承parent
function inherit(parent){
var type = typeof parent;
if(!(type === 'object' || type === 'function')) throw TypeError;
if(Object.create){
return Object.create(parent);
}
function temp() {};
temp.prototype = parent;
return new temp;
}
var animals = inherit(Biology);
console.log(animals.name);//I am Biology
构造函数继承
function Biology(name) {
this.name = name;
};
function Animals(name,age){
this.temp = Biology;
this.temp(name);
this.age = age;
this.printAll = function(){
console.log(this.name + ':' + this.age);
}
}
var animals = new Animals('animals',16);
animals.printAll();//animals:16
apply,call继承
function Biology(name) {
this.name = name;
this.printName = function(){
console.log(this.name);
}
}
function Animals(age){
this.age = age;
Biology.call(this,age);
}
function Plants(address){
this.address = address;
Biology.apply(this,[address]);
}
var animals = new Animals('animals',16);
animals.printName();//animals
var plants = new Plants('plants','深圳');
plants.printName();//plants
ES6类
ES6则在上面基础上,增加了像class,extends,super等面向对象关键字,在写法上简化了类的写法,然后,这些关键字也是在之前的基础上模拟出来的,并且与原型息息相关,甚至有时带来更多的问题。
下面这个例子,简单的对ES6对类进行阐述:
class Biology {
constructor(name){
this.name = name;
}
printName(){
console.log(this.name);
}
static printNameTwice(){
console.log(this.name + ',' + this.name);
}
}
var biology = new Biology('biology');
biology.printName();//biology
Biology.printNameTwice();//biology,biology
class Animals extends Biology {
constructor(name,age){
super(name);
this.age = age;
}
printAll(){
console.log(this.name + ':' + this.age);
}
printName(){
console.log('animals name');
}
get name() {
return this._name.toUpperCase();
}
set name(name) {
this._name = name;
}
}
var animals = new Animals('animals',16);
console.log(animals.name);//ANIMALS
console.log(animals._name);//animals
animals.printName();//animals name
animals.printAll();//ANIMALS:16
Animals.printNameTwice();//Animals,Animals
5、js判断对象是否为空对象的几种方法js判断对象是否为空对象的几种方法
1.将json对象转化为json字符串,再判断该字符串是否为"{}"
var data = {};
var b = (JSON.stringify(data) == "{}");
alert(b);//true
2.for in 循环判断
var obj = {};
var b = function() {
for(var key in obj) {
return false;
}
return true;
}
alert(b());//true
3.jquery的isEmptyObject方法
此方法是jquery将2方法(for in)进行封装,使用时需要依赖jquery
var data = {};
var b = $.isEmptyObject(data);
alert(b);//true
4.Object.getOwnPropertyNames()方法
此方法是使用Object对象的getOwnPropertyNames方法,获取到对象中的属性名,存到一个数组中,返回数组对象,我们可以通过判断数组的length来判断此对象是否为空
注意:此方法不兼容ie8,其余浏览器没有测试
var data = {};
var arr = Object.getOwnPropertyNames(data);
alert(arr.length == 0);//true
5.使用ES6的Object.keys()方法
与4方法类似,是ES6的新方法, 返回值也是对象中属性名组成的数组
var data = {};var arr = Object.keys(data);
alert(arr.length == 0);//true
6、JS常见的dom操作api
7、解释一下事件冒泡和事件捕获
addEventListener("click", function(e) {
console.log("body 捕获", e.target.nodeName, e.currentTarget.nodeName);
}, true);
addEventListener("click", function(e) {
console.log("body 冒泡", e.target.nodeName, e.currentTarget.nodeName);
}, false);
8、事件委托(手写例子),事件冒泡和捕获,如何阻止冒泡?如何阻止默认事件?
9、对闭包的理解?什么时候构成闭包?闭包的实现方法?闭包的优缺点?
闭包就是一个函数,捕获作用域内的外部绑定。这些绑定是为之后使用而被绑定,即使作用域已经销毁。
由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。
闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。
10、this有哪些使用场景?跟C,Java中的this有什么区别?如何改变this的值?
this永远指向函数运行时所在的对象,而不是函数被创建时所在的对象。匿名函数或不处于任何对象中的函数指向window 。
1.如果是call,apply,with,指定的this是谁,就是谁。
2.普通的函数调用,函数被谁调用,this就是谁。
call,apply,bind
11、显示原型和隐式原型,手绘原型链,原型链是什么?为什么要有原型链
显式原型:prototype 隐式原型:__proto__
12、创建对象的多种方式
https://www.cnblogs.com/gromimiss/p/5938647.html
12、实现继承的多种方式和优缺点
https://segmentfault.com/a/1190000011151188
原型继承
核心:子构造函数的原型指向父构造函数的实例
每个构造函数都有一个原型对象,原型对象中都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针。当原型对象等于另外一个类型的实例即继承。
缺点: 子类实例共享属性,造成实例间的属性会相互影响
function Parent1() {
this.name = ['super1']
this.reName = function () {
this.name.push('super111')
}
}function Child1() {
}
Child1.prototype = new Parent1()
var child11 = new Child1()
var child12 = new Child1()
var parent1 = new Parent1()
child11.reName()
console.log(child11.name, child12.name) // [ 'super1', 'super111' ] [ 'super1', 'super111' ], 可以看到子类的实例属性皆来自于父类的一个实例,即子类共享了同一个实例console.log(child11.reName === child12.reName) // true, 共享了父类的方法
构造函数继承
缺点: 父类的方法没有被共享,造成内存浪费
function Child2() {
Parent1.call(this)
}
var child21 = new Child2()
var child22 = new Child2()
child21.reName()
console.log(child21.name, child22.name) // [ 'super1', 'super111' ] [ 'super1' ], 子实例的属性都是相互独立的
console.log(child21.reName === child22.reName) // false, 实例方法也是独立的,没有共享同一个方法
组合继承
缺点: 父类构造函数被调用两次,子类实例的属性存在两份。造成内存浪费
function Parent3() {
this.name = ['super3']
}
Parent3.prototype.reName = function() {
this.name.push('super31')
}
function Child3() {
Parent3.call(this) // 生成子类的实例属性(但是不包括父对象的方法)
}
Child3.prototype = new Parent3() // 继承父类的属性和方法(副作用: 父类的构造函数被调用的多次,且属性也存在两份造成了内存浪费)
var child31 = new Child3()
var child32 = new Child3()
child31.reName()
console.log(child31.name, child32.name) // [ 'super3', 'super31' ] [ 'super3' ], 子类实例不会相互影响
console.log(child31.reName === child32.reName) //true, 共享了父类的方法
寄生继承
完美:子类都有各自的实例不会相互影响,且共享了父类的方法
function Parent4() {
this.name = ['super4']
}
Parent4.prototype.reName = function() {
this.name.push('super41')
}function Child4() {
Parent4.call(this) // 生成子类的实例属性(但是不包括父对象的方法)
}
Child4.prototype = Object.create(Parent4.prototype) // 该方法会使用指定的原型对象及其属性去创建一个新的对象
var child41 = new Child4()
var child42 = new Child4()
child41.reName()
console.log(child41.name, child42.name) //[ 'super4','super41' ] [ 'super4' ], 子类实例不会相互影响
console.log(child41.reName === child42.reName) //true, 共享了父类的方法
ES6 class和寄生继承实现的效果一致
class Parent5 {
constructor() {
this.name = ['super5']
}
reName() {
this.name.push('new 5')
}
}
class Child5 extends Parent5 {
constructor() {
super()
}
}
var child51 = new Child5()var child52 = new Child5()
child51.reName()
console.log(child51.name, child52.name) // [ 'super5', 'new 5' ], 子类实例不会相互影响
console.log(child51.reName === child52.reName) //true, 共享了父类的方法
2.确定原型和实例的关系
1) 通过使用instanceof
instance instanceof Object //true
instance instanceof SuperType //true
instance instanceof SubType //true
2) 通过使用isPrototypeOf()
只要是原型链中出现过的原型,都可以说是该原型链所派生的实例的原型
Object.prototype.isPrototypeOf(instance) //true
SuperType.prototype.isPrototypeOf(instance) //true
SubType.prototype.isPrototypeOf(instance) //true
3.谨慎定义方法
子类型覆盖超类型中的某个方法,或者是需要添加超类中不存在的方法,都需要将给原型添加方法的代码放在继承之后(即 替换原型的语句之后)
14、new 一个对象具体做了什么
(1)创建一个新对象;
(2)将构造函数的作用域赋给新对象(因此this就指向了这个新对象);
(3)执行构造函数中的代码(为这个新对象添加属性);
(4)返回新对象。
15、手写Ajax,XMLHttpRequest
function ajax(){
var xmlhttp;
if(window.XMLHttpRequest){
xmlhttp = new XMLHttpRequest();
}else{
// code for IE6, IE5
xmlhttp = ActionXObject("Microsoft.XMLHTTP");
}
//判定执行状态
xmlhttp.onreadystatechange = function(){
/*
readyState
0: 请求未初始化
1: 服务器连接已建立
2: 请求已接收
3: 请求处理中
4: 请求已完成,且响应已就绪
status
200:请求成功
404:未找到
500:服务器内部错误
*/
if (xmlhttp.readyState==4 && xmlhttp.status==200){
document.getElementById("myDiv").innerHTML=xmlhttp.responseText;//获得字符串形式的响应数据,如果返回的是XML需要单独解析
//responseXML 获得 XML 形式的响应数据
var xmlDoc = xmlhttp.responseXML;
var txt = "";
var num = xmlDoc.getElementsByName("value");//获取节点name=value的值
for(var i=0;i<num.length;i++){
txt = txt+num[i].childNodes[0].nodeValue+"<br />";
}
document.getElementById("myDiv2").innerHTML = txt;
}
}
//@param 最后一个参数表示是否是异步提交,为了避免使用缓存我们加上一个时间戳
xmlhttp.open("Get","url"+
(function(){
var date = new Date();
return date.getSeconds();
})
,true);
//设置头信息
xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");
//将信息发送到服务器
xmlhttp.send();
}
16、变量提升
在ES6之前,JavaScript没有块级作用域(一对花括号{}即为一个块级作用域),只有全局作用域和函数作用域。变量提升即将变量声明提升到它所在作用域的最开始的部分。上个简历的例子如:
console.log(global); // undefined |
之所以会是以上的打印结果,是由于js的变量提升,实际上上面的代码是按照以下来执行的:
var global; // 变量提升,全局作用域范围内,此时只是声明,并没有赋值 |
17、举例说明一个匿名函数的典型用例
https://blog.csdn.net/weixin_40387601/article/details/80424956
第一种:函数申明,这也是最常规的一种
function double(x){
return 2 * x;
}
第二种:这种方法使用了Function构造函数,把参数列表和函数体都作为字符串,很不方便,不建议使用。
var double = new Function('x', 'return 2 * x;');
第三种:
var double = function(x) { return 2* x; }
18、指出JS的宿主对象和原生对象的区别,为什么扩展JS内置对象不是好的做法?有哪些内置对象和内置函数?
19、document load和document DOMContentLoaded两个事件的区别
DOMContentLoaded不等图片、视频、音频等加载完
load等图片、视频、音频等加载完
最后我们来回答这个问题:我们为什么一再强调将css放在头部,将js文件放在尾部?
在面试的过程中,经常会有人在回答页面的优化中提到将js放到body标签底部,原因是因为浏览器生成Dom树的时候是一行一行读HTML代码的,script标签放在最后面就不会影响前面的页面的渲染。那么问题来了,既然Dom树完全生成好后页面才能渲染出来,浏览器又必须读完全部HTML才能生成完整的Dom树,script标签不放在body底部是不是也一样,因为dom树的生成需要整个文档解析完毕。其实现代浏览器为了更好的用户体验,渲染引擎将尝试尽快在屏幕上显示的内容。它不会等到所有HTML解析之前开始构建和布局渲染树。部分的内容将被解析并显示。也就是说浏览器能够渲染不完整的dom树和cssom,尽快的减少白屏的时间。假如我们将js放在header,js将阻塞解析dom,dom的内容会影响到First Paint,导致First Paint延后。所以说我们会将js放在后面,以减少First Paint的时间,但是不会减少DOMContentLoaded被触发的时间。
20、请指出document.onload和document.ready两个事件的区别。
页面加载完成有两种事件,一是ready,表示文档结构已经加载完成(不包含图片等非文字媒体文件),二是onload,指示页面包含图片等文件在内的所有元素都加载完成。
21、=== 和 == ,[] === [],undefined === undefined,[] == [], undefined == undefined
首先,== equality 等同,=== identity 恒等。 ==, 两边值类型不同的时候,要先进行类型转换,再比较。 ===,不做类型转换,类型不同的一定不等。
先说 ===,这个比较简单。下面的规则用来判断两个值是否===相等:
如果类型不同,就[不相等]
如果两个都是数值,并且是同一个值,那么[相等];(!例外)的是,如果其中至少一个是NaN,那么[不相等]。(判断一个值是否是NaN,只能用isNaN()来判断)
如果两个都是字符串,每个位置的字符都一样,那么[相等];否则[不相等]。
如果两个值都是true,或者都是false,那么[相等]。
如果两个值都引用同一个对象或函数,那么[相等];否则[不相等]。
如果两个值都是null,或者都是undefined,那么[相等]。
再说 ==,根据以下规则:
如果两个值类型相同,进行 === 比较。
如果两个值类型不同,他们可能相等。根据下面规则进行类型转换再比较:
如果一个是null、一个是undefined,那么[相等]。
如果一个是字符串,一个是数值,把字符串转换成数值再进行比较。
如果任一值是 true,把它转换成 1 再比较;如果任一值是 false,把它转换成 0 再比较。
如果一个是对象,另一个是数值或字符串,把对象转换成基础类型的值再比较。对象转换成基础类型,利用它的toString或者valueOf方法。js核心内置类,会尝试valueOf先于toString;例外的是Date,Date利用的是toString转换。非js核心的对象,令说(比较麻烦,我也不大懂)
任何其他组合,都[不相等]。
22、typeof能够得到哪些值
typeof运算符用来检测给定变量的数据类型,返回一个用来表示表达式的数据类型的字符串。
可能的返回值有:"number"、"string"、"boolean"、"object"、"function" 和 "undefined"。
表达式 |
返回值 |
typeof undefined |
'undefined' 如果值是undefined |
typeof null |
'object' 如果这个值是对象或者null |
typeof true |
'boolean' 如果这个值是布尔值 |
typeof 123 |
'number' 如果这个值是数字 |
typeof "abc" |
'string' 如果这个字是字符串 |
typeof function() {} |
'function' 如果这个值是函数 |
typeof {} |
'object' 如果这个值是对象或者null |
typeof [] |
'object' 如果这个值是对象或者null |
typeof unknownVariable |
'undefined' 如果这个值没有定义 |
"symbol" —— ES6引入的一种新的原始数据类型Symbol,表示独一无二的值
23什么是“use strict”,好处和坏处
消除Javascript语法的一些不合理、不严谨之处,减少一些怪异行为;
消除代码运行的一些不安全之处,保证代码运行的安全;
提高编译器效率,增加运行速度;
为未来新版本的Javascript做好铺垫。
24、函数的作用域是什么?js 的作用域有几种?
在函数内声明的所有变量在函数体内始终是可见的,可以在整个函数的范围内使用及复用,也就是说在函数体内变量声明之前就已经可用了(事实上在嵌套的作用域中也可以使用)。
块级 全局
25、JS如何实现重载和多态
重载可认为是静态的多态,静态联编,发生在编译阶段;
重载就是一组具有相同名字、不同参数列表的函数(方法)。
重载,函数特征之一,表现为在一个类中同名不同参的方法分别被调用会产生不同的结果。
js本身不支持重载,所以只能通过其他方式实现,arguments检测传参的个数,然后再执行不同的方式; 根据传参的类型,调用不同的方法,用typeof进行检测
多态是动态的,动态联编,发生在运行阶段;
多态,面向对象特征之一,表现为不同对象调用相同方法会产生不同的结果。可以理解一个方法被不同实现后 展现不同的效果及状态。
静态的比动态的效率高,但动态的最大优点是多态性,提高代码复用性。
26、常用的数组api,字符串api
27、原生事件绑定(跨浏览器),dom0和dom2的区别?
<div id="btn" onclick="clickone()"></div> //直接在DOM里绑定事件
document.getElementById("btn").onclick = function(){ alert("hello"); } //脚本里面绑定
document.getElementById("btn").addeventlistener("click",clickone,false); //通过侦听事件处理相应的函数
上边两个会造成覆盖,第三个不会。
.关于获取事件源
event.srcElement是[IE8-]唯一的方式,IE9+未知,其它浏览器都支持标准的event.target方式
关于阻止事件默认行为
event.preventDefault()是标准方法,但[IE8-]不支持,IE自己的方式是event.returnValue = false;
.关于停止事件传播
event.stopPropagation()是标准方法,IE又有意见了,他要这么玩:event.cancelBubble = true;这里需要特别注意了,因为cancel是属性而不是方法,与标准相差甚远,容易记错
DOM0级方式
ele.onclick = handler;ele.onclick=null;最古老的一种方式
优点:全浏览器兼容
缺点:同一事件只能绑定/解绑一个事件处理器
DOM2级方式
ele.add/removeEventListener(eventType, handler, catch);
和IE方式:ele.attach/detachEvent(‘on’+eventType, handler);
优点:支持绑定/解绑多个事件处理器
缺点:需要做兼容性判断。需要注意的是:标准方式中最后一个参数表示是否在事件捕获阶段绑定/解绑,IE不支持事件捕获,所以也就没有第三个参数了
注意:IE方式不仅方法名与标准不同,参数中事件类型还要加上on,否则绑定无效但不报错
给定一个元素获取它相对于视图窗口的坐标
28、如何实现图片滚动懒加载
即在页面载入的时候将页面上的img标签的src指向一个小图片,把真实地址存放在一个自定义属性中,这里我用data-src来存放然后将页面img标签获取并保存,开启一个定时器,遍历保存的img标签,判断其位置是否出现在了可视区域内。如果出现在可视区域了那么就把真实的src地址给赋值上。
并且从数组中删除,避免重复判断。我们可以获取当前img的相对于文档顶的偏移距离减去scrollTop的距离,然后和浏览器窗口高度在进行比较,如果小于浏览器窗口则出现在了可视区域内了,反之,则没有。
29、js 的字符串类型有哪些方法? 正则表达式的函数怎么使用?
30、深拷贝
31、编写一个通用的事件监听函数
32、web端cookie的设置和获取
33、setTimeout和promise的执行顺序
https://blog.csdn.net/baidu_33295233/article/details/79335127
34、JavaScript 的事件流模型都有什么?
dom0,dom2
35、navigator对象,location和history
36、js的垃圾回收机制
https://blog.csdn.net/oliver_web/article/details/53957021
37、内存泄漏的原因和场景
全局变量引起的内存泄漏
闭包引起的内存泄漏
dom清空或删除时,事件未清除导致的内存泄漏
子元素存在引用引起的内存泄漏
39、DOM事件中target和currentTarget的区别
https://www.cnblogs.com/54td/p/5936816.html
- target:触发事件的某个具体对象,只会出现在事件流的目标阶段(谁触发谁命中,所以肯定是目标阶段)
2. currentTarget:绑定事件的对象,恒等于this,可能出现在事件流的任意一个阶段中
3. 通常情况下terget和currentTarget是一致的,我们只要使用terget即可,但有一种情况必须区分这三者的关系,那就是在父子嵌套的关系中,父元素绑定了事件,单击了子元素(根据事件流,在不阻止事件流的前提下他会传递至父元素,导致父元素的事件处理函数执行),这时候currentTarget指向的是父元素,因为他是绑定事件的对象,而target指向了子元素,因为他是触发事件的那个具体对象,
40、typeof 和 instanceof 区别,instanceof原理
typeof 是一个一元运算,放在一个运算数之前,运算数可以是任意类型。
它返回值是一个字符串,该字符串说明运算数的类型。typeof 一般只能返回如下几个结果:
number,boolean,string,function,object,undefined。我们可以使用 typeof 来获取一个变量是否存在,如 if(typeof a!="undefined"){alert("ok")},而不要去使用 if(a) 因为如果 a 不存在(未声明)则会出错,对于 Array,Null 等特殊对象使用 typeof 一律返回 object,这正是 typeof 的局限性。
instance:实例,例子
a instanceof b?alert("true"):alert("false"); //a是b的实例?真:假
instanceof 用于判断一个变量是否某个对象的实例,如 var a=new Array();alert(a instanceof Array); 会返回 true,同时 alert(a instanceof Object) 也会返回 true;这是因为 Array 是 object 的子类。再如:function test(){};var a=new test();alert(a instanceof test) 会返回
谈到 instanceof 我们要多插入一个问题,就是 function 的 arguments,我们大家也许都认为 arguments 是一个 Array,但如果使用 instaceof 去测试会发现 arguments 不是一个 Array 对象,尽管看起来很像。
另外:
测试 var a=new Array();if (a instanceof Object) alert('Y');else alert('N');
得'Y’
但 if (window instanceof Object) alert('Y');else alert('N');
得'N'
所以,这里的 instanceof 测试的 object 是指 js 语法中的 object,不是指 dom 模型对象。
使用 typeof 会有些区别
alert(typeof(window)) 会得 object
40、js动画和css3动画比较
JS动画
缺点:(1)JavaScript在浏览器的主线程中运行,而主线程中还有其它需要运行的JavaScript脚本、样式计算、布局、绘制任务等,对其干扰导致线程可能出现阻塞,从而造成丢帧的情况。
(2)代码的复杂度高于CSS动画
优点:(1)JavaScript动画控制能力很强, 可以在动画播放过程中对动画进行控制:开始、暂停、回放、终止、取消都是可以做到的。
(2)动画效果比css3动画丰富,有些动画效果,比如曲线运动,冲击闪烁,视差滚动效果,只有JavaScript动画才能完成
(3)CSS3有兼容性问题,而JS大多时候没有兼容性问题
CSS动画
缺点:
(1)运行过程控制较弱,无法附加事件绑定回调函数。CSS动画只能暂停,不能在动画中寻找一个特定的时间点,不能在半路反转动画,不能变换时间尺度,不能在特定的位置添加回调函数或是绑定回放事件,无进度报告
(2)代码冗长。想用 CSS 实现稍微复杂一点动画,最后CSS代码都会变得非常笨重。
优点: (1)浏览器可以对动画进行优化。
浏览器使用与 requestAnimationFrame 类似的机制,requestAnimationFrame比起setTimeout,setInterval设置动画的优势主要是:1)requestAnimationFrame 会把每一帧中的所有DOM操作集中起来,在一次重绘或回流中就完成,并且重绘或回流的时间间隔紧紧跟随浏览器的刷新频率,一般来说,这个频率为每秒60帧。2)在隐藏或不可见的元素中requestAnimationFrame不会进行重绘或回流,这当然就意味着更少的的cpu,gpu和内存使用量。
强制使用硬件加速 (通过 GPU 来提高动画性能)
CSS动画流畅的原因
渲染线程分为main thread(主线程)和compositor thread(合成器线程)。
如果CSS动画只是改变transform和opacity,这时整个CSS动画得以在compositor thread完成(而JS动画则会在main thread执行,然后触发compositor进行下一步操作)
在JS执行一些昂贵的任务时,main thread繁忙,CSS动画由于使用了compositor thread可以保持流畅,
在主线程中,维护了一棵Layer树(LayerTreeHost),管理了TiledLayer,在compositor thread,维护了同样一颗LayerTreeHostImpl,管理了LayerImpl,这两棵树的内容是拷贝关系。因此可以彼此不干扰,当Javascript在main thread操作LayerTreeHost的同时,compositor thread可以用LayerTreeHostImpl做渲染。当Javascript繁忙导致主线程卡住时,合成到屏幕的过程也是流畅的。
为了实现防假死,鼠标键盘消息会被首先分发到compositor thread,然后再到main thread。这样,当main thread繁忙时,compositor thread还是能够响应一部分消息,例如,鼠标滚动时,加入main thread繁忙,compositor thread也会处理滚动消息,滚动已经被提交的页面部分(未被提交的部分将被刷白)。
CSS动画比JS流畅的前提:
JS在执行一些昂贵的任务
同时CSS动画不触发layout或paint
在CSS动画或JS动画触发了paint或layout时,需要main thread进行Layer树的重计算,这时CSS动画或JS动画都会阻塞后续操作。
只有如下属性的修改才符合“仅触发Composite,不触发layout或paint”:
backface-visibility
opacity
perspective
perspective-origin
transfrom
所以只有用上了3D加速或修改opacity时,css3动画的优势才会体现出来。
(2)代码相对简单,性能调优方向固定
(3)对于帧速表现不好的低版本浏览器,CSS3可以做到自然降级,而JS则需要撰写额外代码
结论
如果动画只是简单的状态切换,不需要中间过程控制,在这种情况下,css动画是优选方案。它可以让你将动画逻辑放在样式文件里面,而不会让你的页面充斥 Javascript 库。然而如果你在设计很复杂的富客户端界面或者在开发一个有着复杂UI状态的 APP。那么你应该使用js动画,这样你的动画可以保持高效,并且你的工作流也更可控。所以,在实现一些小的交互动效的时候,就多考虑考虑CSS动画。对于一些复杂控制的动画,使用javascript比较可靠。
42、JavaScript 倒计时(setTimeout)
43、js处理异常
44、js的设计模式知道那些
45、轮播图的实现,以及轮播图组件开发,轮播10000张图片过程
46、websocket的工作原理和机制。
https://www.jianshu.com/p/1ee01218097b
就变成了这样,只需要经过一次HTTP请求,就可以做到源源不断的信息传送了。(在程序设计中,这种设计叫做回调,即:你有信息了再来通知我,而不是我傻乎乎的每次跑来问你 )
这样的协议解决了上面同步有延迟,而且还非常消耗资源的这种情况。那么为什么他会解决服务器上消耗资源的问题呢?
其实我们所用的程序是要经过两层代理的,即HTTP协议在Nginx等服务器的解析下,然后再传送给相应的Handler(PHP等)来处理。简单地说,我们有一个非常快速的 接线员(Nginx) ,他负责把问题转交给相应的 客服(Handler) 。
本身接线员基本上速度是足够的,但是每次都卡在客服(Handler)了,老有客服处理速度太慢。,导致客服不够。Websocket就解决了这样一个难题,建立后,可以直接跟接线员建立持久连接,有信息的时候客服想办法通知接线员,然后接线员在统一转交给客户。
这样就可以解决客服处理速度过慢的问题了。
同时,在传统的方式上,要不断的建立,关闭HTTP协议,由于HTTP是非状态性的,每次都要重新传输 identity info (鉴别信息),来告诉服务端你是谁。
虽然接线员很快速,但是每次都要听这么一堆,效率也会有所下降的,同时还得不断把这些信息转交给客服,不但浪费客服的处理时间,而且还会在网路传输中消耗过多的流量/时间。
但是Websocket只需要一次HTTP握手,所以说整个通讯过程是建立在一次连接/状态中,也就避免了HTTP的非状态性,服务端会一直知道你的信息,直到你关闭请求,这样就解决了接线员要反复解析HTTP协议,还要查看identity info的信息。
同时由客户主动询问,转换为服务器(推送)有信息的时候就发送(当然客户端还是等主动发送信息过来的。。),没有信息的时候就交给接线员(Nginx),不需要占用本身速度就慢的客服(Handler)了
至于怎么在不支持Websocket的客户端上使用Websocket。。答案是: 不能
但是可以通过上面说的 long poll 和 ajax 轮询 来 模拟出类似的效果
47、JS代码调试-
48、响应式编程和命令式编程
函数式编程
函数式编程是一系列被不公平对待的编程思想的保护伞,它的核心思想是,它是一种将程序看成是数学方法的求值、不会改变状态、不会产生副作用(后面我们马上会谈到)的编程方式。
FP 核心思想强调:
声明式代码 —— 程序员应该关心是什么,让编译器和运行环境去关心怎样做。
明确性 —— 代码应该尽可能的明显。尤其是要隔离副作用避免意外。要明确定义数据流和错误处理,要避免 GOTO 语句和 异常,因为它们会将应用置于意外的状态。
并发 —— 因为纯函数的概念,大多数函数式代码默认都是并行的。由于CPU运行速度没有像以前那样逐年加快((详见 摩尔定律)), 普遍看来这个特点导致函数式编程渐受欢迎。以及我们也必须利用多核架构的优点,让代码尽量的可并行。
高阶函数 —— 函数和其他的语言基本元素一样是一等公民。你可以像使用 string 和 int 一样的去传递函数。
不变性 —— 变量一经初始化将不能修改。一经创建,永不改变。如果需要改变,需要创建新的。这是明确性和避免副作用之外的另一方面。如果你知道一个变量不能改变,当你使用时会对它的状态更有信心。
函数式编程:JS、Scala、Erlang
响应式编程
响应式系统具备如下特点:
响应性 —— 一个系统应该总是能够及时响应用户请求,并且保持很低的延迟。
弹性 —— 一个系统即使在部分组件开始出现故障的情况下也应该能够作出响应,将停机时间将至最低
可伸缩性 —— 一个系统在负载增加时应该能够根据需求增加资源以确保响应性,但同时也应该能在负载降低时减少资源,保持高效的资源利用率。
消息驱动 —— 在一个系统的不同部分之间传递消息,Ledbrook认为这是响应式系统的一个必备特点。
响应式实际上是观察者模式加上事件源的完成通知能力、错误传播能力和监听者同事件源通信的能力。
响应式流是一种规范,ReactiveX是一种常用的跨平台实现。
下面三个重要的概念是响应式流API的构建基础:
发布者是事件的发送方,可以向它订阅。
订阅者是事件订阅方。
订阅将发布者和订阅者联系起来,使订阅者可以向发布者发送信号。
响应式编程是一种基于异步数据流概念的编程模式。数据流就像一条河:它可以被观测,被过滤,被操作,或者为新的消费者与另外一条流合并为一条新的流。
响应式编程的一个关键概念是事件。事件可以被等待,可以触发过程,也可以触发其它事件。事件是唯一的以合适的方式将我们的现实世界映射到我们的软件中:如果屋里太热了我们就打开一扇窗户。同样的,当我们更改电子表(变化的传播)中的一些数值时,我们需要更新整个表格或者我们的机器人碰到墙时会转弯(响应事件)。
今天,响应式编程最通用的一个场景是UI:我们的移动App必须做出对网络调用、用户触摸输入和系统弹框的响应。在这个世界上,软件之所以是事件驱动并响应的是因为现实生活也是如此。
响应式编程的具体实现-RxJava。RxJava提供了一种以面向时序的方式考虑数据的机会:所有事情都是持续变化的,数据在更新,事件在触发,然后你就可以创建事件响应式的、灵活的、运行流畅的App。
49、手指点击可以触控的屏幕时,是什么事件? 什么是函数柯里化?以及说一下JS的API有哪些应用到了函数柯里化的实现?(函数柯里化一些了解,以及在函数式编程的应用,- 最后说了一下JS中bind函数和数组的reduce方法用到了函数柯里化。)
柯里化通常也称部分求值,其含义是给函数分步传递参数,每次传递参数后部分应用参数,并返回一个更具体的函数接受剩下的参数,这中间可嵌套多层这样的接受部分参数函数,直至返回最后结果。
提高适用性
延迟执行
固定易变因素(bind)
// add 函数柯里化
function add(){
//建立args,利用闭包特性,不断保存arguments
var args = [].slice.call(arguments);
//方法一,新建_add函数实现柯里化
var _add = function(){
if(arguments.length === 0){
//参数为空,对args执行加法
return args.reduce(function(a,b){
return a+b});
}else {
//否则,保存参数到args,返回一个函数
[].push.apply(args,arguments);
return _add;
}
}
//返回_add函数 return _add;
// //方法二,使用arguments.callee实现柯里化
// return function () {
// if (arguments.length === 0) {
// return args.reduce(function(a,b){return a+b});
// }
// Array.prototype.push.apply(args, arguments); // return arguments.callee; // } } console.log(add(1,2,3)(1)(2)(3)(4,5,6)(7,8)());//42
实现的原理主要是:
闭包保存args变量,存储之前的参数
新建一个_add函数,参数的长度为0,就执行加法,否则,存储参数到args,然后返回函数自身(可以选择匿名函数,返回arguments.callee即可,意思相同,见代码中注释掉的部分,但是在严格模式下不能使用,所以还是使用方法一比较稳妥)。
49、escape,encodeURI,encodeURIComponent
escape()函数用于js对字符串进行编码,不常用。
encodeURI()用于整个url编码
encodeURIComponent() 用于参数的传递,参数包含特殊字符可能会造成间断。
50、js事件循环
检查Macrotask 队列是否为空,若不为空,则进行下一步,若为空,则跳到3
从Macrotask队列中取队首(在队列时间最长)的任务进去执行栈中执行(仅仅一个),执行完后进入下一步
检查Microtask队列是否为空,若不为空,则进入下一步,否则,跳到1(开始新的事件循环)
从Microtask队列中取队首(在队列时间最长)的任务进去事件队列执行,执行完后,跳到3
macro-task包括:script(整体代码), setTimeout, setInterval, setImmediate, I/O, UI rendering。
micro-task包括:process.nextTick, Promises, Object.observe, MutationObserver
执行顺序:函数调用栈清空只剩全局执行上下文,然后开始执行所有的micro-task。当所有可执行的micro-task执行完毕之后。循环再次执行macro-task中的一个任务队列,执行完之后再执行所有的micro-task,就这样一直循环。
四.ES6
1、谈一谈 promise
2、所有的 ES6 特性你都知道吗?如果遇到一个东西不知道是 ES6 还是 ES5, 你该怎么区分它
3、es6的继承和es5的继承有什么区别
4、promise封装ajax
5、let const的优点
6、es6 generator 是什么,async/await 实现原理
都是一步函数的同步表达
Generator 函数总是返回一个遍历器,ES6 规定这个遍历器是 Generator 函数的实例,也继承了 Generator 函数的prototype对象上的方法。
* yeild
一旦遇到yield命令,就会暂时退出堆栈,但是并不消失,里面的所有变量和对象会冻结在当前状态。等到对它执行next命令时,这个上下文环境又会重新加入调用栈,冻结的变量和对象恢复执行。
async用来申明里面包裹的内容可以进行同步的方式执行,await则是进行执行顺序控制,每次执行一个await,程序都会暂停等待await返回值,然后再执行之后的await。
await后面调用的函数需要返回一个promise,另外这个函数是一个普通的函数即可,而不是generator。
await只能用在async函数之中,用在普通函数中会报错。
await命令后面的 Promise 对象,运行结果可能是 rejected,所以最好把 await 命令放在 try...catch 代码块中。
其实,async / await的用法和co差不多,await和yield都是表示暂停,外面包裹一层async 或者 co来表示里面的代码可以采用同步的方式进行处理。不过async / await里面的await后面跟着的函数不需要额外处理,co是需要将它写成一个generator的。
7、ES6和node的commonjs模块化规范区别
es6 {
export : '可以输出多个,输出方式为 {}' ,
export default : ' 只能输出一个 ,可以与export 同时输出,但是不建议这么做',
解析阶段确定对外输出的接口,解析阶段生成接口,
模块不是对象,加载的不是对象,
可以单独加载其中的某个接口(方法),
静态分析,动态引用,输出的是值的引用,值改变,引用也改变,即原来模块中的值改变则该加载的值也改变,
this 指向undefined
}
commonJS {
module.exports = ... : '只能输出一个,且后面的会覆盖上面的' ,
exports. ... : ' 可以输出多个',
运行阶段确定接口,运行时才会加载模块,
模块是对象,加载的是该对象,
加载的是整个模块,即将所有的接口全部加载进来,
输出是值的拷贝,即原来模块中的值改变不会影响已经加载的该值,
this 指向当前模块
}
8、箭头函数,以及它的this,和普通函数的this有什么区别
ES6的箭头函数的this指向是,在哪里定义的箭头函数那么它的this就指向哪里。
而ES5普通函数的this指向是,在哪里调用的函数,那么this就指向哪里。
其实箭头函数里是没有this的,而普通函数的是有this的。
但是普通函数在定义的时候并不知道自己的this要指向哪里,所以在被调用的时候普通函数里的this会指向调用它的那个对象。
而箭头函数因为本身没有this,它会直接绑定到它的词法作用域内的this,也就是定义它时的作用域内的this值。
var name='window';
var obj = {
name:'obj',
nameprintf:function(){
console.log(this.name)
}
}
obj.nameprintf();//'obj'
var w = obj.nameprintf;
w();//'window'
五.计算机网络
HTTPS和HTTP的区别主要如下:
1、https协议需要到ca申请证书,一般免费证书较少,因而需要一定费用。
2、http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议。
3、http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
4、http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。
以下是具体一些分析
一、HTTP和HTTPS的基本概念
HTTP:是互联网上应用最为广泛的一种网络协议,是一个客户端和服务器端请求和应答的标准(TCP),用于从WWW服务器传输超文本到本地浏览器的传输协议,它可以使浏览器更加高效,使网络传输减少。
HTTPS:是以安全为目标的HTTP通道,简单讲是HTTP的安全版,即HTTP下加入SSL层,HTTPS的安全基础是SSL,因此加密的详细内容就需要SSL。
HTTPS协议的主要作用可以分为两种:一种是建立一个信息安全通道,来保证数据传输的安全;另一种就是确认网站的真实性。
二 、HTTP和HTTPS的主要特点和工作流程
HTTP特点
1.支持客户/服务器模式。(C/S模式)
2.简单快速:客户向服务器请求服务时,只需传送请求方法和路径。请求方法常用的有GET、HEAD、POST。每种方法规定了客户与服务器联系的类型不同。由于HTTP协议简单,使得HTTP服务器的程序规模小,因而通信速度很快。
3.灵活:HTTP允许传输任意类型的数据对象。正在传输的类型由Content-Type加以标记。
4.无连接:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。
5.无状态:HTTP协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快
HTTP工作流程
第一步:建立TCP/IP连接,客户端与服务器通过Socket三次握手进行连接
第二步:客户端向服务端发起HTTP请求(例如:POST/login.html http/1.1)
第三步:客户端发送请求头信息,请求内容,最后会发送一空白行,标示客户端请求完毕
第四步:服务器做出应答,表示对于客户端请求的应答,例如:HTTP/1.1 200 OK
第五步:服务器向客户端发送应答头信息
第六步:服务器向客户端发送请求头信息后,也会发送一空白行,标示应答头信息发送完毕,接着就以Content-type要求的数据格式发送数据给客户端
第七步:服务端关闭TCP连接,如果服务器或者客户端增Connection:keep-alive就表示客户端与服务器端继续保存连接,在下次请求时可以继续使用这次的连接
HTTPS特点
HTTPS是HTTP协议的修改,它加密数据并确保其机密性。其配置可保护用户在与网站交互时免于窃取个人信息和计费数据。
1、优点
相比于http,https可以提供更加优质保密的信息,保证了用户数据的安全性,此外https同时也一定程度上保护了服务端,使用恶意攻击和伪装数据的成本大大提高。
2、缺点
缺点也同样很明显,第一https的技术门槛较高,多数个人或者私人网站难以支撑,CA机构颁发的证书都是需要年费的,此外对接Https协议也需要额外的技术支持;其二,目前来说大多数网站并不关心数据的安全性和保密性,其https最大的优点对它来说并不适用;其三,https加重了服务端的负担,相比于http其需要更多的资源来支撑,同时也降低了用户的访问速度;第四,目前来说Http网站仍然大规模使用,在浏览器侧也没有特别大的差别,很多用户不关心的话根
第一步:客户使用https的URL访问Web服务器,要求与Web服务器建立SSL连接。
第二步:Web服务器收到客户端请求后,会将网站的证书信息(证书中包含公钥)传送一份给客户端。
第三步:客户端的浏览器与Web服务器开始协商SSL连接的安全等级,也就是信息加密的等级。
第四步:客户端的浏览器根据双方同意的安全等级,建立会话密钥,然后利用网站的公钥将会话密钥加密,并传送给网站。
第五步:Web服务器利用自己的私钥解密出会话密钥。
第六步:Web服务器利用会话密钥加密与客户端之间的通信。
最后说一句 ,ssl证书阿里云上可以免费申请一年
1、HTTP协议头含有哪些重要的部分,HTTP状态码
2、网络url输入到输出怎么做?
3、性能优化为什么要减少 HTTP 访问次数?
4、Http请求的过程与原理
5、https(对是https)有几次握手和挥手?https的原理。
6、http有几次挥手和握手?TLS的中文名?TLS在哪一网络层?
三次握手:
1、建立连接时,客户端发送SYN包(SYN=i)到服务器,并进入到SYN-SEND状态,等待服务器确认
2、服务器收到SYN包,必须确认客户的SYN(ack=i+1),同时自己也发送一个SYN包(SYN=k),即SYN+ACK包,此时服务器进入SYN-RECV状态
3、客户端收到服务器的SYN+ACK包,向服务器发送确认报ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手,客户端与服务器开始传送数据。
SYN攻击就是Client在短时间内伪造大量不存在的IP地址,并向Server不断地发送SYN包,Server回复确认包,并等待Client的确认,由于源地址是不存在的,因此,Server需要不断重发直至超时,这些伪造的SYN包将产时间占用未连接队列,导致正常的SYN请求因为队列满而被丢弃,从而引起网络堵塞甚至系统瘫痪。SYN攻击时一种典型的DDOS攻击,检测SYN攻击的方式非常简单,即当Server上有大量半连接状态且源IP地址是随机的,则可以断定遭到SYN攻击了,使用如下命令可以让之现行:
#netstat -nap | grep SYN_RECV
四次挥手:
(1)第一次挥手:Client发送一个FIN,用来关闭Client到Server的数据传送,Client进入FIN_WAIT_1状态。
(2)第二次挥手:Server收到FIN后,发送一个ACK给Client,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序号),Server进入CLOSE_WAIT状态。
(3)第三次挥手:Server发送一个FIN,用来关闭Server到Client的数据传送,Server进入LAST_ACK状态。
(4)第四次挥手:Client收到FIN后,Client进入TIME_WAIT状态,接着发送一个ACK给Server,确认序号为收到序号+1,Server进入CLOSED状态,完成四次挥手。
TLS为安全传输层协议,所以属于传输层
7、TCP连接的特点,TCP连接如何保证安全可靠的?
8、为什么TCP连接需要三次握手,两次不可以吗,为什么
9、为什么tcp要三次握手四次挥手?
这是因为服务端在LISTEN状态下,收到建立连接请求的SYN报文后,把ACK和SYN放在一个报文里发送给客户端。而关闭连接时,当收到对方的FIN报文时,仅仅表示对方不再发送数据了但是还能接收数据,己方也未必全部数据都发送给对方了,所以己方可以立即close,也可以发送一些数据给对方后,再发送FIN报文给对方来表示同意现在关闭连接,因此,己方ACK和FIN一般都会分开发送。
10、tcp的三次握手和四次挥手画图(当场画写ack 和 seq的值)?
11、tcp与udp的区别
12、get和post的区别?什么情况下用到?
13、http2 与http1 的区别?
14、什么是tcp流,什么是http流
15、有没有自己写过webpack的loader,他的原理
loader本质就是接收字符串(或者buffer),再返回处理完的字符串(或者buffer)的过程。webpack会将加载的资源作为参数传入loader方法,交于loader处理,再返回。
const fs = require('fs')
const path = require('path')
const loaderUtils = require('loader-utils')
const defaultOptions = {
placeholder: '{{__content__}}',
decorator: 'layout'
}
const render = (layoutPath, placeholder, source) => {
try {
var layoutHtml = fs.readFileSync(layoutPath, 'utf-8')
} catch (error) {
throw error
}
return layoutHtml.replace(placeholder, source)
}
module.exports = function (source) {
this.cacheable && this.cacheable()
const options = Object.assign(loaderUtils.getOptions(this), defaultOptions)
const { placeholder, decorator, layout } = options
const reg = new RegExp(`(@${decorator}\\()(.*?)\\)`)
const regResult = reg.exec(source)
var callback = this.async()
if (regResult) {
const request = loaderUtils.urlToRequest(regResult[2])
this.resolve('/', request, (err, rs) => {
if (err) {
rs = path.resolve(this.resourcePath, '../', request)
}
source = source.replace(regResult[0], '')
callback(null, render(rs, placeholder, source))
})
} else if (layout) {
callback(null, render(layout, placeholder, source))
} else {
callback(null, source)
}
}
15、babel是如何将es6代码编译成es5的
Babel工作分为三个阶段:
1.解析:将代码字符串解析成抽象语法树
2.变换:将抽象语法树
3.再建:根据变换后的抽象语法树再生成代码字符串
ES6代码输入 ==》 babylon进行解析 ==》 得到AST
==》 plugin用babel-traverse对AST树进行遍历转译 ==》 得到新的AST树
==》 用babel-generator通过AST树生成ES5代码
16、http2的持久连接和管线化
17、域名解析时是tcp还是udp
18、域名发散和域名收敛
19、Post一个file的时候file放在哪的?
20、HTTP Response的Header里面都有些啥?
六.浏览器相关
1、跨域,为什么JS会对跨域做出限制
2、前端安全:xss,csrf
XSS全称跨站脚本攻击(Cross Site Scripting),顾名思义,就是通过向某网站写入js脚本来实现攻击。
1、在url上注入
2、注入js脚本
防范
1. 过滤用户输入
2. 对不可信输出编码
3. 安全Cookie
4. 提高防范意识、多测试
CSRF全称跨站请求伪造(Cross-site request forgery)
1、 通过GET请求
2. 通过XSS
防御
1.规范请求类型。
2.检查Referer 即检查请求头中的来源网站,从而保证此次请求来源于信任的网站
3.设置请求Token
4.防住第一道防线-XSS 再次强调,如果cookie被别人拿走,任何防御都将在理论上失效。上述的防御手段仅仅是提高攻击门槛。有了你的cookie,我可以直接请求你的页面,获取你的token,获取你的验证码图片并解析出来,然后再发起请求。而服务器还以为这是你本人。
3、浏览器怎么加载页面的?script脚本阻塞有什么解决方法?defer和async的区别?
async是异步下载并立即执行,然后文档继续解析,defer是异步加载后解析文档,然后再执行脚本,这样说起来是不是理解了一点了;
它们的核心功能就是异步,那么两种属性怎么去区分什么情况下用哪个那,主要的参考是如果脚本不依赖于任何脚本,并不被任何脚本依赖,那么则使用 defer,如果脚本是模块化的,不依赖于任何脚本,那么则使用 async;
5、浏览器的全局变量有哪些
6、浏览器同一时间能够从一个域名下载多少资源
7、按需加载,不同页面的元素判断标准
8、web存储、session、cookies、localstroge、sessionStory等的使用和区别
cookie和session
cookie保存在浏览器端,session保存在服务器端
cookie数据始终在同源的http请求中携带(即使不需要),即cookie在浏览器和服务器间来回传递。而sessionStorage和localStorage不会自动把数据发给服务器,仅在本地保存。cookie数据还有路径(path)的概念,可以限制cookie只属于某个路径下。存储大小限制也不同,cookie数据不能超过4k,同时因为每次http请求都会携带cookie,所以cookie只适合保存很小的数据,如会话标识。sessionStorage和localStorage 虽然也有存储大小的限制,但比cookie大得多,可以达到5M或更大。数据有效期不同,sessionStorage:仅在当前浏览器窗口关闭前有效,自然也就不可能持久保持;localStorage:始终有效,窗口或浏览器关闭也一直保存,因此用作持久数据;cookie只在设置的cookie过期时间之前一直有效,即使窗口或浏览器关闭。作用域不同,sessionStorage不在不同的浏览器窗口中共享,即使是同一个页面;localStorage 在所有同源窗口中都是共享的;cookie也是在所有同源窗口中都是共享的。Web Storage 支持事件通知机制,可以将数据更新的通知发送给监听者。Web Storage 的 api 接口使用更方便。
9、浏览器的内核
10、如何实现缓存机制?(从200缓存,到cache到etag再到)
20、http相关 状态码,说一下200和304的理解和区别 浏览器强缓存和协商缓存
HTTP是无连接:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。
HTTP是媒体独立的:这意味着,只要客户端和服务器知道如何处理的数据内容,任何类型的数据都可以通过HTTP发送。客户端以及服务器指定使用适合的MIME-type内容类型。
HTTP是无状态:HTTP协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快。
分类 |
分类描述 |
1** |
信息,服务器收到请求,需要请求者继续执行操作 |
2** |
成功,操作被成功接收并处理 |
3** |
重定向,需要进一步的操作以完成请求 |
4** |
客户端错误,请求包含语法错误或无法完成请求 |
5** |
服务器错误,服务器在处理请求的过程中发生了错误 |
HTTP状态码列表 |
||
状态码 |
状态码英文名称 |
中文描述 |
100 |
Continue |
继续。客户端应继续其请求 |
101 |
Switching Protocols |
切换协议。服务器根据客户端的请求切换协议。只能切换到更高级的协议,例如,切换到HTTP的新版本协议 |
|
||
200 |
OK |
请求成功。一般用于GET与POST请求 |
201 |
Created |
已创建。成功请求并创建了新的资源 |
202 |
Accepted |
已接受。已经接受请求,但未处理完成 |
203 |
Non-Authoritative Information |
非授权信息。请求成功。但返回的meta信息不在原始的服务器,而是一个副本 |
204 |
No Content |
无内容。服务器成功处理,但未返回内容。在未更新网页的情况下,可确保浏览器继续显示当前文档 |
205 |
Reset Content |
重置内容。服务器处理成功,用户终端(例如:浏览器)应重置文档视图。可通过此返回码清除浏览器的表单域 |
206 |
Partial Content |
部分内容。服务器成功处理了部分GET请求 |
|
||
300 |
Multiple Choices |
多种选择。请求的资源可包括多个位置,相应可返回一个资源特征与地址的列表用于用户终端(例如:浏览器)选择 |
301 |
Moved Permanently |
永久移动。请求的资源已被永久的移动到新URI,返回信息会包括新的URI,浏览器会自动定向到新URI。今后任何新的请求都应使用新的URI代替 |
302 |
Found |
临时移动。与301类似。但资源只是临时被移动。客户端应继续使用原有URI |
303 |
See Other |
查看其它地址。与301类似。使用GET和POST请求查看 |
304 |
Not Modified |
未修改。所请求的资源未修改,服务器返回此状态码时,不会返回任何资源。客户端通常会缓存访问过的资源,通过提供一个头信息指出客户端希望只返回在指定日期之后修改的资源 |
305 |
Use Proxy |
使用代理。所请求的资源必须通过代理访问 |
306 |
Unused |
已经被废弃的HTTP状态码 |
307 |
Temporary Redirect |
临时重定向。与302类似。使用GET请求重定向 |
|
||
400 |
Bad Request |
客户端请求的语法错误,服务器无法理解 |
401 |
Unauthorized |
请求要求用户的身份认证 |
402 |
Payment Required |
保留,将来使用 |
403 |
Forbidden |
服务器理解请求客户端的请求,但是拒绝执行此请求 |
404 |
Not Found |
服务器无法根据客户端的请求找到资源(网页)。通过此代码,网站设计人员可设置"您所请求的资源无法找到"的个性页面 |
405 |
Method Not Allowed |
客户端请求中的方法被禁止 |
406 |
Not Acceptable |
服务器无法根据客户端请求的内容特性完成请求 |
407 |
Proxy Authentication Required |
请求要求代理的身份认证,与401类似,但请求者应当使用代理进行授权 |
408 |
Request Time-out |
服务器等待客户端发送的请求时间过长,超时 |
409 |
Conflict |
服务器完成客户端的PUT请求是可能返回此代码,服务器处理请求时发生了冲突 |
410 |
Gone |
客户端请求的资源已经不存在。410不同于404,如果资源以前有现在被永久删除了可使用410代码,网站设计人员可通过301代码指定资源的新位置 |
411 |
Length Required |
服务器无法处理客户端发送的不带Content-Length的请求信息 |
412 |
Precondition Failed |
客户端请求信息的先决条件错误 |
413 |
Request Entity Too Large |
由于请求的实体过大,服务器无法处理,因此拒绝请求。为防止客户端的连续请求,服务器可能会关闭连接。如果只是服务器暂时无法处理,则会包含一个Retry-After的响应信息 |
414 |
Request-URI Too Large |
请求的URI过长(URI通常为网址),服务器无法处理 |
415 |
Unsupported Media Type |
服务器无法处理请求附带的媒体格式 |
416 |
Requested range not satisfiable |
客户端请求的范围无效 |
417 |
Expectation Failed |
服务器无法满足Expect的请求头信息 |
|
||
500 |
Internal Server Error |
服务器内部错误,无法完成请求 |
501 |
Not Implemented |
服务器不支持请求的功能,无法完成请求 |
502 |
Bad Gateway |
充当网关或代理的服务器,从远端服务器接收到了一个无效的请求 |
503 |
Service Unavailable |
由于超载或系统维护,服务器暂时的无法处理客户端的请求。延时的长度可包含在服务器的Retry-After头信息中 |
504 |
Gateway Time-out |
充当网关或代理的服务器,未及时从远端服务器获取请求 |
505 |
HTTP Version not supported |
服务器不 |
当浏览器第一次加载资源的时候,返回一般为200,意思是成功获取资源,并会在浏览器的缓存中记录下max-age,第二次访问的时候: 如果只是用浏览器打开,那么浏览器会去判断这个资源在缓存里有没有,如果有的话,会去判断max-age,看看过期没有,如果没有过期,则直接读缓存,根本不会和服务器进行交互,换句话说,断网都能打开,就和本地跑一样!如果已经过期了,那就去服务器请求,等待服务器响应,这是很费时间的,服务器如果发现资源没有改变过,那么就会返回304,告诉浏览器,我没变过,你去读缓存吧,于是浏览器也不用从服务器拉数据了
1.强缓存:不会向服务器发送请求,直接从缓存中读取资源,在chrome控制台的network选项中可以看到该请求返回200的状态码;
强制缓存
Expires:response header里的过期时间,浏览器再次加载资源时,如果在这个过期时间内,则命中强缓存。
Cache-Control:当值设为max-age=300时,则代表在这个请求正确返回时间(浏览器也会记录下来)的5分钟内再次加载资源,就会命中强缓存。
cache-control除了该字段外,还有下面几个比较常用的设置值:
-no-cache:不使用本地缓存。需要使用缓存协商,先与服务器确认返回的响应是否被更改,如果之前的响应中存在ETag,那么请求的时候会与服务端验证,如果资源未被更改,则可以避免重新下载。
-no-store:直接禁止浏览器缓存数据,每次用户请求该资源,都会向服务器发送一个请求,每次都会下载完整的资源。
-public:可以被所有的用户缓存,包括终端用户和CDN等中间代理服务器。
-private:只能被终端用户的浏览器缓存,不允许CDN等中继缓存服务器对其缓存。
2.协商缓存:向服务器发送请求,服务器会根据这个请求的request header的一些参数来判断是否命中协商缓存,如果命中,则返回304状态码并带上新的response header通知浏览器从缓存中读取资源;
协商缓存
Last-Modify/If-Modify-Since:浏览器第一次请求一个资源的时候,服务器返回的header中会加上Last-Modify,Last-modify是一个时间标识该资源的最后修改时间;当浏览器再次请求该资源时,request的请求头中会包含If-Modify-Since,该值为缓存之前返回的Last-Modify。服务器收到If-Modify-Since后,根据资源的最后修改时间判断是否命中缓存
Etag:web服务器响应请求时,告诉浏览器当前资源在服务器的唯一标识(生成规则由服务器决定)。
If-None-Match:当资源过期时(使用Cache-Control标识的max-age),发现资源具有Etage声明,则再次向web服务器请求时带上头If-None-Match (Etag的值)。web服务器收到请求后发现有头If-None-Match 则与被请求资源的相应校验串进行比对,决定是否命中协商缓存;
ETag和Last-Modified的作用和用法,他们的区别:
1.Etag要优于Last-Modified。Last-Modified的时间单位是秒,如果某个文件在1秒内改变了多次,那么他们的Last-Modified其实并没有体现出来修改,但是Etag每次都会改变确保了精度;
2.在性能上,Etag要逊于Last-Modified,毕竟Last-Modified只需要记录时间,而Etag需要服务器通过算法来计算出一个hash值;
3.在优先级上,服务器校验优先考虑Etag。
浏览器缓存过程
1.浏览器第一次加载资源,服务器返回200,浏览器将资源文件从服务器上请求下载下来,并把response header及该请求的返回时间一并缓存;
2.下一次加载资源时,先比较当前时间和上一次返回200时的时间差,如果没有超过cache-control设置的max-age,则没有过期,命中强缓存,不发请求直接从本地缓存读取该文件(如果浏览器不支持HTTP1.1,则用expires判断是否过期);如果时间过期,则向服务器发送header带有If-None-Match和If-Modified-Since的请求
3.服务器收到请求后,优先根据Etag的值判断被请求的文件有没有做修改,Etag值一致则没有修改,命中协商缓存,返回304;如果不一致则有改动,直接返回新的资源文件带上新的Etag值并返回200;;
4.如果服务器收到的请求没有Etag值,则将If-Modified-Since和被请求文件的最后修改时间做比对,一致则命中协商缓存,返回304;不一致则返回新的last-modified和文件并返回200;;
这个主要涉及到两组header字段:Etag和If-None-Match、Last-Modified和If-Modified-Since。上面以及说得很清楚这两组怎么使用啦~复习一下:
Etag和If-None-Match
Etag/If-None-Match返回的是一个校验码。ETag可以保证每一个资源是唯一的,资源变化都会导致ETag变化。服务器根据浏览器上送的If-None-Match值来判断是否命中缓存。
与Last-Modified不一样的是,当服务器返回304 Not Modified的响应时,由于ETag重新生成过,response header中还会把这个ETag返回,即使这个ETag跟之前的没有变化。
Last-Modify/If-Modify-Since
浏览器第一次请求一个资源的时候,服务器返回的header中会加上Last-Modify,Last-modify是一个时间标识该资源的最后修改时间,例如Last-Modify: Thu,31 Dec 2037 23:59:59 GMT。
当浏览器再次请求该资源时,request的请求头中会包含If-Modify-Since,该值为缓存之前返回的Last-Modify。服务器收到If-Modify-Since后,根据资源的最后修改时间判断是否命中缓存。
如果命中缓存,则返回304,并且不会返回资源内容,并且不会返回Last-Modify。
为什么要有Etag
你可能会觉得使用Last-Modified已经足以让浏览器知道本地的缓存副本是否足够新,为什么还需要Etag呢?HTTP1.1中Etag的出现主要是为了解决几个Last-Modified比较难解决的问题:
一些文件也许会周期性的更改,但是他的内容并不改变(仅仅改变的修改时间),这个时候我们并不希望客户端认为这个文件被修改了,而重新GET;
某些文件修改非常频繁,比如在秒以下的时间内进行修改,(比方说1s内修改了N次),If-Modified-Since能检查到的粒度是s级的,这种修改无法判断(或者说UNIX记录MTIME只能精确到秒);
某些服务器不能精确的得到文件的最后修改时间。
Last-Modified与ETag是可以一起使用的,服务器会优先验证ETag,一致的情况下,才会继续比对Last-Modified,最后才决定是否返回304。
3.常见问题
用户行为对浏览器缓存的影响
4.解决方案
点击刷新按钮或者按F5
浏览器直接对本地的缓存文件过期,但是会带上If-Modifed-Since,If-None-Match,这就意味着服务器会对文件检查新鲜度,返回结果可能是304,也有可能是200.
用户按Ctrl+F5(强制刷新)
浏览器不仅会对本地文件过期,而且不会带上 If-Modifed-Since,If-None-Match,相当于之前从来没有请求过,返回结果是200.
地址栏回车
浏览器发起请求,按照正常流程,本地检查是否过期,然后服务器检查新鲜度,最后返回内容。
21、什么是预加载、懒加载
22、一个 XMLHttpRequest 实例有多少种状态?
23、dns解析原理,输入网址后如何查找服务器
24、服务器如何知道你?
25、浏览器渲染过程
26、ie的某些兼容性问题
28、拖拽实现
29、拆解url的各部分-
30、从输入 URL 到页面展现中间发生了什么?
DNS 查询 DNS 缓存
建立 TCP 连接(三次握手)连接复用
发送 HTTP 请求(请求的四部分)
后台处理请求
监听 80 端口
路由
渲染 HTML 模板
生成响应
发送 HTTP 响应
关闭 TCP 连接(四次挥手)
解析 HTML
下载 CSS(缓存)
解析 CSS
下载 JS(缓存)
解析 JS
下载图片
解析图片
渲染 DOM 树
渲染样式树
执行 JS
七.工程化
1、对webpack,gulp,grunt等有没有了解?对比。
2、webpack的入口文件怎么配置,多个入口怎么分割。
3、webpack的loader和plugins的区别
4、gulp的具体使用。
5.前端工程化的理解、如何自己实现一个文件打包,比如一个JS文件里同时又ES5 和ES6写的代码,如何编译兼容他们
八.模块化
1、对AMD,CMD,CommonJS有没有了解?
(1)CMD Sea.js 在推广过程中对模块定义的规范化产出物 是淘宝团队提供的
define(function(require,exports,module){...});
以来就近,那个地方用到 就在哪个地方require 同步的概念
(2)AMD requriejs在推广过程中对模块定义的规范化产出物
define(
[module-name?] /*可选*/, 模块标识,可以省略。如果没有这个属性,则称为匿名模块。
[array-of-dependencies?] /*可选*/, 所依赖的模块,可以省略 [module-factory-or-object]模块的实现,或者一个JavaScript对象。 );
以来前置,用数组定义引用
// foo,bar为外部模块,加载以后的输出作为回调函数的参数传入,以便访问
requrie(["foo", "bar"], function (foo, bar) {
// 其他代码
foo.doSomething();
});
(3)CommonJS nodejs服务端里用的
CommonJS模块由两部分组成:变量exports和require函数
modele.export ==> export default
export.area ==> export
(4)es6特性 export/import
2、为什么要模块化?不用的时候和用RequireJs的时候代码大概怎么写?
3、说说有哪些模块化的库,有了解过模块化的发展的历史吗?
4、分别说说同步和异步模块化的应用场景,说下AMD异步模块化实现的原理?
5、如何将项目里面的所有的require的模块语法换成import的ES6的语法?
6、使用模块化加载时,模块加载的顺序是怎样的,如果不知道,根据已有的知识,你觉得顺序应该是怎么样的?
九.框架
1、使用过哪些框架?
7、请指出$和$.fn的区别,或者说出$.fn的用途。
1.那么这两个分别是什么意思?
$.extend(obj);是为了扩展jquery本身,为类添加新的方法。
$.fn.extend(obj);给JQUERY对象添加方法。
2.$.fn中的fn是什么意思,其实是prototype,即$.fn=$.prototype;
$.extend({
add:function(a, b) {
return a+b;
}
})
$.add(5,8); // return 13
注意没有,这边的调用直接调用,前面不用任何对象。直接$.+方法名
$.fn.extend(obj);对prototype进行扩展,为jquery类添加成员函数,jquery类的实例可以使用这个成员函数。
$.fn.extend({
clickwhile:function(){
$(this).click(function(){
alert($(this).val())
})
}
})
$('input').clickwhile(); // 当点击输入框会弹出该对象的Value值
注意调用时候前面是有对象的。即$('input')这么个东西。
2、zepto 和 jquery 是什么关系,有什么联系么?
3、jquery源码如何实现选择器的,为什么$取得的对象要设计成数组的形式,这样设计的目的是什么
4、jquery如何绑定事件,有几种类型和区别
5、什么是MVVM,MVC,MVP
6、Vue和Angular的双向数据绑定原理
7、Vue,Angular组件间通信以及路由原理
8、React中调用setState之后发生了什么事情?
React会将当前传入的参数对象与组件当前的状态合并,然后触发调和过程,在调和的过程中,React会以相对高效的方式根据新的状态构建React元素树并且重新渲染整个UI界面.
React得到的元素树之后,React会自动计算出新的树与老的树的节点的差异,然后根据差异对界面进行最小化的渲染,在React的差异算法中,React能够精确的知道在哪些位置发生看改变以及应该如何去改变,这样就保证了UI是按需更新的而不是重新渲染整个界面.
9、React中的refs属性的作用是什么?
Refs是React提供给我们安全的访问DOM元素或者某个组件实例的句柄,我们可以为元素添加ref属性然后在回调函数中接收该元素在DOM树中的句柄,该值会作为回调函数的第一个参数的返回.
10、React中keys的作用是什么?
Keys 是React在操作列表中元素被修改,添加,或者删除的辅助标识
componentWillReceiveProps和componentWillUpdate 的区别
componentWillReceiveProps 在组件接收到一个新的 prop (更新后)时被调用。这个方法在初始化render时不会被调用。
componentWillUpdate在组件接收到新的props或者state但还没有render时被调用。在初始化时不会被调用。
componentDidUpdate 在组件完成更新后立即调用。在初始化时不会被调用。
8、react-router
https://segmentfault.com/a/1190000004527878
实现URL与UI界面的同步。其中在react-router中,URL对应Location对象,而UI是由react components来决定的,这样就转变成location与components之间的同步问题。
在react-router中最主要的component是Router RouterContext Link,history库起到了中间桥梁的作用。
9、react和vue的生命周期
https://www.cnblogs.com/qiaojie/p/6135180.html
初始化
1、getDefaultProps()
设置默认的props,也可以用dufaultProps设置组件的默认属性.
2、getInitialState()
在使用es6的class语法时是没有这个钩子函数的,可以直接在constructor中定义this.state。此时可以访问this.props
3、componentWillMount()
组件初始化时只调用,以后组件更新不调用,整个生命周期只调用一次,此时可以修改state。
4、 render()
react最重要的步骤,创建虚拟dom,进行diff算法,更新dom树都在此进行。此时就不能更改state了。
5、componentDidMount()
组件渲染之后调用,只调用一次。
更新
6、componentWillReceiveProps(nextProps)
组件初始化时不调用,组件接受新的props时调用。
7、shouldComponentUpdate(nextProps, nextState)
react性能优化非常重要的一环。组件接受新的state或者props时调用,我们可以设置在此对比前后两个props和state是否相同,如果相同则返回false阻止更新,因为相同的属性状态一定会生成相同的dom树,这样就不需要创造新的dom树和旧的dom树进行diff算法对比,节省大量性能,尤其是在dom结构复杂的时候
8、componentWillUpdata(nextProps, nextState)
组件初始化时不调用,只有在组件将要更新时才调用,此时可以修改state
9、render()
组件渲染
10、componentDidUpdate()
组件初始化时不调用,组件更新完成后调用,此时可以获取dom节点。
卸载
11、componentWillUnmount()
组件将要卸载时调用,一些事件监听和定时器需要在此时清除。
10、react和vue的虚拟dom以及diff算法
引入了Virtual DOM之后,React是这么干的:你给我一个数据,我根据这个数据生成一个全新的Virtual DOM,然后跟我上一次生成的Virtual DOM去 diff,得到一个Patch,然后把这个Patch打到浏览器的DOM上去。完事。并且这里的patch显然不是完整的虚拟DOM,而是新的虚拟DOM和上一次的虚拟DOM经过diff后的差异化的部分。
https://blog.csdn.net/u012657197/article/details/77816531
但是值得称道的是,React基于两个假设,大大提高了diff算法的性能:
两个相同的组件会产生两个类似的DOM结构,两个不同的组件会产生两个不同的DOM结构。
对于同一层级的一组子节点,它们可以通过唯一 id 进行区分。
基于这两个假设, 将算法的复杂度由O(n^3)变成了O(n)。极大的提高了效率。
先通过虚拟DOM计算出对真实DOM的最小修改量,然后再修改真实的DOM。
一、不同节点类型的比较
在虚拟树中比较两个虚拟DOM节点,若两个节点类型不同,则直接销毁前面的节点,创建并插入新节点。
若被删除的节点之下还有子节点,那么这些子节点也会一并删除。因为一般情况不同组件产生不同的DOM结构,与其浪费时间比较他们基本不会相等的DOM结构还不如加个新组建上去。
二、只会逐层比较节点
比如A节点下有子节点BC,要将A节点包括其子节点移动到其他节点下面,则不是将A赋值并移动到其他节点如D下面,而是重新创建每一个节点:
三、相同节点类型的比较
相同类型的节点, 对属性进行重设。
四、列表节点的比较
列表中节点若没有唯一标识的key值的话,会提示警告。
假设在列表ABCD中B的后面插入E,若没有key值则会将C更新为E,将D更新为C,最后插入D节点。
但是若有key值的话,react会找到正确的插入位置。
还有若A下面有BC子节点,若未提供key值,则react认为BC类型不同,要调整BC的位置会将BC删除后重新新建再插入,若有key值的话,则只是更新BC和其父组件而已。
11、为什么选择Redux
传统 Web 开发面临的困境在于:如何将服务器端或者用户输入的动态数据高效地反映到复杂的用户界面上。
React 的出现则完美解决了上面的问题,它用整体刷新的方式替代了传统的局部刷新。这样一来,开发人员就不需要频繁进行复杂的 DOM 操作,只需要关注数据状态变化和最终的 UI 的呈现,其他的 React 自动解决,大大降低了开发的复杂度。
同时,React 把前端页面组件化(比如Form表单),充分提高代码重复利用率,提高了产品开发效率的同时,代码也更容易理解、测试和维护。
在 Hacker News 发布的求职技能需求数据中, React 已连续 12 个月成为最受企业欢迎的技能,需求指数一度达到 25.93 %,足可见 React 被认可的程度。
掌握 React 不仅可以帮你应对前端应用开发,而且它的编程思想还可以应用到 React Native 原生 App 开发和服务器端渲染的后端开发。所以不论你是否从事前端开发工作,学习 React 对技能提升和职业发展都有很大的帮助。
12、Redux
Redux 的核心是一个 store。
provider
store 是一个 JavaScript 对象,通过 Redux 提供的 createStore(reducers) 方法创建。
store 有两个核心方法: .getState() 和 .dispatch()。
.getState() 返回一个 JavaScript 对象,代表 store 当前的状态。
.dispatch() 接受一个 action 作为参数,将这个 action 分发给所有订阅了更新的 reducer。
action 是一个 JavaScript 对象,通常包含了 type、payload 等字段,用于描述发生的事件及相关信息(使用 Redux 中间件可以让你 dispatch 其它类型的 action,此处不展开)。
reducer 是一个 JavaScript 函数,函数签名为 (previousState, action) => newState,即接受 previousState 和 action 两个参数,根据 action 中携带的信息对 previousState 做出相应的处理,并返回一个新的 state。
中间件:
redux的核心,就是控制和管理所有的数据输入输出,因此有了dispatch,由于dispatch是一个很纯的纯函数,就是单纯的派发action来更改数据,其功能简单且固定。
如果我们的程序中有很多的dispatch,我们就需要添加很多的重复代码,虽然编辑器提供批量替换,但这无疑是产生了很多样板代码。
因为所有的需求都是和dispatch息息相关,所以只要我们把日志放进dispatch函数里,不就好了吗,我们只需要更改dispatch函数,把dispatch进行一层封装。
middleware(store)(dispatch) 就相当于是 const logger = store => next => {},这就是构造后的dispatch,继续向下传递。这里middlewares.reverse(),进行数组反转的原因,是最后构造的dispatch,实际上是最先执行的。因为在applyMiddleware串联的时候,每个中间件只是返回一个新的dispatch函数给下一个中间件,实际上这个dispatch并不会执行。只有当我们在程序中通过store.dispatch(action),真正派发的时候,才会执行。而此时的dispatch是最后一个中间件返回的包装函数。然后依次向前递推执行。
12、Redux vs Mobx
那么具体到这两种模型,又有一些特定的优缺点呈现出来,先谈谈 Redux 的优势:
数据流流动很自然,因为任何 dispatch 都会导致广播,需要依据对象引用是否变化来控制更新粒度。
如果充分利用时间回溯的特征,可以增强业务的可预测性与错误定位能力。
时间回溯代价很高,因为每次都要更新引用,除非增加代码复杂度,或使用 immutable。
时间回溯的另一个代价是 action 与 reducer 完全脱节,数据流过程需要自行脑补。原因是可回溯必然不能保证引用关系。
引入中间件,其实主要为了解决异步带来的副作用,业务逻辑或多或少参杂着 magic。
但是灵活利用中间件,可以通过约定完成许多复杂的工作。
对 typescript 支持困难。
Mobx:
数据流流动不自然,只有用到的数据才会引发绑定,局部精确更新,但免去了粒度控制烦恼。
没有时间回溯能力,因为数据只有一份引用。
自始至终一份引用,不需要 immutable,也没有复制对象的额外开销。
没有这样的烦恼,数据流动由函数调用一气呵成,便于调试。
业务开发不是脑力活,而是体力活,少一些 magic,多一些效率。
由于没有 magic,所以没有中间件机制,没法通过 magic 加快工作效率(这里 magic 是指 action 分发到 reducer 的过程)。
完美支持 typescript。
13、vue的observer,watcher,compile
14、react和angular分别用在什么样的业务吗?性能方面和MVC层面上的区别
15、jQuery对象和JS的Element有什么区别
16、jQuery对象是怎么实现的
17、jQuery除了它封装了一些方法外,还有什么值得我们去学习和使用的?
18、jQuery的$(‘xxx’)做了什么事情
19、介绍一下bootstrap的栅格系统是如何实现的
20、纯函数
函数的返回结果只依赖于它的参数。
函数执行过程里面没有副作用。
23、高阶组件、和父组件有什么区别
高阶组件的主要功能是封装并分离组件的通用逻辑,让通用逻辑在组件间更好地被复用。
进阶用法
高阶组件最常见的函数签名形式是这样的:
HOC([param])([WrappedComponent])
注意事项
1)不要在组件的render方法中使用高阶组件,尽量也不要在组件的其他生命周期方法中使用高阶组件。因为高阶组件每次都会返回一个新的组件,在render中使用会导致每次渲染出来的组件都不相等(===),于是每次render,组件都会卸载(unmount),然后重新挂载(mount),既影响了效率,又丢失了组件及其子组件的状态。高阶组件最适合使用的地方是在组件定义的外部,这样就不会受到组件生命周期的影响了。
2)如果需要使用被包装组件的静态方法,那么必须手动拷贝这些静态方法。因为高阶组件返回的新组件,是不包含被包装组件的静态方法。hoist-non-react-statics可以帮助我们方便的拷贝组件所有的自定义静态方法。有兴趣的同学可以自行了解。
3)Refs不会被传递给被包装组件。尽管在定义高阶组件时,我们会把所有的属性都传递给被包装组件,但是ref并不会传递给被包装组件,因为ref根本不属于React组件的属性。如果你在高阶组件的返回组件中定义了ref,那么它指向的是这个返回的新组件,而不是内部被包装的组件。如果你希望获取被包装组件的引用,你可以把ref的回调函数定义成一个普通属性(给它一个ref以外的名字)。
24、.Nodejs
对nodejs有没有了解
Express 和 koa 有什么关系,有什么区别?
启动方式
koa采用了new Koa()的方式,而express采用传统的函数形式,对比源码如下:
express处理多个中间件
const app = require("express")(); app.use((req,res,next)=>{ console.log("first"); //next(); }); app.use((req,res,next)=>{ console.log("second"); //next(); }); app.use((req,res,next)=>{ console.log("third"); res.status(200).send("<h1>headers ...</h1>"); }); app.listen(3001);
koa处理多个中间件
const Koa = require('koa'); const app = new Koa(); app.use((ctx,next) => { ctx.body = 'Hello Koa-1'; next(); }); app.use((ctx,next) => { ctx.body = 'Hello Koa-2'; next(); }); app.use((ctx,next) => { ctx.body = 'Hello Koa-3'; next(); }); app.listen(3000);
分路由:
koa轻量级 但是要install许多中间件
nodejs适合做什么样的业务?
适合NodeJS的场景
1. RESTful API
这是NodeJS最理想的应用场景,可以处理数万条连接,本身没有太多的逻辑,只需要请求API,组织数据进行返回即可。它本质上只是从某个数据库中查找一些值并将它们组成一个响应。由于响应是少量文本,入站请求也是少量的文本,因此流量不高,一台机器甚至也可以处理最繁忙的公司的API需求。
2. 统一Web应用的UI层
目前MVC的架构,在某种意义上来说,Web开发有两个UI层,一个是在浏览器里面我们最终看到的,另一个在server端,负责生成和拼接页面。
不讨论这种架构是好是坏,但是有另外一种实践,面向服务的架构,更好的做前后端的依赖分离。如果所有的关键业务逻辑都封装成REST调用,就意味着在上层只需要考虑如何用这些REST接口构建具体的应用。那些后端程序员们根本不操心具体数据是如何从一个页面传递到另一个页面的,他们也不用管用户数据更新是通过Ajax异步获取的还是通过刷新页面。
3. 大量Ajax请求的应用
例如个性化应用,每个用户看到的页面都不一样,缓存失效,需要在页面加载的时候发起Ajax请求,NodeJS能响应大量的并发请求。
总而言之,NodeJS适合运用在高并发、I/O密集、少量业务逻辑的场景。
三. NodeJS的优缺点
优点:1. 高并发(最重要的优点)
2. 适合I/O密集型应用
缺点:1. 不适合CPU密集型应用;CPU密集型应用给Node带来的挑战主要是:由于JavaScript单线程的原因,如果有长时间运行的计算(比如大循环),将会导致CPU时间片不能释放,使得后续I/O无法发起;
解决方案:分解大型运算任务为多个小任务,使得运算能够适时释放,不阻塞I/O调用的发起;
2. 只支持单核CPU,不能充分利用CPU
3. 可靠性低,一旦代码某个环节崩溃,整个系统都崩溃
原因:单进程,单线程
解决方案:(1)Nnigx反向代理,负载均衡,开多个进程,绑定多个端口;
(2)开多个进程监听同一个端口,使用cluster模块;
4. 开源组件库质量参差不齐,更新快,向下不兼容
5. Debug不方便,错误没有stack trace
25、nodejs与php,java有什么区别
总结一下:Java、PHP也有办法实现并行请求(子线程),但NodeJS通过回调函数(Callback)和异步机制会做得很自然。
26、Nodejs中的Stream和Buffer有什么区别?
buffer
为数据缓冲对象,是一个类似数组结构的对象,可以通过指定开始写入的位置及写入的数据长度,往其中写入二进制数据
stream
是对buffer对象的高级封装,其操作的底层还是buffer对象,stream可以设置为可读、可写,或者即可读也可写,在nodejs中继承了EventEmitter接口,可以监听读入、写入的过程。具体实现有文件流,httpresponse等
27、node的异步问题是如何解决的?
1、 callback function
2、 promise
generator function(co)
async await function(es2016 规范)
28、node是如何实现高并发的?
因为I/O操作是由node的工作线程去执行的(nodejs底层的libuv是多线程的线程池用来并行io操作),且主线程是不需要等待结果返回的,只要发出指令马上就可以去忙其他事情了。
29、说一下 Nodejs 的 event loop 的原理
一个事件轮询Event Loop需要三个组件:
事件队列Event Queue,属于FIFO模型,一端推入事件数据,另外一端拉出事件数据,两端只通过这个队列通讯,属于一种异步的松耦合。
队列的读取轮询线程,事件的消费者,Event Loop的主角。
单独线程池Thread Pool,专门用来执行长任务,重任务,干繁重体力活的。
在Node.js中,因为只有一个单线程不断地轮回查询队列中是否有事件,对于数据库 文件系统等I/O操作,包括HTTP请求等等这些容易堵塞等待的操作,如果也是在这个单线程中实现,肯定会堵塞影响其他工作任务的执行,Javascript/Node.js会委托给底层的线程池执行,并会告诉线程池一个回调函数,这样单线程继续执行其他事情,当这些堵塞操作完成后,其结果与提供的回调函数一起再放入队列中,当单线程从队列中不断读取事件,读取到这些堵塞的操作结果后,会将这些操作结果作为回调函数的输入参数,然后激活运行回调函数。
请注意,Node.js的这个单线程不只是负责读取队列事件,还会执行运行回调函数,这是它区别于多线程模式的一个主要特点,多线程模式下,单线程只负责读取队列事件,不再做其他事情,会委托其他线程做其他事情,特别是多核的情况下,一个CPU核负责读取队列事件,一个CPU核负责执行激活的任务,这种方式最适合很耗费CPU计算的任务。反过来,Node..js的执行激活任务也就是回调函数中的任务还是在负责轮询的单线程中执行,这就注定了它不能执行CPU繁重的任务,比如JSON转换为其他数据格式等等,这些任务会影响事件轮询的效率。
十一.数据结构
1、基本数据结构:(数组、队列、链表、堆、二叉树、哈希表等等)
2、8种排序算法,原理,以及适用场景和复杂度
https://www.cnblogs.com/ytb-wpq/p/6479240.html
排序算法(背诵冒泡排序、选择排序、计数排序、快速排序、插入排序、归并排序)
- 冒泡:
function bubbleSort(arr) {
var len = arr.length;
for (var i = 0; i < len - 1; i++) {
for (var j = 0; j < len - 1 - i; j++) {
if (arr[j] > arr[j+1]) { // 相邻元素两两对比
var temp = arr[j+1]; // 元素交换
arr[j+1] = arr[j];
arr[j] = temp;
}
}
}
return arr;
}
2、选择:
function selectionSort(arr) {
var len = arr.length;
var minIndex, temp;
for (var i = 0; i < len - 1; i++) {
minIndex = i;
for (var j = i + 1; j < len; j++) {
if (arr[j] < arr[minIndex]) { // 寻找最小的数
minIndex = j; // 将最小数的索引保存
}
}
temp = arr[i];
arr[i] = arr[minIndex];
arr[minIndex] = temp;
}
return arr;
}
3、插入排序:
function insertionSort(arr) {
var len = arr.length;
var preIndex, current;
for (var i = 1; i < len; i++) {
preIndex = i - 1;
current = arr[i];
while(preIndex >= 0 && arr[preIndex] > current) {
arr[preIndex+1] = arr[preIndex];
preIndex--;
}
arr[preIndex+1] = current;
}
return arr;
}
二分查找法
翻转二叉树
3、说出越多越好的费波拉切数列的实现方法?
十二.性能优化
1、cdn的用法是什么?什么时候用到?
2、浏览器的页面优化?
3、如何优化 DOM 操作的性能
4、单页面应用有什么SEO方案?
5、单页面应用首屏显示比较慢,原因是什么?有什么解决方案?
十三.其他
1、正则表达式
2、前端渲染和后端渲染的优缺点
3、数据库的四大特性,什么是原子性,表的关系
4、你觉得前端体系应该是怎样的?
5、一个静态资源要上线,里面有各种资源依赖,你如何平稳上线
6、如果要你去实现一个前端模板引擎,你会怎么做
7、知道流媒体查询吗?
8、SEO
9、mysql 和 mongoDB 有什么区别?
10、restful的method解释
11、数据库知识、操作系统知识
12、click在ios上有300ms延迟,原因及如何解决
13、移动端的适配,rem+媒体查询/meta头设置
14、移动端的手势和事件;
15、unicode,utf8,gbk编码的了解,乱码的解决
十四.开放性问题
1、你都看过什么书?最近在看什么书?
2、用过什么框架?有没有看过什么框架的代码?
3、有没有学过设计模式?
4、说一说观察者模式吧!能不能写出来?
5、你最大的优点是什么?那你最大的缺点呢?
6、你除了写博客还有什么输出?
7、现在你的领导给你了一份工作,要求你一个星期完成,但你看了需求以后估计需要3周才能完成,你该怎么办?
8、平时关注的前端技术
9、如何规划自己的职业生涯
10、项目过程中,有遇到什么问题吗?怎么解决的?
11、最近在研究哪方面的东西?
12、请介绍一项你最热爱、最擅长的专业领域,并且介绍的学习规划。
13、请介绍你参与的印象最深刻的一个项目,为什么?并且介绍你在项目中的角色和发挥的作用。
十五.HR面
1、你为什么要学习前端?
2、你平时的是怎么学习前端的?有什么输出?
3、你觉得自己最好的项目是什么?
4、身边比较佩服的人有什么值得你学习的?你为什么没有跟他们一样?
5、同事的什么问题会让你接受不了
6、压力最大的事情是什么?
7、身边的朋友通常对你的评价是什么
8、喜欢什么样的工作氛围
9、如何看待加班
10、有没有对象
11、意向城市
12、其他的offer
13、为什么要录取你?
14、周末都会干什么?
15、未来职业规划
Js数组的常用方法:
方法 |
描述 |
连接两个或更多的数组,并返回结果。 |
|
从数组的指定位置拷贝元素到数组的另一个指定位置中。 |
|
检测数值元素的每个元素是否都符合条件。 |
|
使用一个固定值来填充数组。 |
|
检测数值元素,并返回符合条件所有元素的数组。 |
|
返回符合传入测试(函数)条件的数组元素。 |
|
返回符合传入测试(函数)条件的数组元素索引。 |
|
数组每个元素都执行一次回调函数。 |
|
搜索数组中的元素,并返回它所在的位置。 |
|
把数组的所有元素放入一个字符串。 |
|
返回一个指定的字符串值最后出现的位置,在一个字符串中的指定位置从后向前搜索。 |
|
通过指定函数处理数组的每个元素,并返回处理后的数组。 |
|
删除数组的最后一个元素并返回删除的元素。 |
|
向数组的末尾添加一个或更多元素,并返回新的长度。 |
|
将数组元素计算为一个值(从左到右)。 |
|
将数组元素计算为一个值(从右到左)。 |
|
反转数组的元素顺序。 |
|
删除并返回数组的第一个元素。 |
|
选取数组的的一部分,并返回一个新数组。 |
|
检测数组元素中是否有元素符合指定条件。 |
|
对数组的元素进行排序。 |
|
从数组中添加或删除元素。 |
|
把数组转换为字符串,并返回结果。 |
|
向数组的开头添加一个或更多元素,并返回新的长度。 |
|
返回数组对象的原始值。 |
数组去重:
方法一:
双层循环,外层循环元素,内层循环时比较值
如果有相同的值则跳过,不相同则push进数组
Array.prototype.distinct = function(){
var arr = this,
result = [],
i,
j,
len = arr.length;
for(i = 0; i < len; i++){
for(j = i + 1; j < len; j++){
if(arr[i] === arr[j]){
j = ++i;
}
}
result.push(arr[i]);
}
return result;
}
var arra = [1,2,3,4,4,1,1,2,1,1,1];
arra.distinct(); //返回[3,4,2,1]
方法二:利用splice直接在原数组进行操作
双层循环,外层循环元素,内层循环时比较值
值相同时,则删去这个值
注意点:删除元素之后,需要将数组的长度也减1.
Array.prototype.distinct = function (){
var arr = this,
i,
j,
len = arr.length;
for(i = 0; i < len; i++){
for(j = i + 1; j < len; j++){
if(arr[i] == arr[j]){
arr.splice(j,1);
len--;
j--;
}
}
}
return arr;
};
var a = [1,2,3,4,5,6,5,3,2,4,56,4,1,2,1,1,1,1,1,1,];
var b = a.distinct();
console.log(b.toString()); //1,2,3,4,5,6,56
优点:简单易懂
缺点:占用内存高,速度慢
方法三:利用对象的属性不能相同的特点进行去重
Array.prototype.distinct = function (){
var arr = this,
i,
obj = {},
result = [],
len = arr.length;
for(i = 0; i< arr.length; i++){
if(!obj[arr[i]]){ //如果能查找到,证明数组元素重复了
obj[arr[i]] = 1;
result.push(arr[i]);
}
}
return result;
};
var a = [1,2,3,4,5,6,5,3,2,4,56,4,1,2,1,1,1,1,1,1,];
var b = a.distinct();
console.log(b.toString()); //1,2,3,4,5,6,56
方法四:数组递归去重
运用递归的思想
先排序,然后从最后开始比较,遇到相同,则删除
Array.prototype.distinct = function (){
var arr = this,
len = arr.length;
arr.sort(function(a,b){ //对数组进行排序才能方便比较
return a - b;
})
function loop(index){
if(index >= 1){
if(arr[index] === arr[index-1]){
arr.splice(index,1);
}
loop(index - 1); //递归loop函数进行去重
}
}
loop(len-1);
return arr;
};
var a = [1,2,3,4,5,6,5,3,2,4,56,4,1,2,1,1,1,1,1,1,56,45,56];
var b = a.distinct();
console.log(b.toString()); //1,2,3,4,5,6,45,56
方法五:利用indexOf以及forEach
Array.prototype.distinct = function (){
var arr = this,
result = [],
len = arr.length;
arr.forEach(function(v, i ,arr){ //这里利用map,filter方法也可以实现
var bool = arr.indexOf(v,i+1); //从传入参数的下一个索引值开始寻找是否存在重复
if(bool === -1){
result.push(v);
}
})
return result;
};
var a = [1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,3,3,3,3,3,3,3,2,3,3,2,2,1,23,1,23,2,3,2,3,2,3];
var b = a.distinct();
console.log(b.toString()); //1,23,2,3
方法六:利用ES6的set
Set数据结构,它类似于数组,其成员的值都是唯一的。
利用Array.from将Set结构转换成数组
function dedupe(array){
return Array.from(new Set(array));
}
dedupe([1,1,2,3]) //[1,2,3]
拓展运算符(...)内部使用for...of循环
let arr = [1,2,3,3];
let resultarr = [...new Set(arr)];
console.log(resultarr); //[1,2,3]
Js实现 addClass hasClass removeClass toggleClass
function hasClass(obj, cls) {
return obj.className.match(new RegExp('(\\s|^)' + cls + '(\\s|$)'));
}
function addClass(obj, cls) {
if (!this.hasClass(obj, cls)) obj.className += " " + cls;
}
function removeClass(obj, cls) {
if (hasClass(obj, cls)) {
var reg = new RegExp('(\\s|^)' + cls + '(\\s|$)');
obj.className = obj.className.replace(reg, ' ');
}
}
function toggleClass(obj,cls){
if(hasClass(obj,cls)){
removeClass(obj, cls);
}else{
addClass(obj, cls);
}
}
String的金额的转换,转成每3个一个逗号
function addCommas(nStr) {
nStr += '';
x = nStr.split('.');
x1 = x[0];
x2 = x.length > 1 ? '.' + x[1] : '';
var rgx = /(\d+)(\d{3})/;
while (rgx.test(x1)) {
x1 = x1.replace(rgx, '$1' + ',' + '$2');
}
return x1 + x2;
}
console.log(addCommas(12132435556.15454545));