总结不易,希望可以帮助到即将面试或还在学习中的web前端小伙伴,祝面试顺利,拿高薪!
本章是HTML考点的⾮重难点,因此我们采⽤简略回答的⽅式进⾏撰写,所以不会有太多详细的解释。我们约定,每个问题后我们标记『✨ 』的为⾼频⾯试题
doctype的作⽤是什么?✨
DOCTYPE是html5标准⽹⻚声明,且必须声明在HTML⽂档的第⼀⾏。来告知浏览器的解析器⽤什么⽂档标准解析这个
⽂档,不同的渲染模式会影响到浏览器对于 CSS 代码甚⾄ JavaScript 脚本的解析
⽂档解析类型有:
BackCompat:怪异模式,浏览器使⽤⾃⼰的怪异模式解析渲染⻚⾯。(如果没有声明DOCTYPE,默认就是这个模式)
CSS1Compat:标准模式,浏览器使⽤W3C的标准解析渲染⻚⾯。
IE8还有⼀种介乎于上述两者之间的近乎标准的模式,但是基本淘汰了。
这三种模式的区别是什么?
标准模式(standards mode):⻚⾯按照 HTML 与 CSS 的定义渲染怪异模式(quirks mode)模式: 会模拟更旧的浏览器的⾏为
近乎标准(almost standards)模式: 会实施了⼀种表单元格尺⼨的怪异⾏为(与IE7之前的单元格布局⽅式⼀致), 除此之外符合标准定义
HTML、XHTML、XML有什么区别?
HTML(超⽂本标记语⾔): 在html4.0之前HTML先有实现再有标准,导致HTML⾮常混乱和松散
XML(可扩展标记语⾔): 主要⽤于存储数据和结构,可扩展,⼤家熟悉的JSON也是相似的作⽤,但是更加轻量⾼效,所以XML现在市场越来越⼩了
XHTML(可扩展超⽂本标记语⾔): 基于上⾯两者⽽来,W3C为了解决HTML混乱问题⽽⽣,并基于此诞⽣了
HTML5,开头加⼊ 的做法因此⽽来,如果不加就是兼容混乱的HTML,加了就是标准模式。
什么是data-属性?
HTML的数据属性,⽤于将数据储存于标准的HTML元素中作为额外信息,我们可以通过js访问并操作它,来达到操作数据的⽬的。
前端框架出现之后,这种⽅法已经不流⾏了
你对HTML语义化的理解?✨
语义化是指使⽤恰当语义的html标签,让⻚⾯具有良好的结构与含义,⽐如
标签就代表段落,
HTML5与HTML4的不同之处
⽂件类型声明()仅有⼀型:。新的解析顺序:不再基于SGML。
新的元素:section, video, progress, nav, meter, time, aside, canvas, command, datalist, details, embed, figcaption, figure, footer, header, hgroup, keygen, mark, output, rp, rt, ruby, source, summary, wbr 。 input元素的新类型:date, email, url等等。
新的属性:ping(⽤于a与area), charset(⽤于meta), async(⽤于script)。全域属性:id, tabindex, repeat。
新的全域属性:contenteditable, contextmenu, draggable, dropzone, hidden, spellcheck。
移除元素:acronym, applet, basefont, big, center, dir, font, frame, frameset, isindex, noframes, strike, tt
有哪些常⽤的meta标签?
meta标签由name和content两个属性来定义,来描述⼀个HTML⽹⻚⽂档的属性,例如作者、⽇期和时间、⽹⻚描述、关键词、⻚⾯刷新等,除了⼀些http标准规定了⼀些name作为⼤家使⽤的共识,开发者也可以⾃定义name。
charset,⽤于描述HTML⽂档的编码形式
http-equiv,顾名思义,相当于http的⽂件头作⽤,⽐如下⾯的代码就可以设置http的缓存过期⽇期
viewport,移动前端最熟悉不过,Web开发⼈员可以控制视⼝的⼤⼩和⽐例
apple-mobile-web-app-status-bar-style,开发过PWA应⽤的开发者应该很熟悉,为了⾃定义评估⼯具栏的颜⾊。
src和href的区别?
src是指向外部资源的位置,指向的内容会嵌⼊到⽂档中当前标签所在的位置,在请求src资源时会将其指向的资源 下载并应⽤到⽂档内,如js脚本,img图⽚和frame等元素。当浏览器解析到该元素时,会暂停其他资源的下载和处理,知道将该资源加载、编译、执⾏完毕,所以⼀般js脚本会放在底部⽽不是头部。
href是指向⽹络资源所在位置(的超链接),⽤来建⽴和当前元素或⽂档之间的连接,当浏览器识别到它他指向的
⽂件时,就会并⾏下载资源,不会停⽌对当前⽂档的处理。
知道img的srcset的作⽤是什么?(追问)
可以设计响应式图⽚,我们可以使⽤两个新的属性srcset 和 sizes来提供更多额外的资源图像和提示,帮助浏览器选择正确的⼀个资源。
srcset 定义了我们允许浏览器选择的图像集,以及每个图像的⼤⼩。
sizes 定义了⼀组媒体条件(例如屏幕宽度)并且指明当某些媒体条件为真时,什么样的图⽚尺⼨是最佳选择。所以,有了这些属性,浏览器会:
查看设备宽度
检查 sizes 列表中哪个媒体条件是第⼀个为真查看给予该媒体查询的槽⼤⼩
加载 srcset 列表中引⽤的最接近所选的槽⼤⼩的图像
srcset提供了根据屏幕条件选取图⽚的能⼒
还有哪⼀个标签能起到跟srcset相似作⽤?(追问)
元素通过包含零或多个 元素和⼀个 元素来为不同的显示/设备场景提供图像版本。浏览器会选择最匹配的⼦ 元素,如果没有匹配的,就选择 元素的 src 属性中的URL。然后,所选图像呈现在 元素占据的空间中
picture同样可以通过不同设备来匹配不同的图像资源
script标签中defer和async的区别?✨
defer:浏览器指示脚本在⽂档被解析后执⾏,script被异步加载后并不会⽴刻执⾏,⽽是等待⽂档被解析完毕后执
⾏。
async:同样是异步加载脚本,区别是脚本加载完毕后⽴即执⾏,这导致async属性下的脚本是乱序的,对于script
有先后依赖关系的情况,并不适⽤。
蓝⾊线代表⽹络读取,红⾊线代表执⾏时间,这俩都是针对脚本的;绿⾊线代表 HTML 解析
有⼏种前端储存的⽅式?✨
cookies、localstorage、sessionstorage、Web SQL、IndexedDB
这些⽅式的区别是什么?(追问)✨
cookies: 在HTML5标准前本地储存的主要⽅式,优点是兼容性好,请求头⾃带cookie⽅便,缺点是⼤⼩只有4k,
⾃动请求头加⼊cookie浪费流量,每个domain限制20个cookie,使⽤起来麻烦需要⾃⾏封装
localStorage:HTML5加⼊的以键值对(Key-Value)为标准的⽅式,优点是操作⽅便,永久性储存(除⾮⼿动删除),⼤⼩为5M,兼容IE8+
sessionStorage:与localStorage基本类似,区别是sessionStorage当⻚⾯关闭后会被清理,⽽且与cookie、localStorage不同,他不能在所有同源窗⼝中共享,是会话级别的储存⽅式
Web SQL:2010年被W3C废弃的本地数据库数据存储⽅案,但是主流浏览器(⽕狐除外)都已经有了相关的实现,web sql类似于SQLite,是真正意义上的关系型数据库,⽤sql进⾏操作,当我们⽤JavaScript时要进⾏转换, 较为繁琐。
IndexedDB: 是被正式纳⼊HTML5标准的数据库储存⽅案,它是NoSQL数据库,⽤键值对进⾏储存,可以进⾏快速读取操作,⾮常适合web场景,同时⽤JavaScript进⾏操作会⾮常⽅便。
CSS选择器的优先级是怎样的?✨ link和@import的区别?
有哪些⽅式(CSS)可以隐藏⻚⾯元素?
em\px\rem区别?
块级元素⽔平居中的⽅法?
CSS有⼏种定位⽅式? 如何理解z-index?✨ 如何理解层叠上下⽂?✨ 清除浮动有哪些⽅法? 你对css-sprites的理解 你对媒体查询的理解? 你对盒模型的理解?✨
标准盒模型和怪异盒模型有什么区别?✨
谈谈对BFC(Block Formatting Context)的理解? ✨ 为什么有时候⼈们⽤translate来改变位置⽽不是定位? 伪类和伪元素的区别是什么?
你对flex的理解?✨
关于CSS的动画与过渡问题
本章是CSS考点的⾮重难点,因此我们采⽤简略回答的⽅式进⾏撰写,所以不会有太多详细的解释。我们约定,每个问题后我们标记『✨ 』的为⾼频⾯试题
CSS选择器的优先级是怎样的?✨
CSS选择器的优先级是:内联 > ID选择器 > 类选择器 > 标签选择器
到具体的计算层⾯,优先级是由 A 、B、C、D 的值来决定的,其中它们的值计算规则如下:
A 的值等于 1 的前提是存在内联样式, 否则 A = 0; B 的值等于 ID选择器 出现的次数;
C 的值等于 类选择器 和 属性选择器 和 伪类 出现的总次数;
D 的值等于 标签选择器 和 伪元素 出现的总次数 。
就⽐如下⾯的选择器,它不存在内联样式,所以A=0,不存在id选择器B=0,存在⼀个类选择器C=1,存在三个标签选择器
D=3,那么最终计算结果为: {0, 0, 1 ,3}
按照这个结算⽅式,下⾯的计算结果为: {0, 1, 0, 0}
我们的⽐较优先级的⽅式是从A到D去⽐较值的⼤⼩,A、B、C、D权重从左到右,依次减⼩。判断优先级时,从左到右,⼀⼀⽐较,直到⽐较出最⼤值,即可停⽌。
⽐如第⼆个例⼦的B与第⼀个例⼦的B相⽐,1>0,接下来就不需要⽐较了,第⼆个选择器的优先级更⾼。
link和@import的区别?
link属于XHTML标签,⽽@import是CSS提供的。
⻚⾯被加载时,link会同时被加载,⽽@import引⽤的CSS会等到⻚⾯被加载完再加载。
import只在IE 5以上才能识别,⽽link是XHTML标签,⽆兼容问题。link⽅式的样式权重⾼于@import的权重。
使⽤dom控制样式时的差别。当使⽤javascript控制dom去改变样式的时候,只能使⽤link标签,因为@import不是
dom可以控制的。
有哪些⽅式(CSS)可以隐藏⻚⾯元素?
opacity:0 :本质上是将元素的透明度将为0,就看起来隐藏了,但是依然占据空间且可以交互
visibility:hidden : 与上⼀个⽅法类似的效果,占据空间,但是不可以交互了
overflow:hidden : 这个只隐藏元素溢出的部分,但是占据空间且不可交互
display:none : 这个是彻底隐藏了元素,元素从⽂档流中消失,既不占据空间也不交互,也不影响布局
z-index:-9999 : 原理是将层级放到底部,这样就被覆盖了,看起来隐藏了
transform: scale(0,0) : 平⾯变换,将元素缩放为0,但是依然占据空间,但不可交互
还有⼀些靠绝对定位把元素移到可视区域外,或者⽤clip-path进⾏裁剪的操作过于Hack,就不提了。
em\px\rem区别?
px:绝对单位,⻚⾯按精确像素展示。
em:相对单位,基准点为⽗节点字体的⼤⼩,如果⾃身定义了font-size按⾃身来计算(浏览器默认字体是16px),整个⻚⾯内1em不是⼀个固定的值。
rem:相对单位,可理解为”root em”, 相对根节点html的字体⼤⼩来计算,CSS3新加属性,chrome/firefox/IE9+⽀持
块级元素⽔平居中的⽅法?
如果使⽤Hack的话,⽔平居中的⽅法⾮常多,我们只介绍主流的,奇葩的⻅拓展阅读
margin:0 auto ⽅法
flex布局,⽬前主流⽅法
table⽅法
还有⼀些通过position+(margin|transform)等⽅法的不⼀样列举了,⾮重点没必要。拓展阅读: 16种⽅法实现⽔平居中垂直居中
CSS有⼏种定位⽅式?
static: 正常⽂档流定位,此时 top, right, bottom, left 和 z-index 属性⽆效,块级元素从上往下纵向排布,⾏级元素从左向右排列。
relative:相对定位,此时的『相对』是相对于正常⽂档流的位置。
absolute:相对于最近的⾮ static 定位祖先元素的偏移,来确定元素位置,⽐如⼀个绝对定位元素它的⽗级、和祖
⽗级元素都为relative,它会相对他的⽗级⽽产⽣偏移。
fixed:指定元素相对于屏幕视⼝(viewport)的位置来指定元素位置。元素的位置在屏幕滚动时不会改变,⽐如那种回到顶部的按钮⼀般都是⽤此定位⽅式。
sticky:粘性定位,特性近似于relative和fixed的合体,其在实际应⽤中的近似效果就是IOS通讯录滚动的时候的
『顶屁股』。
⽂字描述很难理解,可以直接看代码
如何理解z-index?✨
CSS 中的z-index属性控制重叠元素的垂直叠加顺序,默认元素的z-index为0,我们可以修改z-index来控制元素的图层位置,⽽且z-index只能影响设置了position值的元素。
我们可以把视图上的元素认为是⼀摞书的层叠,⽽⼈眼是俯视的视⻆,设置z-index的位置,就如同设置某⼀本书在这摞书中的位置。
顶部: 最接近观察者
…
3 层
2 层
1 层
0 层 默认层
-1 层
-2 层
-3 层
…
底层: 距离观察者最远
可以结合这个例⼦理解z-index
如何理解层叠上下⽂?✨
是什么?
层叠上下⽂是HTML元素的三维概念,这些HTML元素在⼀条假想的相对于⾯向(电脑屏幕的)视窗或者⽹⻚的⽤户的z 轴上延伸,HTML元素依据其⾃身属性按照优先级顺序占⽤层叠上下⽂的空间。
如何产⽣?
触发⼀下条件则会产⽣层叠上下⽂: 根元素 (HTML),
z-index 值不为 "auto"的 绝对/相对定位,
⼀个 z-index 值不为 "auto"的 flex 项⽬ (flex item),即:⽗元素 display: flex|inline-flex, opacity 属性值⼩于 1 的元素(参考 the specification for opacity),
transform 属性值不为 "none"的元素,
mix-blend-mode 属性值不为 "normal"的元素, filter值不为“none”的元素,
perspective 值 不 为 “none” 的 元 素 , isolation 属性被设置为 "isolate"的元素,
position: fixed
在 will-change 中指定了任意 CSS 属性,即便你没有直接指定这些属性的值(参考 这篇⽂章)
-webkit-overflow-scrolling 属性被设置 "touch"的元素
拓展阅读:层叠上下⽂-张鑫旭
清除浮动有哪些⽅法?
空 div ⽅ 法 :
Clearfix ⽅法:上⽂使⽤.clearfix类已经提到overflow: auto或overflow: hidden⽅法,使⽤BFC你对css sprites的理解,好处是什么?
是什么 ?
雪碧图也叫CSS精灵, 是⼀CSS图像合成技术,开发⼈员往往将⼩图标合并在⼀起之后的图⽚称作雪碧图。
如何操作?
使⽤⼯具(PS之类的)将多张图⽚打包成⼀张雪碧图,并为其⽣成合适的 CSS。 每张图⽚都有相应的 CSS 类,该类定义了background-image、background-position和background-size属性。 使⽤图⽚时,将相应的类添加到你的元素中。
好处:
减少加载多张图⽚的 HTTP 请求数(⼀张雪碧图只需要⼀个请求) 提前加载资源
不⾜:
CSS Sprite维护成本较⾼,如果⻚⾯背景有少许改动,⼀般就要改这张合并的图⽚
加载速度优势在http2开启后荡然⽆存,HTTP2多路复⽤,多张图⽚也可以重复利⽤⼀个连接通道搞定
你对媒体查询的理解?
是什么
媒体查询由⼀个可选的媒体类型和零个或多个使⽤媒体功能的限制了样式表范围的表达式组成,例如宽度、⾼度和颜
⾊。媒体查询,添加⾃CSS3,允许内容的呈现针对⼀个特定范围的输出设备⽽进⾏裁剪,⽽不必改变内容本身,⾮常适合web⽹⻚应对不同型号的设备⽽做出对应的响应适配。
如何使⽤?
媒体查询包含⼀个可选的媒体类型和,满⾜CSS3规范的条件下,包含零个或多个表达式,这些表达式描述了媒体特 征,最终会被解析为true或false。如果媒体查询中指定的媒体类型匹配展示⽂档所使⽤的设备类型,并且所有的表达式的值都是true,那么该媒体查询的结果为true.那么媒体查询内的样式将会⽣效。
拓展阅读:深⼊理解CSS Media媒体查询
你对盒模型的理解✨
是什么?
当对⼀个⽂档进⾏布局(lay out)的时候,浏览器的渲染引擎会根据标准之⼀的 CSS 基础框盒模型(CSS basic box model),将所有元素表示为⼀个个矩形的盒⼦(box)。CSS 决定这些盒⼦的⼤⼩、位置以及属性(例如颜⾊、背景、边框尺⼨…)。
盒模型由content(内容)、padding(内边距)、border(边框)、margin(外边距)组成。
标准盒模型和怪异盒模型有什么区别?✨
在W3C标准下,我们定义元素的width值即为盒模型中的content的宽度值,height值即为盒模型中的content的⾼度值。因此,标准盒模型下:
元素的宽度 = margin-left + border-left + padding-left + width + padding-right + border-right + margin-right
⽽IE怪异盒模型(IE8以下)width的宽度并不是content的宽度,⽽是border-left + padding-left + content的宽度值 + padding-right + border-right之和,height同理。
在怪异盒模型下:
元素占据的宽度 = margin-left + width + margin-right
虽然现代浏览器默认使⽤W3C的标准盒模型,但是在不少情况下怪异盒模型更好⽤,于是W3C在css3中加⼊ box- sizing 。
此演示来源于拓展阅读⽂章
拓展阅读:深⼊理解盒模型
谈谈对BFC的理解✨
是什么?
书⾯解释:BFC(Block Formatting Context)这⼏个英⽂拆解
Box: CSS布局的基本单位,Box 是 CSS 布局的对象和基本单位, 直观点来说,就是⼀个⻚⾯是由很多个 Box 组成的,实际就是上个问题说的盒模型
Formatting context:块级上下⽂格式化,它是⻚⾯中的⼀块渲染区域,并且有⼀套渲染规则,它决定了其⼦元素将如何定位,以及和其他元素的关系和相互作⽤
简⽽⾔之,它是⼀块独⽴的区域,让处于BFC内部的元素与外部的元素互相隔离
如何形成?
BFC触发条件:
根元素,即HTML元素position: fixed/absolute float 不 为 none overflow不为visible
display的值为inline-block、table-cell、table-caption
作⽤是什么?
防⽌margin发⽣重叠
两栏布局,防⽌⽂字环绕等
防⽌元素塌陷
拓展阅读:深⼊理解BFC
为什么有时候⼈们⽤translate来改变位置⽽不是定位?
translate()是transform的⼀个值。改变transform或opacity不会触发浏览器重新布局(reflow)或重绘(repaint),只会 触发复合(compositions)。⽽改变绝对定位会触发重新布局,进⽽触发重绘和复合。transform使浏览器为元素创建⼀个 GPU 图层,但改变绝对定位会使⽤到 CPU。 因此translate()更⾼效,可以缩短平滑动画的绘制时间。
⽽translate改变位置时,元素依然会占据其原始空间,绝对定位就不会发⽣这种情况。拓展阅读:CSS3 3D transform变换-张鑫旭
伪类和伪元素的区别是什么?
是什么?
伪类(pseudo-class) 是⼀个以冒号(:)作为前缀,被添加到⼀个选择器末尾的关键字,当你希望样式在特定状态下才被呈现到指定的元素时,你可以往元素的选择器后⾯加上对应的伪类。
伪元素⽤于创建⼀些不在⽂档树中的元素,并为其添加样式。⽐如说,我们可以通过::before来在⼀个元素前增加⼀些
⽂本,并为这些⽂本添加样式。虽然⽤户可以看到这些⽂本,但是这些⽂本实际上不在⽂档树中。
区别
其实上⽂已经表达清楚两者区别了,伪类是通过在元素选择器上加⼊伪类改变元素状态,⽽伪元素通过对元素的操作进
⾏对元素的改变。
我们通过 p::before 对这段⽂本添加了额外的元素,通过 p:first-child 改变了⽂本的样式。
拓展阅读:伪类与伪元素
你对flex的理解?✨
web应⽤有不同设备尺⼨和分辨率,这时需要响应式界⾯设计来满⾜复杂的布局需求,Flex弹性盒模型的优势在于开发
⼈员只是声明布局应该具有的⾏为,⽽不需要给出具体的实现⽅式,浏览器负责完成实际布局,当布局涉及到不定宽度,分布对⻬的场景时,就要优先考虑弹性盒布局
具体⽤法移步阮⼀峰的flex语法、flex实战,讲得⾮常通俗易懂,⽽且我们⼀两句话说不清楚。
关于CSS的动画与过渡问题
深⼊理解CSS动画animation https://www.cnblogs.com/xiaohuochai/p/5391663.html
深⼊理解CSS过渡transition https://www.cnblogs.com/xiaohuochai/p/5347930.html
参考资料:
终于到了⼤家最擅⻓的JavaScript部分,相⽐于HTML和CSS笔者写起JavaScript要顺⼿很多,虽然前端有三剑客的说法,但是实际应⽤中基本就是JavaScript为绝对主导,尤其是在⼯程化的今天。
所以JavaScript才是前端基础⾯试中的重中之重,在这部分我们会加⼊⼀个新的部分就是原理性的解释。
⽐如,我们会有⼀个⾯试问题『解释下变量提升?』,在本章下我们会有⼀个简短的解释,但是不会解释原理性的东
⻄,因为『简短的解释』是给⾯试官听的,『原理性的』是给⾃⼰解释的,原理性的解释会在相关问题下连接到其他各个原理性详解的章节。
再说⼀下为什么会有『原理详解』这⼀part,本项⽬并不仅想作为⾯试季帮助⼤家突击的⼀个清单,更想做的是帮助⼤家梳理前端的各个知识点,并把知识点讲透彻,这才是真正对每个开发者有成⻓的事情。
此外,如果不懂原理,很容易被较真的⾯试官追问,⼀下就原形毕露了,所以如果你不懂原理,建议阅读原理部分,如果你已经懂了,可以看简答部分作为梳理即可。
我们约定,每个问题后我们标记『✨ 』的为⾼频⾯试题
本章索引
async/await 相⽐于Promise的优势?
解释下变量提升?✨
JavaScript引擎的⼯作⽅式是,先解析代码,获取所有被声明的变量,然后再⼀⾏⼀⾏地运⾏。这造成的结果,就是所有的变量的声明语句,都会被提升到代码的头部,这就叫做变量提升(hoisting)。
上⾯的代码实际执⾏顺序是这样的:
第⼀步: 引擎将 var a = 1 拆解为 var a = undefined 和 a = 1 ,并将 var a = undefined 放到最顶端, a = 1 还在原来的位置
这样⼀来代码就是这样:
第⼆步就是执⾏,因此js引擎⼀⾏⼀⾏从上往下执⾏就造成了当前的结果,这就叫变量提升。原理详解请移步,预解释与变量提升
⼀段JavaScript代码是如何执⾏的?✨
此部分涉及概念较多,请移步JavaScript执⾏机制
理解闭包吗?✨
这个问题其实在问:
闭包是什么
MDN的解释:闭包是函数和声明该函数的词法环境的组合。
按照我的理解就是:闭包 =『函数』和『函数体内可访问的变量总和』举个简单的例⼦:
add 函数本身,以及其内部可访问的变量,即 a = 1 ,这两个组合在⼀起就被称为闭包,仅此⽽已。
闭包的作⽤
闭包最⼤的作⽤就是隐藏变量,闭包的⼀⼤特性就是内部函数总是可以访问其所在的外部函数中声明的参数和变量,即使在其外部函数被返回(寿命终结)了之后
基于此特性,JavaScript可以实现私有变量、特权变量、储存变量等
我们就以私有变量举例,私有变量的实现⽅法很多,有靠约定的(变量名前加_),有靠Proxy代理的,也有靠Symbol这种新数据类型的。
但是真正⼴泛流⾏的其实是使⽤闭包。
函数体内的 var name = ‘cxk’ 只有 getName 和 setName 两个函数可以访问,外部⽆法访问,相对于将变量私有化。
JavaScript的作⽤域链理解吗?✨
JavaScript属于静态作⽤域,即声明的作⽤域是根据程序正⽂在编译时就确定的,有时也称为词法作⽤域。
其本质是JavaScript在执⾏过程中会创造可执⾏上下⽂,可执⾏上下⽂中的词法环境中含有外部词法环境的引⽤,我们 可以通过这个引⽤获取外部词法环境的变量、声明等,这些引⽤串联起来⼀直指向全局的词法环境,因此形成了作⽤域链。
原理详解请移步JavaScript执⾏机制
ES6模块与CommonJS模块有什么区别?
ES6 Module和CommonJS模块的区别:
CommonJS是对模块的浅拷⻉,ES6 Module是对模块的引⽤,即ES6 Module只存只读,不能改变其值,具体点就是指针指向不能变,类似const
import的接⼝是read-only(只读状态),不能修改其变量值。 即不能修改其变量的指针指向,但可以改变变量内部指针指向,可以对commonJS对重新赋值(改变指针指向),但是对ES6 Module赋值会编译报错。
ES6 Module和CommonJS模块的共同点:
CommonJS和ES6 Module都可以对引⼊的对象进⾏赋值,即对对象内部属性的值进⾏改变。详解请移步ES6模块与CommonJS模块的差异
js有哪些类型?
JavaScript的类型分为两⼤类,⼀类是原始类型,⼀类是复杂(引⽤)类型。原始类型:
boolean null undefined number string symbol
复杂类型:
Object
还有⼀个没有正式发布但即将被加⼊标准的原始类型BigInt。
为什么会有BigInt的提案?
JavaScript中Number.MAX_SAFE_INTEGER表示最⼤安全数字,计算结果是9007199254740991,即在这个数范围内不 会出现精度丢失(⼩数除外)。
但是⼀旦超过这个范围,js就会出现计算不准确的情况,这在⼤数计算的时候不得不依靠⼀些第三⽅库进⾏解决,因此官⽅提出了BigInt来解决此问题。
null与undefined的区别是什么?
null表示为空,代表此处不应该有值的存在,⼀个对象可以是null,代表是个空对象,⽽null本身也是对象。
undefined表示『不存在』,JavaScript是⼀⻔动态类型语⾔,成员除了表示存在的空值外,还有可能根本就不存在(因为存不存在只在运⾏期才知道),这就是undefined的意义所在。
0.1+0.2为什么不等于0.3?
JS 的 Number 类型遵循的是 IEEE 754 标准,使⽤的是 64 位固定⻓度来表示。
IEEE 754 浮点数由三个域组成,分别为 sign bit (符号位)、exponent bias (指数偏移值) 和 fraction (分数值)。64 位中,
sign bit 占 1 位,exponent bias 占 11 位,fraction 占 52 位。
通过公式表示浮点数的值 value = sign x exponent x fraction
**
当⼀个数为正数,sign bit 为 0,当为负数时,sign bit 为 1.
以 0.1 转换为 IEEE 754 标准表示为例解释⼀下如何求 exponent bias 和 fraction。转换过程主要经历 3 个过程:
将 0.1 转换为⼆进制表示
回顾⼀下⼀个数的⼩数部分如何转换为⼆进制。⼀个数的⼩数部分,乘以 2,然后取整数部分的结果,再⽤计算后的⼩数部分重复计算,直到⼩数部分为 0 。
因此 0.1 转换为⼆进制表示的过程如下:
⼩数 x2 的结果 整数部分
0.1 0.2 0
0.2 0.4 0
0.4 0.8 0
0.8 1.6 1
0.6 1.2 1
0.2 0.4 0
0.4 0.8 0
0.8 1.6 1
0.6 1.2 1
… … …
得到 0.1 的⼆进制表示为 0.00011…(⽆限重复 0011)
通过科学计数法表示
0.00011…(⽆限重复 0011) 通过科学计数法表示则是 1.10011001…(⽆线重复 1001)*2
转换为 IEEE 754 标准表示
当经过科学计数法表示之后,就可以求得 exponent bias 和 fraction 了。
exponent bias (指数偏移值) 等于 双精度浮点数固定偏移值 (2-1) 加上指数实际值(即 2 中的 -4) 的 11 位⼆进制表示。为什么是 11 位?因为 exponent bias 在 64 位中占 11 位。
因此 0.1 的 exponent bias 等于 1023 + (-4) = 1019 的11 位⼆进制表示,即 011 1111 1011。
再来获取 0.1 的 fraction,fraction 就是 1.10011001…(⽆线重复 1001) 中的⼩数位,由于 fraction 占 52位所以抽取 52
位⼩数,1001…(中间有 11 个 1001)…1010 (请注意最后四位,是 1010 ⽽不是 1001,因为四舍五⼊有进位,这个进位
就是造成 0.1 + 0.2 不等于 0.3 的原因)
此时如果将这个数转换为⼗进制,可以发现值已经变为 0.100000000000000005551115123126 ⽽不是 0.1 了,因此这个计算精度就出现了问题。
类型转换的规则有哪些?
在if语句、逻辑语句、数学运算逻辑、==等情况下都可能出现隐⼠类型转换。
类型转换的原理是什么?
类型转换指的是将⼀种类型转换为另⼀种类型,例如:
当然,类型转换分为显式和隐式,但是不管是隐式转换还是显式转换,都会遵循⼀定的原理,由于JavaScript是⼀⻔动态类型的语⾔,可以随时赋予任意值,但是各种运算符或条件判断中是需要特定类型的,因此JavaScript引擎会在运算时为变量设 定类型.
这看起来很美好,JavaScript引擎帮我们搞定了 类型 的问题,但是引擎毕竟不是ASI(超级⼈⼯智能),它的很多动作会跟我们预期相去甚远,我们可以从⼀到⾯试题开始.
答案是0
是什么原因造成了上述结果呢?那么我们得从ECMA-262中提到的转换规则和抽象操作说起,有兴趣的童鞋可以仔细阅读下这浩如烟海的语⾔规范,如果没这个耐⼼还是往下看.
这是JavaScript种类型转换可以从原始类型转为引⽤类型,同样可以将引⽤类型转为原始类型,转为原始类型的抽象操作为 ToPrimitive ,⽽后续更加细分的操作为: ToNumber ToString ToBoolean 。
为了更深⼊的探究JavaScript引擎是如何处理代码中类型转换问题的,就需要看 ECMA-262详细的规范,从⽽探究其内部原理,我们从这段内部原理示意代码开始.
上⾯代码的逻辑是这样的:
那讲了实现原理,这个 ToPrimitive 有什么⽤呢?实际很多操作会调⽤ ToPrimitive ,⽐如加、相等或⽐较操。在进⾏加操作时会将左右操作数转换为 primitive ,然后进⾏相加。
下⾯来个实例,({}) + 1(将{}放在括号中是为了内核将其认为⼀个代码块)会输出啥?可能⽇常写代码并不会这样写, 不过⽹上出过类似的⾯试题。
加操作只有左右运算符同时为 String或Number 时会执⾏对应的 %_StringAdd或%NumberAdd ,下⾯看下 ({}) + 1 内部会经过哪些步骤:
{} 和 1 ⾸先会调⽤ToPrimitive {} 会⾛到 DefaultNumber ,⾸先会调⽤ valueOf ,返回的是 ,不是
primitive类型,从⽽继续⾛到 toString ,返回 [object Object] ,是 String 类型 最后加操作,结果为 [object Object]1 再⽐如有⼈问你 [] + 1 输出啥时,你可能知道应该怎么去计算了,先对 [] 调⽤ ToPrimitive ,返回空字符串,最后结果为"1"。
谈谈你对原型链的理解?✨
这个问题关键在于两个点,⼀个是原型对象是什么,另⼀个是原型链是如何形成的
原型对象
绝⼤部分的函数(少数内建函数除外)都有⼀个 prototype 属性,这个属性是原型对象⽤来创建新对象实例,⽽所有被创建的对象都会共享原型对象,因此这些对象便可以访问原型对象的属性。
例如 hasOwnProperty() ⽅法存在于Obejct原型对象中,它便可以被任何对象当做⾃⼰的⽅法使⽤.
⽤法: object.hasOwnProperty( propertyName )
hasOwnProperty() 函数的返回值为 Boolean 类型。如果对象 object 具有名称为 propertyName 的属性,则返回 true ,否则返回 false 。
由以上代码可知, hasOwnProperty() 并不存在于 person 对象中,但是 person 依然可以拥有此⽅法. 所以 person 对象是如何找到 Object 对象中的⽅法的呢?靠的是原型链。
原型链
原因是每个对象都有 proto 属性,此属性指向该对象的构造函数的原型。
对象可以通过 proto 与上游的构造函数的原型对象连接起来,⽽上游的原型对象也有⼀个 proto ,这样就形成了原型链。
经典原型链图
如何判断是否是数组?
es6中加⼊了新的判断⽅法
在考虑兼容性的情况下可以⽤toString的⽅法
谈⼀谈你对this的了解?✨
this的指向不是在编写时确定的,⽽是在执⾏时确定的,同时,this不同的指向在于遵循了⼀定的规则。
⾸先,在默认情况下,this是指向全局对象的,⽐如在浏览器就是指向window。
其次,如果函数被调⽤的位置存在上下⽂对象时,那么函数是被隐式绑定的。
再次,显示改变this指向,常⻅的⽅法就是call、apply、bind 以bind为例:
最后,也是优先级最⾼的绑定 new 绑定。
⽤ new 调⽤⼀个构造函数,会创建⼀个新对象, 在创造这个新对象的过程中,新对象会⾃动绑定到Person对象的this上, 那么 this ⾃然就指向这个新对象。
绑定优先级: new绑定 > 显式绑定 >隐式绑定 >默认绑定
那么箭头函数的this指向哪⾥?✨
箭头函数不同于传统JavaScript中的函数,箭头函数并没有属于⾃⼰的this,它的所谓的this是捕获其所在上下⽂的 this
值,作为⾃⼰的 this 值,并且由于没有属于⾃⼰的this,⽽箭头函数是不会被new调⽤的,这个所谓的this也不会被改变.
我们可以⽤Babel理解⼀下箭头函数:
转化后
async/await是什么?
async 函数,就是 Generator 函数的语法糖,它建⽴在Promises上,并且与所有现有的基于Promise的API兼容。
async/await相⽐于Promise的优势?
代码读起来更加同步,Promise虽然摆脱了回调地狱,但是then的链式调⽤也会带来额外的阅读负担
Promise传递中间值⾮常麻烦,⽽async/await⼏乎是同步的写法,⾮常优雅
错误处理友好,async/await可以⽤成熟的try/catch,Promise的错误捕获⾮常冗余
调试友好,Promise的调试很差,由于没有代码块,你不能在⼀个返回表达式的箭头函数中设置断点,如果你在⼀个.then代码块中使⽤调试器的步进(step-over)功能,调试器并不会进⼊后续的.then代码块,因为调试器只能跟踪 同步代码的『每⼀步』。
JavaScript的参数是按照什么⽅式传递的?
基本类型传递⽅式
由于js中存在复杂类型和基本类型,对于基本类型⽽⾔,是按值传递的.
虽然在函数 test 中 a 被修改,并没有有影响到 外部 a 的值,基本类型是按值传递的.
复杂类型按引⽤传递?
我们将外部 a 作为⼀个对象传⼊ test 函数.
可以看到,在函数体内被修改的 a 对象也同时影响到了外部的 a 对象,可⻅复杂类型是按引⽤传递的. 可是如果再做⼀个实验:
外部的 a 并没有被修改,如果是按引⽤传递的话,由于共享同⼀个堆内存, a 在外部也会表现为 10 才对. 此时的复杂类型同时表现出了 按值传递 和 按引⽤传递 的特性.
按共享传递
复杂类型之所以会产⽣这种特性,原因就是在传递过程中,对象 a 先产⽣了⼀个 副本a ,这个 副本a 并不是深克隆得到的 副地址同样指向对象 a 指向的堆内存.
因此在函数体中修改 x=10 只是修改了存,此时对象 a 也会受到影响.
对象没有变化. 但是如果修改了 x.a=10 是修改了两者指向的同⼀堆内
有⼈讲这种特性叫做传递引⽤,也有⼀种说法叫做按共享传递.
聊⼀聊如何在JavaScript中实现不可变对象?
实现不可变数据有三种主流的⽅法
JavaScript的基本类型和复杂类型是储存在哪⾥的?
基本类型储存在栈中,但是⼀旦被闭包引⽤则成为常住内存,会储存在内存堆中。复杂类型会储存在内存堆中。
原理解析请移步JavaScript内存管理
讲讲JavaScript垃圾回收是怎么做的?
此过程⽐较复杂,请看详细解析。
原理解析请移步JavaScript内存管理
HTTP协议
HTTP有哪些⽅法?
HTTP1.0定义了三种请求⽅法: GET, POST 和 HEAD⽅法
HTTP1.1新增了五种请求⽅法:OPTIONS, PUT, DELETE, TRACE 和 CONNECT
这些⽅法的具体作⽤是什么?
GET: 通常⽤于请求服务器发送某些资源
HEAD: 请求资源的头部信息, 并且这些头部与 HTTP GET ⽅法请求时返回的⼀致. 该请求⽅法的⼀个使⽤场景是在下载⼀个⼤⽂件前先获取其⼤⼩再决定是否要下载, 以此可以节约带宽资源
OPTIONS: ⽤于获取⽬的资源所⽀持的通信选项
POST: 发送数据给服务器
PUT: ⽤于新增资源或者使⽤请求中的有效负载替换⽬标资源的表现形式
DELETE: ⽤于删除指定的资源
PATCH: ⽤于对资源进⾏部分修改
CONNECT: HTTP/1.1协议中预留给能够将连接改为管道⽅式的代理服务器TRACE: 回显服务器收到的请求,主要⽤于测试或诊断
GET和POST有什么区别?
数据传输⽅式不同:GET请求通过URL传输数据,⽽POST的数据通过请求体传输。
安全性不同:POST的数据因为在请求主体内,所以有⼀定的安全性保证,⽽GET的数据在URL中,通过历史记录,缓存很容易查到数据信息。
数据类型不同:GET只允许 ASCII 字符,⽽POST⽆限制
GET⽆害: 刷新、后退等浏览器操作GET请求是⽆害的,POST可能重复提交表单
特性不同:GET是安全(这⾥的安全是指只读特性,就是使⽤这个⽅法不会引起服务器状态变化)且幂等(幂等的概念是指同⼀个请求⽅法执⾏多次和仅执⾏⼀次的效果完全相同),⽽POST是⾮安全⾮幂等
PUT和POST都是给服务器发送新增资源,有什么区别?
PUT 和POST⽅法的区别是,PUT⽅法是幂等的:连续调⽤⼀次或者多次的效果相同(⽆副作⽤),⽽POST⽅法是⾮幂等的。
除此之外还有⼀个区别,通常情况下,PUT的URI指向是具体单⼀资源,⽽POST可以指向资源集合。
举个例⼦,我们在开发⼀个博客系统,当我们要创建⼀篇⽂章的时候往往⽤ POST https://www.jianshu.com/articles , 这个请求的语义是,在articles的资源集合下创建⼀篇新的⽂章,如果我们多次提交这个请求会创建多个⽂章,这是⾮幂等的。
⽽ PUT https://www.jianshu.com/articles/820357430 的语义是更新对应⽂章下的资源(⽐如修改作者名称等),这个
URI指向的就是单⼀资源,⽽且是幂等的,⽐如你把『刘德华』修改成『蔡徐坤』,提交多少次都是修改成『蔡徐坤』
ps: 『POST表示创建资源,PUT表示更新资源』这种说法是错误的,两个都能创建资源,根本区别就在于幂等性
PUT和PATCH都是给服务器发送修改资源,有什么区别?
PUT和PATCH都是更新资源,⽽PATCH⽤来对已知资源进⾏局部更新。
⽐如我们有⼀篇⽂章的地址 https://www.jianshu.com/articles/820357430 ,这篇⽂章的可以表示为:
当我们要修改⽂章的作者时,我们可以直接发送 PUT https://www.jianshu.com/articles/820357430 ,这个时候的数据应该是:
这种直接覆盖资源的修改⽅式应该⽤put,但是你觉得每次都带有这么多⽆⽤的信息,那么可以发送 PATCH https://www.jianshu.com/articles/820357430 ,这个时候只需要:
http的请求报⽂是什么样的?
请求报⽂有4部分组成: 请求⾏
请求头部空⾏
请求体
请求⾏包括:请求⽅法字段、URL字段、HTTP协议版本字段。它们⽤空格分隔。例如,GET /index.html HTTP/1.1。
请求头部:请求头部由关键字/值对组成,每⾏⼀对,关键字和值⽤英⽂冒号“:”分隔
User-Agent:产⽣请求的浏览器类型。
Accept:客户端可识别的内容类型列表。
Host:请求的主机名,允许多个域名同处⼀个IP地址,即虚拟主机。
请求体: post put等请求携带的数据
http的响应报⽂是什么样的?
请求报⽂有4部分组成:
响应⾏响应头空 ⾏ 响应体
响应⾏: 由协议版本,状态码和状态码的原因短语组成,例如 HTTP/1.1 200 OK 。响应头:响应部⾸组成
响应体:服务器响应的数据
聊⼀聊HTTP的部⾸有哪些?
内容很多,重点看标『✨ 』内容
通⽤⾸部字段(General Header Fields):请求报⽂和响应报⽂两⽅都会使⽤的⾸部Cache-Control 控制缓存 ✨
Connection 连接管理、逐条⾸部 ✨
Upgrade 升级为其他协议via 代理服务器的相关信息Wraning 错误和警告通知
Transfor-Encoding 报⽂主体的传输编码格式 ✨
Trailer 报⽂末端的⾸部⼀览
Pragma 报⽂指令
Date 创建报⽂的⽇期
请求⾸部字段(Reauest Header Fields):客户端向服务器发送请求的报⽂时使⽤的⾸部Accept 客户端或者代理能够处理的媒体类型 ✨
Accept-Encoding 优先可处理的编码格式Accept-Language 优先可处理的⾃然语⾔Accept-Charset 优先可以处理的字符集If-Match ⽐较实体标记(ETage) ✨
If-None-Match ⽐较实体标记(ETage)与 If-Match相反 ✨
If-Modified-Since ⽐较资源更新时间(Last-Modified)✨
If-Unmodified-Since⽐较资源更新时间(Last-Modified),与 If-Modified-Since相反 ✨
If-Rnages 资源未更新时发送实体byte的范围请求
Range 实体的字节范围请求 ✨
Authorization web的认证信息 ✨
Proxy-Authorization 代理服务器要求web认证信息
Host 请求资源所在服务器 ✨
From ⽤户的邮箱地址
User-Agent 客户端程序信息 ✨ Max-Forwrads 最⼤的逐跳次数TE 传输编码的优先级
Referer 请 求 原 始 放 的 url Expect 期待服务器的特定⾏为
响应⾸部字段(Response Header Fields):从服务器向客户端响应时使⽤的字段
Accept-Ranges 能接受的字节范围Age 推算资源创建经过时间Location 令客户端重定向的URI ✨ vary 代理服务器的缓存信息
ETag 能够表示资源唯⼀资源的字符串 ✨
WWW-Authenticate 服务器要求客户端的验证信息Proxy-Authenticate 代理服务器要求客户端的验证信息Server 服务器的信息 ✨
Retry-After 和状态码503 ⼀起使⽤的⾸部字段,表示下次请求服务器的时间
实体⾸部字段(Entiy Header Fields):针对请求报⽂和响应报⽂的实体部分使⽤⾸部
Allow 资源可⽀持http请求的⽅法 ✨ Content-Language 实体的资源语⾔Content-Encoding 实体的编码格式Content-Length 实体的⼤⼩(字节) Content-Type 实体媒体类型
Content-MD5 实体报⽂的摘要Content-Location 代 替 资 源 的 yri Content-Rnages 实体主体的位置返回Last-Modified 资源最后的修改资源 ✨ Expires 实体主体的过期资源 ✨
聊⼀聊HTTP的状态码有哪些?
2XX 成功
200 OK,表示从客户端发来的请求在服务器端被正确处理 ✨
201 Created 请求已经被实现,⽽且有⼀个新的资源已经依据请求的需要⽽建⽴
202 Accepted 请求已接受,但是还没执⾏,不保证完成请求
204 No content,表示请求成功,但响应报⽂不含实体的主体部分206 Partial Content,进⾏范围请求 ✨
3XX 重定向
301 moved permanently,永久性重定向,表示资源已被分配了新的 URL 302 found,临时性重定向,表示资源临时被分配了新的 URL ✨
303 see other,表示资源存在着另⼀个 URL,应使⽤ GET ⽅法丁⾹获取资源
304 not modified,表示服务器允许访问资源,但因发⽣请求未满⾜条件的情况
307 temporary redirect,临时重定向,和302含义相同
4XX 客户端错误
400 bad request,请求报⽂存在语法错误 ✨
401 unauthorized,表示发送的请求需要有通过 HTTP 认证的认证信息 ✨
403 forbidden,表示对请求资源的访问被服务器拒绝 ✨ 404 not found,表示在服务器上没有找到请求的资源 ✨ 408 Request timeout, 客户端请求超时
409 Confict, 请求的资源可能引起冲突
5XX 服务器错误
500 internal sever error,表示服务器端在执⾏请求时发⽣了错误 ✨
501 Not Implemented 请求超出服务器能⼒范围,例如服务器不⽀持当前请求所需要的某个功能,或者请求是服务器不⽀持的某个⽅法
503 service unavailable,表明服务器暂时处于超负载或正在停机维护,⽆法处理请求505 http version not supported 服务器不⽀持,或者拒绝⽀持在请求中使⽤的 HTTP 版本
同样是重定向307,303,302的区别?
302是http1.0的协议状态码,在http1.1版本的时候为了细化302状态码⼜出来了两个303和307。
303明确表示客户端应当采⽤get⽅法获取资源,他会把POST请求变为GET请求进⾏重定向。 307会遵照浏览器标准, 不会从post变为get。
HTTP的keep-alive是⼲什么的?
在早期的HTTP/1.0中,每次http请求都要创建⼀个连接,⽽创建连接的过程需要消耗资源和时间,为了减少资源消耗, 缩短响应时间,就需要重⽤连接。在后来的HTTP/1.0中以及HTTP/1.1中,引⼊了重⽤连接的机制,就是在http请求头中加⼊Connection: keep-alive来告诉对⽅这个请求响应完成后不要关闭,下⼀次咱们还⽤这个请求继续交流。协议规定
HTTP/1.0如果想要保持⻓连接,需要在请求头中加上Connection: keep-alive。keep-alive的优点:
较少的CPU和内存的使⽤(由于同时打开的连接的减少了) 允许请求和应答的HTTP管线化
降低拥塞控制 (TCP连接减少了)
减少了后续请求的延迟(⽆需再进⾏握⼿) 报告错误⽆需关闭TCP连
为什么有了HTTP为什么还要HTTPS?
https是安全版的http,因为http协议的数据都是明⽂进⾏传输的,所以对于⼀些敏感信息的传输就很不安全,HTTPS就是为了解决HTTP的不安全⽽⽣的。
HTTPS是如何保证安全的?
过程⽐较复杂,我们得先理解两个概念
对称加密:即通信的双⽅都使⽤同⼀个秘钥进⾏加解密,⽐如特务接头的暗号,就属于对称加密
对称加密虽然很简单性能也好,但是⽆法解决⾸次把秘钥发给对⽅的问题,很容易被⿊客拦截秘钥。
⾮对称加密:
但是问题来了,如果中间⼈篡改了证书,那么身份证明是不是就⽆效了?这个证明就⽩买了,这个时候需要⼀个新的技术,数字签名。
数字签名就是⽤CA⾃带的HASH算法对证书的内容进⾏HASH得到⼀个摘要,再⽤CA的私钥加密,最终组成数字签名。
当别⼈把他的证书发过来的时候,我再⽤同样的Hash算法,再次⽣成消息摘要,然后⽤CA的公钥对数字签名解密,得到CA 创建的消息摘要,两者⼀⽐,就知道中间有没有被⼈篡改了。
这个时候就能最⼤程度保证通信的安全了。
HTTP2相对于HTTP1.x有什么优势和特点?
⼆进制分帧
帧:HTTP/2 数据通信的最⼩单位消息:指 HTTP/2 中逻辑上的 HTTP 消息。例如请求和响应等,消息由⼀个或多个帧组成。
流:存在于连接中的⼀个虚拟通道。流可以承载双向消息,每个流都有⼀个唯⼀的整数ID HTTP/2 采⽤⼆进制格式传输数据,⽽⾮ HTTP 1.x 的⽂本格式,⼆进制协议解析起来更⾼效。
头部压缩
HTTP/1.x会在请求和响应中中重复地携带不常改变的、冗⻓的头部数据,给⽹络带来额外的负担。
HTTP/2在客户端和服务器端使⽤“⾸部表”来跟踪和存储之前发送的键-值对,对于相同的数据,不再通过每次请求和响应发送
⾸部表在HTTP/2的连接存续期内始终存在,由客户端和服务器共同渐进地更新; 每个新的⾸部键-值对要么被追加到当前表的末尾,要么替换表中之前的值。
你可以理解为只发送差异数据,⽽不是全部发送,从⽽减少头部的信息量
服务器推送
服务端可以在发送⻚⾯HTML时主动推送其它资源,⽽不⽤等到浏览器解析到相应位置,发起请求再响应。例如服务端可以主动把JS和CSS⽂件推送给客户端,⽽不需要客户端解析HTML时再发送这些请求。
服务端可以主动推送,客户端也有权利选择是否接收。如果服务端推送的资源已经被浏览器缓存过,浏览器可以通过发送RST_STREAM帧来拒收。主动推送也遵守同源策略,服务器不会随便推送第三⽅资源给客户端。
多路复⽤
HTTP 1.x 中,如果想并发多个请求,必须使⽤多个 TCP 链接,且浏览器为了控制资源,还会对单个域名有 6-8个的TCP链接请求限制。
HTTP2中:
同域名下所有通信都在单个连接上完成。 单个连接可以承载任意数量的双向数据流。
数据流以消息的形式发送,⽽消息⼜由⼀个或多个帧组成,多个帧之间可以乱序发送,因为根据帧⾸部的流标识可以重新组装
拓展阅读:HTTP/2特性及其在实际应⽤中的表现
HTTP的缓存的过程是怎样的?
通常情况下的步骤是:
什么时候会触发强缓存或者协商缓存?
强缓存
强缓存离不开两个响应头 Expires 与 Cache-Control
Expires:Expires是http1.0提出的⼀个表示资源过期时间的header,它描述的是⼀个绝对时间,由服务器返回, Expires 受限于本地时间,如果修改了本地时间,可能会造成缓存失效
Expires: Wed, 11 May 2018 07:20:00 GMT
Cache-Control: Cache-Control 出现于 HTTP / 1.1,优先级⾼于 Expires ,表示的是相对时间
Cache-Control: max-age=315360000
⽬前主流的做法使⽤ Cache-Control 控制缓存,除了 max-age 控制过期时间外,还有⼀些不得不提
Cache-Control: public可以被所有⽤户缓存,包括终端和CDN等中间代理服务器Cache-Control: private只能被终端浏览器缓存,不允许中继缓存服务器进⾏缓存
Cache-Control: no-cache,先缓存本地,但是在命中缓存之后必须与服务器验证缓存的新鲜度才能使⽤Cache-Control: no-store,不会产⽣任何缓存
在缓存有效期内命中缓存,浏览器会直接读取本地的缓存资源,当缓存过期之后会与服务器进⾏协商。
协商缓存
当第⼀次请求时服务器返回的响应头中没有Cache-Control和Expires或者Cache-Control和Expires过期抑或它的属性设置为no-cache时,那么浏览器第⼆次请求时就会与服务器进⾏协商。
如果缓存和服务端资源的最新版本是⼀致的,那么就⽆需再次下载该资源,服务端直接返回304 Not Modified 状态码, 如果服务器发现浏览器中的缓存已经是旧版本了,那么服务器就会把最新资源的完整内容返回给浏览器,状态码就是 200 Ok。
服务器判断缓存是否是新鲜的⽅法就是依靠HTTP的另外两组信息
Last-Modified/If-Modified-Since
客户端⾸次请求资源时,服务器会把资源的最新修改时间 Last-Modified:Thu, 19 Feb 2019 08:20:55 GMT 通过响应部⾸发送给客户端,当再次发送请求是,客户端将服务器返回的修改时间放在请求头 If-Modified-Since:Thu, 19 Feb 2019 08:20:55 GMT 发送给服务器,服务器再跟服务器上的对应资源进⾏⽐对,如果服务器的资源更新,那么返回最新的资源,此时状态码200,当服务器资源跟客户端的请求的部⾸时间⼀致,证明客户端的资源是最新的,返回304状态码, 表示客户端直接⽤缓存即可。
ETag/If-None-Match
ETag的流程跟Last-Modified是类似的,区别就在于ETag是根据资源内容进⾏hash,⽣成⼀个信息摘要,只要资源内容有变化,这个摘要就会发⽣巨变,通过这个摘要信息⽐对,即可确定客户端的缓存资源是否为最新,这⽐Last-Modified 的精确度要更⾼。
响应头
因此整体的缓存流程图如下:
图⽚来源于博客
TODO:
http的整个流程,涉及tcp/ip协议
参考:
图 解 HTTP HTTP权威指南HTTP缓存策略
TCP⾯试题
TCP的⾯试题通常情况下前端不会涉及太多,此章主要⾯对node.js⼯程师。
TCP 的特性
TCP 提供⼀种⾯向连接的、可靠的字节流服务
在⼀个 TCP 连接中,仅有两⽅进⾏彼此通信。⼴播和多播不能⽤于 TCP TCP 使⽤校验和,确认和重传机制来保证可靠传输
TCP 给数据分节进⾏排序,并使⽤累积确认保证数据的顺序不变和⾮重复
TCP 使⽤滑动窗⼝机制来实现流量控制,通过动态改变窗⼝的⼤⼩进⾏拥塞控制
请简述TCP\UDP的区别
协议
连接性
双⼯性
可靠性
有序性
有界性 拥塞控制 传输速度
量级
头部
⼤⼩
TCP ⾯向连接(Connection oriented) 全双
⼯
(1:1) 可靠
(重传机制) 有序
(通过SYN排
序)
⽆, 有粘包情况
有
慢
低
20~60
字节
UDP ⽆连接(Connection less)
n:m 不可靠 (丢包后数据丢失)
⽆序
有消息边界, ⽆粘包
⽆
快
⾼
8字节
UDP socket ⽀持 n 对 m 的连接状态, 在官⽅⽂档中有写到在 dgram.createSocket(options[, callback]) 中的 option 可以指定 reuseAddr 即 SO_REUSEADDR 标志. 通过 SO_REUSEADDR 可以简单的实现 n 对 m 的多播特性 (不过仅在⽀持多播的系统上才有).
TCP粘包是怎么回事,如何处理? ✨
默认情况下, TCP 连接会启⽤延迟传送算法 (Nagle 算法), 在数据发送之前缓存他们. 如果短时间有多个数据发送, 会缓冲到⼀起作⼀次发送 (缓冲⼤⼩⻅ socket.bufferSize ), 这样可以减少 IO 消耗提⾼性能.
如果是传输⽂件的话, 那么根本不⽤处理粘包的问题, 来⼀个包拼⼀个包就好了. 但是如果是多条消息, 或者是别的⽤途的数据那么就需要处理粘包.
可以参⻅⽹上流传⽐较⼴的⼀个例⼦, 连续调⽤两次 send 分别发送两段数据 data1 和 data2, 在接收端有以下⼏种常⻅的情况:
A. 先接收到 data1, 然后接收到 data2 .
B. 先接收到 data1 的部分数据, 然后接收到 data1 余下的部分以及 data2 的全部.
C. 先接收到了 data1 的全部数据和 data2 的部分数据, 然后接收到了 data2 的余下的数据.
D. ⼀次性接收到了 data1 和 data2 的全部数据.
其中的 BCD 就是我们常⻅的粘包的情况. ⽽对于处理粘包的问题, 常⻅的解决⽅案有:
为什么udp不会粘包?
如何理解 TCP backlog?
本⽂来⾃How TCP backlog works in Linux
当应⽤程序调⽤ listen 系统调⽤让⼀个 socket 进⼊ LISTEN 状态时,需要指定⼀个参数: backlog 。这个参数经常被描述为,新连接队列的⻓度限制。
tcp-state-diagram.png
由于 TCP 建⽴连接需要进⾏3次握⼿,⼀个新连接在到达 ESTABLISHED 状态可以被 accept 系统调⽤返回给应⽤程序前, 必须经过⼀个中间状态 SYN RECEIVED (⻅上图)。这意味着, TCP/IP 协议栈在实现 backlog 队列时,有两种不同的选
择:
历史上,起源于 BSD 的 TCP 实现使⽤第⼀种⽅法。这个⽅案意味着,但 backlog 限制达到,系统将停⽌对 SYN 包响应 SYN/ACK 包。通常,协议栈只是丢弃 SYN 包(⽽不是回⼀个 RST 包)以便客户端可以重试(⽽不是异常退出)。
TCP/IP详解 卷3 第 14.5 节中有提到这⼀点。书中作者提到, BSD 实现虽然使⽤了两个独⽴的队列,但是⾏为跟使⽤⼀个队列并没什么区别。
在 Linux 上,情况有所不同,情况 listen 系统调⽤ man ⽂档⻚:
The behavior of the backlog argument on TCP sockets changed with Linux 2.2. Now it specifies the queue length for completely established sockets waiting to be accepted, instead of the number of incomplete connection requests. The maximum length of the queue for incomplete sockets can be set using
/proc/sys/net/ipv4/tcp_max_syn_backlog. When syncookies are enabled there is no logical maximum length and this setting is ignored. 意思是, backlog 参数的⾏为在 Linux 2.2之后有所改变。现在,它指定了等
待 accept 系统调⽤的已建⽴连接队列的⻓度,⽽不是待完成连接请求数。待完成连接队列⻓度
由 /proc/sys/net/ipv4/tcp_max_syn_backlog 指定;在 syncookies 启⽤的情况下,逻辑上没有最⼤值限制,这个设置便被忽略。
也就是说,当前版本的 Linux 实现了第⼆种⽅案,使⽤两个队列——⼀个 SYN 队列,⻓度系统级别可设置以及⼀个 accept 队列⻓度由应⽤程序指定。
现在,⼀个需要考虑的问题是在 accept 队列已满⽽⼀个已完成新连接需要⽤ SYN 队列移动到 accept 队列(收到3次握
⼿中最后⼀个 ACK 包),这个实现⽅案是什么⾏为。这种情况下,由 net/ipv4/tcp_minisocks.c 中 tcp_check_req 函数处理:
对于 IPv4 ,第⼀⾏代码实际上调⽤的是 net/ipv4/tcp_ipv4.c 中的 tcp_v4_syn_recv_sock 函数,代码如下:
可以看到,这⾥会检查 accept 队列的⻓度。如果队列已满,跳到 exit_overflow 标签执⾏⼀些清理⼯作、更
新 /proc/net/netstat 中的统计项 ListenOverflows 和 ListenDrops ,最后返回 NULL 。这会触发 tcp_check_req 函数跳到 listen_overflow 标签执⾏代码。
很显然,除⾮ /proc/sys/net/ipv4/tcp_abort_on_overflow 被设置为 1 (这种情况下发送⼀个 RST 包),实现什么都没做。总结⼀下: Linux 内核协议栈在收到3次握⼿最后⼀个 ACK 包,确认⼀个新连接已完成,⽽ accept 队列已满的情况下,会忽略这个包。⼀开始您可能会对此感到奇怪——别忘了 SYN RECEIVED 状态下有⼀个计时器实现:如果 ACK 包没有收到(或者是我们讨论的忽略),协议栈会重发 SYN/ACK 包(重试次数由 /proc/sys/net/ipv4/tcp_synack_retries 决定)。看以下抓包结果就⾮常明显——⼀个客户正尝试连接⼀个已经达到其最⼤ backlog 的 socket :
3.399 127.0.0.1 -> 127.0.0.1 TCP 74 9999 > 53302 [SYN, ACK] Seq=0 Ack=1 Len=0
3.399 127.0.0.1 -> 127.0.0.1 TCP 66 [TCP Dup ACK 10#1] 53302 > 9999 [ACK] Seq=6 Ack=1 Len=0
6.459 127.0.0.1 -> 127.0.0.1 TCP 71 [TCP Retransmission] 53302 > 9999 [PSH, ACK] Seq=1 Ack=1 Len=5
7.599 127.0.0.1 -> 127.0.0.1 TCP 74 9999 > 53302 [SYN, ACK] Seq=0 Ack=1 Len=0
7.599 127.0.0.1 -> 127.0.0.1 TCP 66 [TCP Dup ACK 13#1] 53302 > 9999 [ACK] Seq=6 Ack=1 Len=0
13.131 127.0.0.1 -> 127.0.0.1 TCP 71 [TCP Retransmission] 53302 > 9999 [PSH, ACK] Seq=1 Ack=1 Len=5
15.599 127.0.0.1 -> 127.0.0.1 TCP 74 9999 > 53302 [SYN, ACK] Seq=0 Ack=1 Len=0
15.599 127.0.0.1 -> 127.0.0.1 TCP 66 [TCP Dup ACK 16#1] 53302 > 9999 [ACK] Seq=6 Ack=1 Len=0
26.491 127.0.0.1 -> 127.0.0.1 TCP 71 [TCP Retransmission] 53302 > 9999 [PSH, ACK] Seq=1 Ack=1 Len=5
31.599 127.0.0.1 -> 127.0.0.1 TCP 74 9999 > 53302 [SYN, ACK] Seq=0 Ack=1 Len=0
31.599 127.0.0.1 -> 127.0.0.1 TCP 66 [TCP Dup ACK 19#1] 53302 > 9999 [ACK] Seq=6 Ack=1 Len=0
53.179 127.0.0.1 -> 127.0.0.1 TCP 71 [TCP Retransmission] 53302 > 9999 [PSH, ACK] Seq=1 Ack=1 Len=5
106.491 127.0.0.1 -> 127.0.0.1 TCP 71 [TCP Retransmission] 53302 > 9999 [PSH, ACK] Seq=1 Ack=1 Len=5
106.491 127.0.0.1 -> 127.0.0.1 TCP 54 9999 > 53302 [RST] Seq=1 Len=0
由于客户端的 TCP 实现在收到多个 SYN/ACK 包时,认为 ACK 包已经丢失了并且重传它。如果在 SYN/ACK 重试次数达到限制前,服务端应⽤从 accept 队列接收连接,使得 backlog 减少,那么协议栈会处理这些重传的 ACK 包,将连接状态从 SYN RECEIVED 变更到 ESTABLISHED 并且将其加⼊ accept 队列。否则,正如以上包跟踪所示,客户读会收到⼀
个 RST 包宣告连接失败。
在客户端看来,第⼀次收到 SYN/ACK 包之后,连接就会进⼊ ESTABLISHED 状态。如果这时客户端⾸先开始发送数据,那么数据也会被重传。好在 TCP 有慢启动机制,在服务端还没进⼊ ESTABLISHED 之前,客户端能发送的数据⾮常有限。 相反,如果客户端⼀开始就在等待服务端,⽽服务端 backlog 没能减少,那么最后的结果是连接在客户端看来
是 ESTABLISHED 状态,但在服务端看来是 CLOSED 状态。这也就是所谓的半开连接。
有⼀点还没讨论的是: man listen 中提到每次收到新 SYN 包,内核往 SYN 队列追加⼀个新连接(除⾮该队列已满)。事实并⾮如此, net/ipv4/tcp_ipv4.c 中 tcp_v4_conn_request 函数负责处理 SYN 包,请看以下代码:
可以看到,在 accept 队列已满的情况下,内核会强制限制 SYN 包的接收速率。如果有⼤量 SYN 包待处理,它们其中的
⼀些会被丢弃。这样看来,就完全依靠客户端重传 SYN 包了,这种⾏为跟 BSD 实现⼀样。
下结论前,需要再研究以下 Linux 这种实现⽅式跟 BSD 相⽐有什么优势。 Stevens 是这样说的:
在 accept 队列已满或者 SYN 队列已满的情况下, backlog 会达到限制。第⼀种情况经常发⽣在服务器或者服务器进程⾮常繁忙的情况下,进程没法⾜够快地调⽤ accept 系统调⽤从中取出已完成连接。后者是 HTTP 服务器经常⾯临的问题,在服务端客户端往返时间⾮常⻓的时候(相对于连接到达速率),因为新 SYN 包在往返时间内都会占据⼀个连接对象。 ⼤多数情况下 accept 队列都是空的,因为⼀旦有⼀个新连接进⼊队列,阻塞等待
的 accept 系统调⽤将返回,然后连接从队列中取出。
Stevens 建议的解决⽅案是简单地调⼤ backlog 。但有个问题是,应⽤程序在调优 backlog 参数时,不仅需要考虑⾃身对新连接的处理逻辑,还需要考虑⽹络状况,包括往返时间等。Linux实现实际上分成两部分:应⽤程序只负责调
解 backlog 参数,确保 accept 调⽤⾜够快以免 accept 队列被塞满;系统管理员则根据⽹络状况调节 /proc/sys/net/ipv4/tcp_max_syn_backlog ,各司其职。
常⽤端⼝号与对应的服务
端⼝ 作⽤说明
21 21端⼝主要⽤于FTP(File Transfer Protocol,⽂件传输协议)服务。
23 23端⼝主要⽤于Telnet(远程登录)服务,是Internet上普遍采⽤的登录和仿真程序。
25 25端⼝为SMTP(Simple Mail Transfer Protocol,简单邮件传输协议)服务器所开放,主要⽤于发送邮件,如今绝⼤多数邮件服务器都使⽤该协议。
53 53端⼝为DNS(Domain Name Server,域名服务器)服务器所开放,主要⽤于域名解析,DNS服务在NT系统中使⽤的最为⼴泛。
67、
68 67、68端⼝分别是为Bootp服务的Bootstrap Protocol Server(引导程序协议服务端)和Bootstrap Protocol Client(引导程序协议客户端)开放的端⼝。
69 TFTP是Cisco公司开发的⼀个简单⽂件传输协议,类似于FTP。
79 79端⼝是为Finger服务开放的,主要⽤于查询远程主机在线⽤户、操作系统类型以及是否缓冲区溢出等⽤户的详细信息。
80 80端⼝是为HTTP(HyperText Transport Protocol,超⽂本传输协议)开放的,这是上⽹冲浪使⽤最多的协议,主要⽤于在WWW(World WideWeb,万维⽹)服务上传输信息的协议。
99 99端⼝是⽤于⼀个名为“Metagram Relay”(亚对策延时)的服务,该服务⽐较少⻅,⼀般是⽤不到的。
109、
110 109端⼝是为POP2(Post Office Protocol Version 2,邮局协议2)服务开放的,110端⼝是为POP3(邮件协议3)服务开放的,POP2、POP3都是主要⽤于接收邮件的。
111 111端⼝是SUN公司的RPC(Remote ProcedureCall,远程过程调⽤)服务所开放的端⼝,主要⽤于分布式系统中不同计算机的内部进程通信,RPC在多种⽹络服务中都是很重要的组件。
113 113端⼝主要⽤于Windows的“Authentication Service”(验证服务)。 119端⼝:119端⼝是为“Network News TransferProtocol”(⽹络新闻组传输协议,简称NNTP)开放的。
135 135端⼝主要⽤于使⽤RPC(Remote Procedure Call,远程过程调⽤)协议并提供DCOM(分布式组件对象模型)服务。
137 137端⼝主要⽤于“NetBIOS Name Service”(NetBIOS名称服务)。
139 139端⼝是为“NetBIOS Session Service”提供的,主要⽤于提供Windows⽂件和打印机共享以及Unix中的Samba服务。
143 143端⼝主要是⽤于“Internet Message Access Protocol”v2(Internet消息访问协议,简称IMAP)。
161 161端⼝是⽤于“Simple Network Management Protocol”(简单⽹络管理协议,简称SNMP)。
443 443端⼝即⽹⻚浏览端⼝,主要是⽤于HTTPS服务,是提供加密和通过安全端⼝传输的另⼀种HTTP。
554 554端⼝默认情况下⽤于“Real Time Streaming Protocol”(实时流协议,简称RTSP)。
1024 1024端⼝⼀般不固定分配给某个服务,在英⽂中的解释是“Reserved”(保留)。
1080 1080端⼝是Socks代理服务使⽤的端⼝,⼤家平时上⽹使⽤的WWW服务使⽤的是HTTP协议的代理服务。
1755 1755端⼝默认情况下⽤于“Microsoft Media Server”(微软媒体服务器,简称MMS)。
4000 4000端⼝是⽤于⼤家经常使⽤的QQ聊天⼯具的,再细说就是为QQ客户端开放的端⼝,QQ服务端使⽤的端⼝是8000。
5554 在今年4⽉30⽇就报道出现了⼀种针对微软lsass服务的新蠕⾍病毒——震荡波(Worm.Sasser),该病毒可以利⽤TCP 5554端⼝开启⼀个FTP服务,主要被⽤于病毒的传播。
5632 5632端⼝是被⼤家所熟悉的远程控制软件pcAnywhere所开启的端⼝。
8080 8080端⼝同80端⼝,是被⽤于WWW代理服务的,可以实现⽹⻚。
说⼀说OSI七层模型
讲⼀下三次握⼿?✨
所谓三次握⼿(Three-way Handshake),是指建⽴⼀个 TCP 连接时,需要客户端和服务器总共发送3个包。
三次握⼿的⽬的是连接服务器指定端⼝,建⽴ TCP 连接,并同步连接双⽅的序列号和确认号,交换 TCP 窗⼝⼤⼩信息。在 socket 编程中,客户端执⾏ connect() 时。将触发三次握⼿。
第⼀次握⼿(SYN=1, seq=x):
客户端发送⼀个 TCP 的 SYN 标志位置1的包,指明客户端打算连接的服务器的端⼝,以及初始序号 X,保存在包头的序列号(Sequence Number)字段⾥。
发送完毕后,客户端进⼊ SYN_SEND 状态。
第⼆次握⼿(SYN=1, ACK=1, seq=y, ACKnum=x+1):
服务器发回确认包(ACK)应答。即 SYN 标志位和 ACK 标志位均为1。服务器端选择⾃⼰ ISN 序列号,放到 Seq 域
⾥,同时将确认序号(Acknowledgement Number)设置为客户的 ISN 加1,即X+1。 发送完毕后,服务器端进⼊
SYN_RCVD 状态。
第三次握⼿(ACK=1,ACKnum=y+1)
客户端再次发送确认包(ACK),SYN 标志位为0,ACK 标志位为1,并且把服务器发来 ACK 的序号字段+1,放在确定字段中发送给对⽅,并且在数据段放写ISN的+1
发送完毕后,客户端进⼊ ESTABLISHED 状态,当服务器端接收到这个包时,也进⼊ ESTABLISHED 状态,TCP 握⼿结束。
三次握⼿的过程的示意图如下:
讲⼀下四次握⼿?✨
TCP 的连接的拆除需要发送四个包,因此称为四次挥⼿(Four-way handshake),也叫做改进的三次握⼿。客户端或服务器均可主动发起挥⼿动作,在 socket 编程中,任何⼀⽅执⾏ close() 操作即可产⽣挥⼿操作。
第⼀次挥⼿(FIN=1,seq=x)
假设客户端想要关闭连接,客户端发送⼀个 FIN 标志位置为1的包,表示⾃⼰已经没有数据可以发送了,但是仍然可以接受数据。
发送完毕后,客户端进⼊ FIN_WAIT_1 状态。第⼆次挥⼿(ACK=1,ACKnum=x+1)
服务器端确认客户端的 FIN 包,发送⼀个确认包,表明⾃⼰接受到了客户端关闭连接的请求,但还没有准备好关闭连接。
发送完毕后,服务器端进⼊ CLOSE_WAIT 状态,客户端接收到这个确认包之后,进⼊ FIN_WAIT_2 状态,等待服务器端关闭连接。
第三次挥⼿(FIN=1,seq=y)
服务器端准备好关闭连接时,向客户端发送结束连接请求,FIN 置为1。
发送完毕后,服务器端进⼊ LAST_ACK 状态,等待来⾃客户端的最后⼀个ACK。第四次挥⼿(ACK=1,ACKnum=y+1)
客户端接收到来⾃服务器端的关闭请求,发送⼀个确认包,并进⼊ TIME_WAIT 状态,等待可能出现的要求重传的
ACK 包。
服务器端接收到这个确认包之后,关闭连接,进⼊ CLOSED 状态。
客户端等待了某个固定时间(两个最⼤段⽣命周期,2MSL,2 Maximum Segment Lifetime)之后,没有收到服务器端的 ACK ,认为服务器端已经正常关闭连接,于是⾃⼰也关闭连接,进⼊ CLOSED 状态。
四次挥⼿的示意图如下:
参考:
DOM
DOM的事件模型是什么? DOM的事件流是什么? 什么是事件委托?
前端框架⼤⾏其道的今天,我们直接操作DOM的时候变得更少了,因此不妨复习⼀下DOM的基本知识
DOM的事件模型是什么?
DOM之事件模型分脚本模型、内联模型(同类⼀个,后者覆盖)、动态绑定(同类多个)
DOM的事件流是什么?
事件就是⽂档或浏览器窗⼝中发⽣的⼀些特定的交互瞬间,⽽事件流(⼜叫事件传播)描述的是从⻚⾯中接收事件的顺序。
事件冒泡
事件冒泡(event bubbling),即事件开始时由最具体的元素(⽂档中嵌套层次最深的那个节点)接收,然后逐级向上传播到较为不具体的节点。
看如下例⼦:
如果单击了⻚⾯中的
事件捕获
事件捕获的思想是不太具体的节点应该更早接收到事件,⽽最具体的节点应该最后接收到事件。事件捕获的⽤意在于在事件到达预定⽬标之前就捕获它。
还是以上⼀节的html结构为例:
在事件捕获过程中,document对象⾸先接收到click事件,然后事件沿DOM树依次向下,⼀直传播到事件的实际⽬标, 即
事件流
事件流⼜称为事件传播,DOM2级事件规定的事件流包括三个阶段:事件捕获阶段(capture phase)、处于⽬标阶段(target phase)和事件冒泡阶段(bubbling phase)。
触发顺序通常为
什么是事件委托
事件委托就是利⽤事件冒泡,只指定⼀个事件处理程序,就可以管理某⼀类型的所有事件. 在绑定⼤量事件的时候往往选择事件委托。
优点:
节省内存占⽤,减少事件注册
新增⼦对象时⽆需再次对其绑定事件,适合动态添加元素
局限性:
focus、blur 之类的事件本身没有事件冒泡机制,所以⽆法委托
mousemove、mouseout 这样的事件,虽然有事件冒泡,但是只能不断通过位置去计算定位,对性能消耗⾼,不适合事件委托
浏览器与新技术
常⻅的浏览器内核有哪些?
浏览器的主要组成部分是什么? 浏览器是如何渲染UI的?
浏览器如何解析css选择器? DOM Tree是如何构建的? 浏览器重绘与重排的区别? 如何触发重排和重绘?
如何避免重绘或者重排? 前端如何实现即时通讯? 什么是浏览器同源策略? 如何实现跨域?
本章关于浏览器原理部分的内容主要来源于浏览器⼯作原理,这是⼀篇很⻓的⽂章,可以算上⼀本⼩书了,有精⼒的⾮常建议阅读。
常⻅的浏览器内核有哪些?
浏览器/RunTime 内核(渲染引擎) JavaScript 引擎
Chrome Blink(28~) Webkit(Chrome 27)
V8
FireFox Gecko SpiderMonkey
Safari Webkit JavaScriptCore
Edge EdgeHTML Chakra(for JavaScript)
IE Trident Chakra(for JScript)
PhantomJS Webkit JavaScriptCore
Node.js - V8
浏览器的主要组成部分是什么?
图:浏览器的主要组件。
值得注意的是,和⼤多数浏览器不同,Chrome 浏览器的每个标签⻚都分别对应⼀个呈现引擎实例。每个标签⻚都是⼀个独⽴的进程。
浏览器是如何渲染UI的?
浏览器如何解析css选择器?
浏览器会『从右往左』解析CSS选择器。
我们知道DOM Tree与Style Rules合成为 Render Tree,实际上是需要将Style Rules附着到DOM Tree上,因此需要根据选择器提供的信息对DOM Tree进⾏遍历,才能将样式附着到对应的DOM元素上。
以下这段css为例
我们对应的DOM Tree 如下
若从左向右的匹配,过程是:
DOM Tree是如何构建的?
浏览器重绘与重排的区别?
重排: 部分渲染树(或者整个渲染树)需要重新分析并且节点尺⼨需要重新计算,表现为重新⽣成布局,重新排列元素
重绘: 由于节点的⼏何属性发⽣改变或者由于样式发⽣改变,例如改变元素背景⾊时,屏幕上的部分内容需要更新,表现为某些元素的外观被改变
单单改变元素的外观,肯定不会引起⽹⻚重新⽣成布局,但当浏览器完成重排之后,将会重新绘制受到此次重排影响的部分
重排和重绘代价是⾼昂的,它们会破坏⽤户体验,并且让UI展示⾮常迟缓,⽽相⽐之下重排的性能影响更⼤,在两者⽆法避免的情况下,⼀般我们宁可选择代价更⼩的重绘。
『重绘』不⼀定会出现『重排』,『重排』必然会出现『重绘』。
如何触发重排和重绘?
任何改变⽤来构建渲染树的信息都会导致⼀次重排或重绘: 添加、删除、更新DOM节点
通过display: none隐藏⼀个DOM节点-触发重排和重绘
通过visibility: hidden隐藏⼀个DOM节点-只触发重绘,因为没有⼏何变化移动或者给⻚⾯中的DOM节点添加动画
添加⼀个样式表,调整样式属性
⽤户⾏为,例如调整窗⼝⼤⼩,改变字号,或者滚动。
如何避免重绘或者重排?
集中改变样式
我们往往通过改变class的⽅式来集中改变样式
使⽤DocumentFragment
我们可以通过createDocumentFragment创建⼀个游离于DOM树之外的节点,然后在此节点上批量操作,最后插⼊
DOM树中,因此只触发⼀次重排
提升为合成层
将元素提升为合成层有以下优点:
合成层的位图,会交由 GPU 合成,⽐ CPU 处理要快
当需要 repaint 时,只需要 repaint 本身,不会影响到其他的层对于 transform 和 opacity 效果,不会触发 layout 和 paint
提升合成层的最好⽅式是使⽤ CSS 的 will-change 属性:
关于合成层的详解请移步⽆线性能优化:Composite
前端如何实现即时通讯?
短轮询
短轮询的原理很简单,每隔⼀段时间客户端就发出⼀个请求,去获取服务器最新的数据,⼀定程度上模拟实现了即时通讯。
优点:兼容性强,实现⾮常简单
缺点:延迟性⾼,⾮常消耗请求资源,影响性能
comet
comet有两种主要实现⼿段,⼀种是基于 AJAX 的⻓轮询(long-polling)⽅式,另⼀种是基于 Iframe 及 htmlfile 的流
(streaming)⽅式,通常被叫做⻓连接。
具体两种⼿段的操作⽅法请移步Comet技术详解:基于HTTP⻓连接的Web端实时通信技术
⻓轮询优缺点:
优点:兼容性好,资源浪费较⼩
缺点:服务器hold连接会消耗资源,返回数据顺序⽆保证,难于管理维护
⻓连接优缺点:
优点:兼容性好,消息即时到达,不发⽆⽤请求缺点:服务器维护⻓连接消耗资源
SSE
使⽤指南请看Server-Sent Events 教程
SSE(Server-Sent Event,服务端推送事件)是⼀种允许服务端向客户端推送新数据的HTML5技术。
优点:基于HTTP⽽⽣,因此不需要太多改造就能使⽤,使⽤⽅便,⽽websocket⾮常复杂,必须借助成熟的库或框架
缺点:基于⽂本传输效率没有websocket⾼,不是严格的双向通信,客户端向服务端发送请求⽆法复⽤之前的连接,需要重新发出独⽴的请求
Websocket
使⽤指南请看WebSocket 教程
Websocket是⼀个全新的、独⽴的协议,基于TCP协议,与http协议兼容、却不会融⼊http协议,仅仅作为html5的⼀部分,其作⽤就是在服务器和客户端之间建⽴实时的双向通信。
优点:真正意义上的实时双向通信,性能好,低延迟
缺点:独⽴与http的协议,因此需要额外的项⽬改造,使⽤复杂度⾼,必须引⼊成熟的库,⽆法兼容低版本浏览器
Web Worker
后⾯性能优化部分会⽤到,先做了解
Web Worker 的作⽤,就是为 JavaScript 创造多线程环境,允许主线程创建 Worker 线程,将⼀些任务分配给后者运⾏
Web Worker教程
Service workers
后⾯性能优化部分会⽤到,先做了解
Service workers 本质上充当Web应⽤程序与浏览器之间的代理服务器,也可以在⽹络可⽤时作为浏览器和⽹络间的代理,创建有效的离线体验。
Service workers教程
什么是浏览器同源策略?
同源策略限制了从同⼀个源加载的⽂档或脚本如何与来⾃另⼀个源的资源进⾏交互。这是⼀个⽤于隔离潜在恶意⽂件的重要安全机制。
同源是指"协议+域名+端⼝"三者相同,即便两个不同的域名指向同⼀个ip地址,也⾮同源。下表给出了相对http://store.company.com/dir/page.html同源检测的示例:
浏览器中的⼤部分内容都是受同源策略限制的,但是以下三个标签可以不受限制:
如何实现跨域?
跨域是个⽐较古⽼的命题了,历史上跨域的实现⼿段有很多,我们现在主要介绍三种⽐较主流的跨域⽅案,其余的⽅案我们就不深⼊讨论了,因为使⽤场景很少,也没必要记这么多奇技淫巧。
最经典的跨域⽅案jsonp
jsonp本质上是⼀个Hack,它利⽤
最流⾏的跨域⽅案cors
cors是⽬前主流的跨域解决⽅案,跨域资源共享(CORS) 是⼀种机制,它使⽤额外的 HTTP 头来告诉浏览器 让运⾏在⼀个 origin (domain) 上的Web应⽤被准许访问来⾃不同源服务器上的指定的资源。当⼀个资源从与该资源本身所在的服务器不同的域、协议或端⼝请求⼀个资源时,资源会发起⼀个跨域 HTTP 请求。
如果你⽤express,可以这样在后端设置
在⽣产环境中建议⽤成熟的开源中间件解决问题。
最⽅便的跨域⽅案Nginx
nginx是⼀款极其强⼤的web服务器,其优点就是轻量级、启动快、⾼并发。
现在的新项⽬中nginx⼏乎是⾸选,我们⽤node或者java开发的服务通常都需要经过nginx的反向代理。
反向代理的原理很简单,即所有客户端的请求都必须先经过nginx的处理,nginx作为代理服务器再讲请求转发给node或者java服务,这样就规避了同源策略。
其它跨域⽅案
参考⽂章:
为什么 CSS 选择器解析的时候是从右往左?
前端⼯程化
Babel的原理是什么?
babel 的转译过程也分为三个阶段,这三步具体是:
解析 Parse: 将代码解析⽣成抽象语法树( 即AST ),即词法分析与语法分析的过程
转换 Transform: 对于 AST 进⾏变换⼀系列的操作,babel 接受得到 AST 并通过 babel-traverse 对其进⾏遍历,在此过程中进⾏添加、更新及移除等操作
⽣成 Generate: 将变换后的 AST 再转换为 JS 代码, 使⽤到的模块是 babel-generator
更具体的原理可以移步如何写⼀个babel
如何写⼀个babel插件?
Babel解析成AST,然后插件更改AST,最后由Babel输出代码
那么Babel的插件模块需要你暴露⼀个function,function内返回visitor
visitor是对各类型的AST节点做处理的地⽅,那么我们怎么知道Babel⽣成了的AST有哪些节点呢? 很简单,你可以把Babel转换的结果打印出来,或者这⾥有传送⻔: AST explorer
这⾥我们看到 const result = 1 + 2 中的 1 + 1 是⼀个 BinaryExpression 节点,那么在visitor中,我们就处理这个节点
插件写好了,我们运⾏下插件试试
与预期⼀致,那么转换 const result = 1 + 2 + 3 + 4 + 5; 呢?
结果是: const result = 3 + 3 + 4 + 5;
这就奇怪了,为什么只计算了 1 + 2 之后,就没有继续往下运算了? 我们看⼀下这个表达式的AST树
你会发现Babel解析成表达式⾥⾯再嵌套表达式。
⽽我们的判断条件并不符合所有的,只符合 1 + 2
那么我们得改⼀改
第⼀次计算 1 + 2 之后,我们会得到这样的表达式
其中 3 + 3 ⼜符合了我们的条件, 我们通过向上递归的⽅式遍历⽗级节点
⼜转换成这样:
到这⾥,我们就得出了结果 const result = 15;
那么其他运算呢:
const result = 100 + 10 - 50 >>> const result = 60;
const result = (100 / 2) + 50 >>> const result = 100;
const result = (((100 / 2) + 50 * 2) / 50) ** 2 >>> const result = 9;
项⽬地址
上述答案来源于cnode帖⼦
更详实的教程移步官⽅的插件教程
你的git⼯作流是怎样的?
GitFlow 是由 Vincent Driessen 提出的⼀个 git操作流程标准。包含如下⼏个关键分⽀:
名称 说明
master 主分⽀
develop 主开发分⽀,包含确定即将发布的代码
feature 新功能分⽀,⼀般⼀个新功能对应⼀个分⽀,对于功能的拆分需要⽐较合理,以避免⼀些后⾯不必要的代码冲突
release 发布分⽀,发布时候⽤的分⽀,⼀般测试时候发现的 bug 在这个分⽀进⾏修复
hotfix hotfix 分⽀,紧急修 bug 的时候⽤
GitFlow 的优势有如下⼏点:
并⾏开发:GitFlow 可以很⽅便的实现并⾏开发:每个新功能都会建⽴⼀个新的 feature 分⽀,从⽽和已经完成的功能隔离开来,⽽且只有在新功能完成开发的情况下,其对应的 feature 分⽀才会合并到主开发分⽀上(也就
是我们经常说的 develop 分⽀)。另外,如果你正在开发某个功能,同时⼜有⼀个新的功能需要开发,你只需要提交当前 feature 的代码,然后创建另外⼀个 feature 分⽀并完成新功能开发。然后再切回之前的 feature 分
⽀即可继续完成之前功能的开发。
协作开发:GitFlow 还⽀持多⼈协同开发,因为每个 feature 分⽀上改动的代码都只是为了让某个新的 feature
可以独⽴运⾏。同时我们也很容易知道每个⼈都在⼲啥。
发布阶段:当⼀个新 feature 开发完成的时候,它会被合并到 develop 分⽀,这个分⽀主要⽤来暂时保存那些还没有发布的内容,所以如果需要再开发新的 feature ,我们只需要从 develop 分⽀创建新分⽀,即可包含所有已经完成的 feature 。
⽀持紧急修复:GitFlow 还包含了 hotfix 分⽀。这种类型的分⽀是从某个已经发布的 tag 上创建出来并做⼀个紧急的修复,⽽且这个紧急修复只影响这个已经发布的 tag,⽽不会影响到你正在开发的新 feature 。
然后就是 GitFlow 最经典的⼏张流程图,⼀定要理解:
feature 分⽀都是从 develop 分⽀创建,完成后再合并到 develop 分⽀上,等待发布。
当需要发布时,我们从 develop 分⽀创建⼀个 release 分⽀
然后这个 release 分⽀会发布到测试环境进⾏测试,如果发现问题就在这个分⽀直接进⾏修复。在所有问题修复之
前,我们会不停的重复发布->测试->修复->重新发布->重新测试这个流程。
发布结束后,这个 release 分⽀会合并到 develop 和 master 分⽀,从⽽保证不会有代码丢失。
master 分⽀只跟踪已经发布的代码,合并到 master 上的 commit 只能来⾃ release 分⽀和 hotfix 分⽀。
hotfix 分⽀的作⽤是紧急修复⼀些 Bug。
它们都是从 master 分⽀上的某个 tag 建⽴,修复结束后再合并到 develop 和 master 分⽀上。
更多⼯作流可以参考阮⽼师的Git ⼯作流程
rebase 与 merge的区别?
git rebase 和 git merge ⼀样都是⽤于从⼀个分⽀获取并且合并到当前分⽀.
假设⼀个场景,就是我们开发的[feature/todo]分⽀要合并到master主分⽀,那么⽤rebase或者merge有什么不同呢?
marge 特点:⾃动创建⼀个新的commit 如果合并的时候遇到冲突,仅需要修改后重新commit 优点:记录了真实的commit情况,包括每个分⽀的详情
缺点:因为每次merge会⾃动产⽣⼀个merge commit,所以在使⽤⼀些git 的GUI tools,特别是commit⽐较频繁时,看到分⽀很杂乱。
rebase 特点:会合并之前的commit历史
优点:得到更简洁的项⽬历史,去掉了merge commit
缺点:如果合并出现代码问题不容易定位,因为re-write了history
因此,当需要保留详细的合并信息的时候建议使⽤git merge,特别是需要将分⽀合并进⼊master分⽀时;当发现⾃⼰修改某个功能时,频繁进⾏了git commit提交时,发现其实过多的提交信息没有必要时,可以尝试git rebase.
git reset、git revert 和 git checkout 有什么区别
这个问题同样也需要先了解 git 仓库的三个组成部分:⼯作区(Working Directory)、暂存区(Stage)和历史记录区
(History)。
⼯作区:在 git 管理下的正常⽬录都算是⼯作区,我们平时的编辑⼯作都是在⼯作区完成暂存区:临时区域。⾥⾯存放将要提交⽂件的快照
历史记录区:git commit 后的记录区
三个区的转换关系以及转换所使⽤的命令:
git reset、git revert 和 git checkout的共同点:⽤来撤销代码仓库中的某些更改。然后是不同点:
⾸先,从 commit 层⾯来说:
git reset 可以将⼀个分⽀的末端指向之前的⼀个 commit。然后再下次 git 执⾏垃圾回收的时候,会把这个 commit
之后的 commit 都扔掉。git reset 还⽀持三种标记,⽤来标记 reset 指令影响的范围:
–mixed:会影响到暂存区和历史记录区。也是默认选项
–soft:只影响历史记录区
–hard:影响⼯作区、暂存区和历史记录区
注意:因为 git reset 是直接删除 commit 记录,从⽽会影响到其他开发⼈员的分⽀,所以不要在公共分⽀(⽐如
develop)做这个操作。
git checkout 可以将 HEAD 移到⼀个新的分⽀,并更新⼯作⽬录。因为可能会覆盖本地的修改,所以执⾏这个指令之前,你需要 stash 或者 commit 暂存区和⼯作区的更改。
git revert 和 git reset 的⽬的是⼀样的,但是做法不同,它会以创建新的 commit 的⽅式来撤销 commit,这样能保留之前的 commit 历史,⽐较安全。另外,同样因为可能会覆盖本地的修改,所以执⾏这个指令之前,你需要stash 或者 commit 暂存区和⼯作区的更改。
然后,从⽂件层⾯来说:
git reset 只是把⽂件从历史记录区拿到暂存区,不影响⼯作区的内容,⽽且不⽀持 --mixed、–soft 和 --hard。git checkout 则是把⽂件从历史记录拿到⼯作区,不影响暂存区的内容。
git revert 不⽀持⽂件层⾯的操作。
React⾯试题
React最新的⽣命周期是怎样的?
React 16之后有三个⽣命周期被废弃(但并未删除)
componentWillMount componentWillReceiveProps componentWillUpdate
官⽅计划在17版本完全删除这三个函数,只保留UNSAVE_前缀的三个函数,⽬的是为了向下兼容,但是对于开发者⽽
⾔应该尽量避免使⽤他们,⽽是使⽤新增的⽣命周期函数替代它们
⽬前React 16.8 +的⽣命周期分为三个阶段,分别是挂载阶段、更新阶段、卸载阶段挂载阶段:
constructor: 构造函数,最先被执⾏,我们通常在构造函数⾥初始化state对象或者给⾃定义⽅法绑定this getDerivedStateFromProps: static getDerivedStateFromProps(nextProps, prevState) ,这是个静态⽅法,当我们接收到新的属性想去修改我们state,可以使⽤getDerivedStateFromProps
render: render函数是纯函数,只返回需要渲染的东⻄,不应该包含其它的业务逻辑,可以返回原⽣的DOM、React
组件、Fragment、Portals、字符串和数字、Boolean和null等内容
componentDidMount: 组件装载之后调⽤,此时我们可以获取到DOM节点并操作,⽐如对canvas,svg的操作,服务器请求,订阅都可以写在这个⾥⾯,但是记得在componentWillUnmount中取消订阅
更新阶段:
getDerivedStateFromProps: 此⽅法在更新个挂载阶段都可能会调⽤
shouldComponentUpdate: shouldComponentUpdate(nextProps, nextState) ,有两个参数nextProps和nextState,表示新的属性和变化之后的state,返回⼀个布尔值,true表示会触发重新渲染,false表示不会触发重新渲染,默认返回true,我们通常利⽤此⽣命周期来优化React程序性能
render: 更新阶段也会触发此⽣命周期
getSnapshotBeforeUpdate: getSnapshotBeforeUpdate(prevProps, prevState) , 这 个 ⽅ 法 在 render 之 后 , componentDidUpdate之前调⽤,有两个参数prevProps和prevState,表示之前的属性和之前的state,这个函数有
⼀个返回值,会作为第三个参数传给componentDidUpdate,如果你不想要返回值,可以返回null,此⽣命周期必须与componentDidUpdate搭配使⽤
componentDidUpdate: componentDidUpdate(prevProps, prevState, snapshot) ,该⽅法在getSnapshotBeforeUpdate
⽅法之后被调⽤,有三个参数prevProps,prevState,snapshot,表示之前的props,之前的state,和snapshot。 第三个参数是getSnapshotBeforeUpdate返回的,如果触发某些回调函数时需要⽤到 DOM 元素的状态,则将对⽐或计算的过程迁移⾄ getSnapshotBeforeUpdate,然后在 componentDidUpdate 中统⼀触发回调或更新状态。
卸载阶段:
componentWillUnmount: 当我们的组件被卸载或者销毁了就会调⽤,我们可以在这个函数⾥去清除⼀些定时器,取消⽹络请求,清理⽆效的DOM元素等垃圾清理⼯作
⼀个查看react⽣命周期的⽹站
React的请求应该放在哪个⽣命周期中?
React的异步请求到底应该放在哪个⽣命周期⾥,有⼈认为在 componentWillMount 中可以提前进⾏异步请求,避免⽩屏,其实这个观点是有问题的.
由于JavaScript中异步事件的性质,当您启动API调⽤时,浏览器会在此期间返回执⾏其他⼯作。当React渲染⼀个组件时,它不会等待componentWillMount它完成任何事情 - React继续前进并继续render,没有办法“暂停”渲染以等待数据到达。
⽽且在 componentWillMount 请求会有⼀系列潜在的问题,⾸先,在服务器渲染时,如果在 componentWillMount ⾥获取数据,fetch data会执⾏两次,⼀次在服务端⼀次在客户端,这造成了多余的请求,其次,在React 16进⾏React Fiber重写后, componentWillMount 可能在⼀次渲染中多次调⽤.
⽬前官⽅推荐的异步请求是在 componentDidmount 中进⾏.
如果有特殊需求需要提前请求,也可以在特殊情况下在 constructor 中请求:
react 17之后 componentWillMount 会被废弃,仅仅保留 UNSAFE_componentWillMount
setState到底是异步还是同步?
先给出答案: 有时表现出异步,有时表现出同步
React组件通信如何实现?
React组件间通信⽅式:
⽗组件向⼦组件通讯: ⽗组件可以向⼦组件通过传 props 的⽅式,向⼦组件进⾏通讯
⼦组件向⽗组件通讯: props+回调的⽅式,⽗组件向⼦组件传递props进⾏通讯,此props为作⽤域为⽗组件⾃身的函数,⼦组件调⽤该函数,将⼦组件想要传递的信息,作为参数,传递到⽗组件的作⽤域中
兄弟组件通信: 找到这两个兄弟节点共同的⽗节点,结合上⾯两种⽅式由⽗节点转发信息进⾏通信
跨层级通信: Context 设计⽬的是为了共享那些对于⼀个组件树⽽⾔是“全局”的数据,例如当前认证的⽤户、主题或⾸选语⾔,对于跨越多层的全局数据通过 Context 通信再适合不过
发布订阅模式: 发布者发布事件,订阅者监听事件并做出反应,我们可以通过引⼊event模块进⾏通信
全局状态管理⼯具: 借助Redux或者Mobx等全局状态管理⼯具进⾏通信,这种⼯具会维护⼀个全局状态中⼼Store,并根据不同的事件产⽣新的状态
React有哪些优化性能是⼿段?
性能优化的⼿段很多时候是通⽤的详情⻅前端性能优化加载篇
React如何进⾏组件/逻辑复⽤?
抛开已经被官⽅弃⽤的Mixin,组件抽象的技术⽬前有三种⽐较主流:
⾼阶组件:
属性代理反向继承
渲染属性
react-hooks
组件复⽤详解⻅组件复⽤
mixin、hoc、render props、react-hooks的优劣如何?
Mixin的缺陷:
组件与 Mixin 之间存在隐式依赖(Mixin 经常依赖组件的特定⽅法,但在定义组件时并不知道这种依赖关系) 多个 Mixin 之间可能产⽣冲突(⽐如定义了相同的state字段)
Mixin 倾向于增加更多状态,这降低了应⽤的可预测性(The more state in your application, the harder it is to reason about it.),导致复杂度剧增
隐式依赖导致依赖关系不透明,维护成本和理解成本迅速攀升:
难以快速理解组件⾏为,需要全盘了解所有依赖 Mixin 的扩展⾏为,及其之间的相互影响
组价⾃身的⽅法和state字段不敢轻易删改,因为难以确定有没有 Mixin 依赖它
Mixin 也难以维护,因为 Mixin 逻辑最后会被打平合并到⼀起,很难搞清楚⼀个 Mixin 的输⼊输出
HOC相⽐Mixin的优势:
HOC通过外层组件通过 Props 影响内层组件的状态,⽽不是直接改变其 State不存在冲突和互相⼲扰,这就降低了耦合度
不同于 Mixin 的打平+合并,HOC 具有天然的层级结构(组件树结构),这⼜降低了复杂度
HOC的缺陷:
扩展性限制: HOC ⽆法从外部访问⼦组件的 State因此⽆法通过shouldComponentUpdate滤掉不必要的更新,React
在⽀持 ES6 Class 之后提供了React.PureComponent来解决这个问题
Ref 传递问题: Ref 被隔断,后来的React.forwardRef 来解决这个问题
Wrapper Hell: HOC可能出现多层包裹组件的情况,多层抽象同样增加了复杂度和理解成本命名冲突: 如果⾼阶组件多次嵌套,没有使⽤命名空间的话会产⽣冲突,然后覆盖⽼属性
不可⻅性: HOC相当于在原有组件外层再包装⼀个组件,你压根不知道外层的包装是啥,对于你是⿊盒
Render Props优点:
上述HOC的缺点Render Props都可以解决
Render Props缺陷:
使⽤繁琐: HOC使⽤只需要借助装饰器语法通常⼀⾏代码就可以进⾏复⽤,Render Props⽆法做到如此简单嵌套过深: Render Props虽然摆脱了组件多层嵌套的问题,但是转化为了函数回调的嵌套
React Hooks优点:
简洁: React Hooks解决了HOC和Render Props的嵌套问题,更加简洁解耦: React Hooks可以更⽅便地把 UI 和状态分离,做到更彻底的解耦组合: Hooks 中可以引⽤另外的 Hooks形成新的Hooks,组合变化万千函数友好: React Hooks为函数组件⽽⽣,从⽽解决了类组件的⼏⼤问题:
this 指向容易错误
分割在不同声明周期中的逻辑使得代码难以理解和维护代码复⽤成本⾼(⾼阶组件容易使代码量剧增)
React Hooks缺陷:
额外的学习成本(Functional Component 与 Class Component 之间的困惑)
写法上有限制(不能出现在条件、循环中),并且写法限制增加了重构成本
破坏了PureComponent、React.memo浅⽐较的性能优化效果(为了取最新的props和state,每次render()都要重新创建事件处函数)
在闭包场景可能会引⽤到旧的state、props值
内部实现上不直观(依赖⼀份可变的全局状态,不再那么“纯”)
React.memo并不能完全替代shouldComponentUpdate(因为拿不到 state change,只针对 props change) 关于react-hooks的评价来源于官⽅react-hooks RFC
你是如何理解fiber的?
React Fiber 是⼀种基于浏览器的单线程调度算法.
React 16之前 , reconcilation 算法实际上是递归,想要中断递归是很困难的,React 16 开始使⽤了循环来代替之前的递归.
Fiber :⼀种将 recocilation (递归 diff),拆分成⽆数个⼩任务的算法;它随时能够停⽌,恢复。停⽌恢复的时机取决于当前的⼀帧(16ms)内,还有没有⾜够的时间允许计算。
你对 Time Slice的理解?
时间分⽚
React 在渲染(render)的时候,不会阻塞现在的线程如果你的设备⾜够快,你会感觉渲染是同步的
如果你设备⾮常慢,你会感觉还算是灵敏的
虽然是异步渲染,但是你将会看到完整的渲染,⽽不是⼀个组件⼀⾏⾏的渲染出来同样书写组件的⽅式
也就是说,这是React背后在做的事情,对于我们开发者来说,是透明的,具体是什么样的效果呢?
有图表三个图表,有⼀个输⼊框,以及上⾯的三种模式
这个组件⾮常的巨⼤,⽽且在输⼊框每次输⼊东⻄的时候,就会进去⼀直在渲染。为了更好的看到渲染的性能,Dan为我们做了⼀个表。
我们先看看,同步模式:
同步模式下,我们都知道,我们没输⼊⼀个字符,React就开始渲染,当React渲染⼀颗巨⼤的树的时候,是⾮常卡的,
所以才会有shouldUpdate的出现,在这⾥Dan也展示了,这种卡!
我们再来看看第⼆种(Debounced模式):
Debounced模式简单的来说,就是延迟渲染,⽐如,当你输⼊完成以后,再开始渲染所有的变化。
这么做的坏处就是,⾄少不会阻塞⽤户的输⼊了,但是依然有⾮常严重的卡顿。
切换到异步模式:
异步渲染模式就是不阻塞当前线程,继续跑。在视频⾥可以看到所有的输⼊,表上都会是原谅⾊的。
时间分⽚正是基于可随时打断、重启的Fiber架构,可打断当前任务,优先处理紧急且重要的任务,保证⻚⾯的流畅运⾏.
redux的⼯作流程?
⾸先,我们看下⼏个核⼼概念:
Store:保存数据的地⽅,你可以把它看成⼀个容器,整个应⽤只能有⼀个Store。
State:Store对象包含所有数据,如果想得到某个时点的数据,就要对Store⽣成快照,这种时点的数据集合,就叫
做State。
Action:State的变化,会导致View的变化。但是,⽤户接触不到State,只能接触到View。所以,State的变化必须是View导致的。Action就是View发出的通知,表示State应该要发⽣变化了。
Action Creator:View要发送多少种消息,就会有多少种Action。如果都⼿写,会很麻烦,所以我们定义⼀个函数来⽣成Action,这个函数就叫Action Creator。
Reducer:Store收到Action以后,必须给出⼀个新的State,这样View才会发⽣变化。这种State的计算过程就叫做Reducer。Reducer是⼀个函数,它接受Action和当前State作为参数,返回⼀个新的State。
dispatch:是View发出Action的唯⼀⽅法。
然后我们过下整个⼯作流程:
react-redux是如何⼯作的?
Provider: Provider的作⽤是从最外部封装了整个应⽤,并向connect模块传递store connect: 负责连接React和Redux
获取state: connect通过context获取Provider中的store,通过store.getState()获取整个store tree 上所有state 包装原组件: 将state和action通过props的⽅式传⼊到原组件内部wrapWithConnect返回⼀个ReactComponent 对象Connect,Connect重新render外部传⼊的原组件WrappedComponent,并把connect中传⼊的mapStateToProps, mapDispatchToProps与组件上原有的props合并后,通过属性的⽅式传给
WrappedComponent
监听store tree变化: connect缓存了store tree中state的状态,通过当前state状态和变更前state状态进⾏⽐较,从
⽽确定是否调⽤ this.setState() ⽅法触发Connect及其⼦组件的重新渲染
redux与mobx的区别?
两者对⽐:
redux将数据保存在单⼀的store中,mobx将数据保存在分散的多个store中
redux使⽤plain object保存数据,需要⼿动处理变化后的操作;mobx适⽤observable保存数据,数据变化后⾃动处理响应的操作
redux使⽤不可变状态,这意味着状态是只读的,不能直接去修改它,⽽是应该返回⼀个新的状态,同时使⽤纯函数;mobx中的状态是可变的,可以直接对其进⾏修改
mobx相对来说⽐较简单,在其中有很多的抽象,mobx更多的使⽤⾯向对象的编程思维;redux会⽐较复杂,因为其中的函数式编程思想掌握起来不是那么容易,同时需要借助⼀系列的中间件来处理异步和副作⽤
mobx中有更多的抽象和封装,调试会⽐较困难,同时结果也难以预测;⽽redux提供能够进⾏时间回溯的开发⼯具,同时其纯函数以及更少的抽象,让调试变得更加的容易
场景辨析:
基于以上区别,我们可以简单得分析⼀下两者的不同使⽤场景.
mobx更适合数据不复杂的应⽤: mobx难以调试,很多状态⽆法回溯,⾯对复杂度⾼的应⽤时,往往⼒不从⼼.
redux适合有回溯需求的应⽤: ⽐如⼀个画板应⽤、⼀个表格应⽤,很多时候需要撤销、重做等操作,由于redux不可变的特性,天然⽀持这些操作.
mobx适合短平快的项⽬: mobx上⼿简单,样板代码少,可以很⼤程度上提⾼开发效率.
当然mobx和redux也并不⼀定是⾮此即彼的关系,你也可以在项⽬中⽤redux作为全局状态管理,⽤mobx作为组件局部状态管理器来⽤.
redux中如何进⾏异步操作?
当然,我们可以在 componentDidmount 中直接进⾏请求⽆须借助redux.
但是在⼀定规模的项⽬中,上述⽅法很难进⾏异步流的管理,通常情况下我们会借助redux的异步中间件进⾏异步处理. redux异步流中间件其实有很多,但是当下主流的异步中间件只有两种redux-thunk、redux-saga,当然redux-observable
可能也有资格占据⼀席之地,其余的异步中间件不管是社区活跃度还是npm下载量都⽐较差了.
redux异步中间件之间的优劣?
redux-thunk优点:
体积⼩: redux-thunk的实现⽅式很简单,只有不到20⾏代码
使⽤简单: redux-thunk没有引⼊像redux-saga或者redux-observable额外的范式,上⼿简单
redux-thunk缺陷:
样板代码过多: 与redux本身⼀样,通常⼀个请求需要⼤量的代码,⽽且很多都是重复性质的耦合严重: 异步操作与redux的action偶合在⼀起,不⽅便管理
功能孱弱: 有⼀些实际开发中常⽤的功能需要⾃⼰进⾏封装
redux-saga优点:
异步解耦: 异步操作被被转移到单独 saga.js 中,不再是掺杂在 action.js 或 component.js 中
action摆脱thunk function: dispatch 的参数依然是⼀个纯粹的 action (FSA),⽽不是充满 “⿊魔法” thunk function 异常处理: 受益于 generator function 的 saga 实现,代码异常/请求失败 都可以直接通过 try/catch 语法直接捕获处理
功能强⼤: redux-saga提供了⼤量的Saga 辅助函数和Effect 创建器供开发者使⽤,开发者⽆须封装或者简单封装即可使⽤
灵活: redux-saga可以将多个Saga可以串⾏/并⾏组合起来,形成⼀个⾮常实⽤的异步flow
易测试,提供了各种case的测试⽅案,包括mock task,分⽀覆盖等等
redux-saga缺陷:
额外的学习成本: redux-saga不仅在使⽤难以理解的 generator function,⽽且有数⼗个API,学习成本远超redux- thunk,最重要的是你的额外学习成本是只服务于这个库的,与redux-observable不同,redux-observable虽然也有额外学习成本但是背后是rxjs和⼀整套思想
体积庞⼤: 体积略⼤,代码近2000⾏,min版25KB左右
功能过剩: 实际上并发控制等功能很难⽤到,但是我们依然需要引⼊这些代码
ts⽀持不友好: yield⽆法返回TS类型
redux-observable优点:
功能最强: 由于背靠rxjs这个强⼤的响应式编程的库,借助rxjs的操作符,你可以⼏乎做任何你能想到的异步处理
背靠rxjs: 由于有rxjs的加持,如果你已经学习了rxjs,redux-observable的学习成本并不⾼,⽽且随着rxjs的升级redux- observable也会变得更强⼤
redux-observable缺陷:
学习成本奇⾼: 如果你不会rxjs,则需要额外学习两个复杂的库
社区⼀般: redux-observable的下载量只有redux-saga的1/5,社区也不够活跃,在复杂异步流中间件这个层⾯redux- saga仍处于领导地位
关于redux-saga与redux-observable的详细⽐较可⻅此链接
Vue⾯试题
Vue框架部分我们会涉及⼀些⾼频且有⼀定探讨价值的⾯试题,我们不会涉及⼀些⾮常初级的在官⽅⽂档就能查看的纯记忆性质的⾯试题,⽐如:
vue常⽤的修饰符?
vue-cli ⼯程常⽤的 npm 命令有哪些?
vue中 keep-alive 组件的作⽤?
⾸先,上述类型的⾯试题在⽂档中可查,没有⽐官⽅⽂档更权威的答案了,其次这种问题没有太⼤价值,除了考察候选⼈的记忆⼒,最后,这种⾯试题只要⽤过vue的都知道,没有必要占⽤我们的篇幅.
我们的问题并不多,但是难度可能会⾼⼀些,如果你真的搞懂了这些问题,在绝⼤多数情况下会有举⼀反三的效果,可以说基本能拿下Vue相关的所有重要知识点了.
你对MVVM的理解?
MVVM是什么?
MVVM 模式,顾名思义即 Model-View-ViewModel 模式。它萌芽于2005年微软推出的基于 Windows 的⽤户界⾯框架
WPF ,前端最早的 MVVM 框架 knockout 在2010年发布。
Model 层: 对应数据层的域模型,它主要做域模型的同步。通过 Ajax/fetch 等 API 完成客户端和服务端业务 Model 的同步。在层间关系⾥,它主要⽤于抽象出 ViewModel 中视图的 Model。
View 层:作为视图模板存在,在 MVVM ⾥,整个 View 是⼀个动态模板。除了定义结构、布局外,它展示的是ViewModel 层的数据和状态。View 层不负责处理状态,View 层做的是 数据绑定的声明、 指令的声明、 事件绑定的声明。
ViewModel 层:把 View 需要的层数据暴露,并对 View 层的 数据绑定声明、 指令声明、 事件绑定声明 负责,也就是处理 View 层的具体业务逻辑。ViewModel 底层会做好绑定属性的监听。当 ViewModel 中数据变化,View 层会得到更 新;⽽当 View 中声明了数据的双向绑定(通常是表单元素),框架也会监听 View 层(表单)值的变化。⼀旦值变化,View 层绑定的 ViewModel 中的数据也会得到⾃动更新。
MVVM的优缺点?
优点:
你对Vue⽣命周期的理解?
⽣命周期是什么
Vue 实例有⼀个完整的⽣命周期,也就是从开始创建、初始化数据、编译模版、挂载Dom -> 渲染、更新 -> 渲染、卸载等⼀系列过程,我们称这是Vue的⽣命周期。
各个⽣命周期的作⽤
⽣命周期 描述
beforeCreate 组件实例被创建之初,组件的属性⽣效之前
created 组件实例已经完全创建,属性也绑定,但真实dom还没有⽣成, e l 还 不 可 ⽤ b e f o r e M o u n t 在 挂 载 开 始 之 前 被 调 ⽤ : 相 关 的 r e n d e r 函 数 ⾸ 次 被 调 ⽤ m o u n t e d e l 被 新 创 建 的 v m . el 还不可⽤ beforeMount 在挂载开始之前被调⽤:相关的 render 函数⾸次被调⽤ mounted el 被新创建的 vm. el还不可⽤beforeMount在挂载开始之前被调⽤:相关的render函数⾸次被调⽤mountedel被新创建的vm.el 替换,并挂载到实例上去之后调⽤该钩⼦
beforeUpdate 组件数据更新之前调⽤,发⽣在虚拟 DOM 打补丁之前
update 组件数据更新之后
activited keep-alive专属,组件被激活时调⽤
deadctivated keep-alive专属,组件被销毁时调⽤
beforeDestory 组件销毁前调⽤
destoryed 组件销毁后调⽤
⽣命周期示意图
异步请求适合在哪个⽣命周期调⽤?
官⽅实例的异步请求是在mounted⽣命周期中调⽤的,⽽实际上也可以在created⽣命周期中调⽤。
Vue组件如何通信?
Vue组件通信的⽅法如下:
props/ e m i t + v − o n : 通 过 p r o p s 将 数 据 ⾃ 上 ⽽ 下 传 递 , ⽽ 通 过 emit+v-on: 通过props将数据⾃上⽽下传递,⽽通过 emit+v−on:通过props将数据⾃上⽽下传递,⽽通过emit和v-on来向上传递信息。
EventBus: 通过EventBus进⾏信息的发布与订阅
vuex: 是全局数据管理库,可以通过vuex管理全局的数据流
a t t r s / attrs/ attrs/listeners: Vue2.4中加⼊的 a t t r s / attrs/ attrs/listeners可以进⾏跨级的组件通信
provide/inject:以允许⼀个祖先组件向其所有⼦孙后代注⼊⼀个依赖,不论组件层次有多深,并在起上下游关系成
⽴的时间⾥始终⽣效,这成为了跨组件通信的基础
还有⼀些⽤solt插槽或者ref实例进⾏通信的,使⽤场景过于有限就不赘述了。
详细可以参考这篇⽂章vue中8种组件通信⽅式,不过太偏⻔的通信⽅式根本不会⽤到,单做知识点了解即可
computed和watch有什么区别?
computed:
computed 是计算属性,也就是计算值,它更多⽤于计算值的场景
computed 具有缓存性,computed的值在getter执⾏后是会缓存的,只有在它依赖的属性值改变之后,下⼀次获取
computed的值时才会重新调⽤对应的getter来计算
computed 适⽤于计算⽐较消耗性能的计算场景
watch:
更多的是「观察」的作⽤,类似于某些数据的监听回调,⽤于观察
⾏回调进⾏后续操作
⽆缓存性,⻚⾯重新渲染时值不变化也会执⾏
或者本组件的值,当数据变化时来执
⼩结:
Vue是如何实现双向绑定的?
利⽤ Object.defineProperty 劫持对象的访问器,在属性值发⽣变化时我们可以获取变化,然后根据变化进⾏后续响应,在
vue3.0中通过Proxy代理对象进⾏类似的操作。
详细实现⻅Proxy⽐defineproperty优劣对⽐?
Proxy与Object.defineProperty的优劣对⽐?
Proxy的优势如下:
Proxy可以直接监听对象⽽⾮属性Proxy可以直接监听数组的变化
Proxy有多达13种拦截⽅法,不限于apply、ownKeys、deleteProperty、has等等是 Object.defineProperty 不具备的Proxy返回的是⼀个新对象,我们可以只操作新的对象达到⽬的,⽽ Object.defineProperty 只能遍历对象属性直接修改
Proxy作为新标准将受到浏览器⼚商重点持续的性能优化,也就是传说中的新标准的性能红利
Object.defineProperty的优势如下:
兼容性好,⽀持IE9
详细实现⻅Proxy⽐defineproperty优劣对⽐?
你是如何理解Vue的响应式系统的?
响应式系统简述:
任何⼀个 Vue Component 都有⼀个与之对应的 Watcher 实例。
Vue 的 data 上的属性会被添加 getter 和 setter 属性。
当 Vue Component render 函数被执⾏的时候, data 上会被 触碰(touch), 即被读, getter ⽅法会被调⽤, 此时 Vue 会
去记录此 Vue component 所依赖的所有 data。(这⼀过程被称为依赖收集)
data 被改动时(主要是⽤户操作), 即被写, setter ⽅法会被调⽤, 此时 Vue 会去通知所有依赖于此 data 的组件去调⽤他们的 render 函数进⾏更新。
深⼊响应式系统
既然Vue通过数据劫持可以精准探测数据变化,为什么还需要虚拟
DOM进⾏diff检测差异?
考点: Vue的变化侦测原理
前置知识: 依赖收集、虚拟DOM、响应式系统
现代前端框架有两种⽅式侦测变化,⼀种是pull⼀种是push
pull: 其代表为React,我们可以回忆⼀下React是如何侦测到变化的,我们通常会⽤ setState API显式更新,然后React会进
⾏⼀层层的Virtual Dom Diff操作找出差异,然后Patch到DOM上,React从⼀开始就不知道到底是哪发⽣了变化,只是知道
「有变化了」,然后再进⾏⽐较暴⼒的Diff操作查找「哪发⽣变化了」,另外⼀个代表就是Angular的脏检查操作。
push: Vue的响应式系统则是push的代表,当Vue程序初始化的时候就会对数据data进⾏依赖的收集,⼀但数据发⽣变化,响应式系统就会⽴刻得知,因此Vue是⼀开始就知道是「在哪发⽣变化了」,但是这⼜会产⽣⼀个问题,如果你熟悉Vue的响 应式系统就知道,通常⼀个绑定⼀个数据就需要⼀个Watcher,⼀但我们的绑定细粒度过⾼就会产⽣⼤量的Watcher,这会 带来内存以及依赖追踪的开销,⽽细粒度过低会⽆法精准侦测变化,因此Vue的设计是选择中等细粒度的⽅案,在组件级别 进⾏push侦测的⽅式,也就是那套响应式系统,通常我们会第⼀时间侦测到发⽣变化的组件,然后在组件内部进⾏Virtual Dom Diff获取更加具体的差异,⽽Virtual Dom Diff则是pull操作,Vue是push+pull结合的⽅式进⾏变化侦测的.
Vue为什么没有类似于React中shouldComponentUpdate的⽣命周期?
考点: Vue的变化侦测原理
前置知识: 依赖收集、虚拟DOM、响应式系统根本原因是Vue与React的变化侦测⽅式有所不同
React是pull的⽅式侦测变化,当React知道发⽣变化后,会使⽤Virtual Dom Diff进⾏差异检测,但是很多组件实际上是肯定不会发⽣变化的,这个时候需要⽤shouldComponentUpdate进⾏⼿动操作来减少diff,从⽽提⾼程序整体的性能.
Vue是pull+push的⽅式侦测变化的,在⼀开始就知道那个组件发⽣了变化,因此在push的阶段并不需要⼿动控制diff,⽽组 件内部采⽤的diff⽅式实际上是可以引⼊类似于shouldComponentUpdate相关⽣命周期的,但是通常合理⼤⼩的组件不会有过量的diff,⼿动优化的价值有限,因此⽬前Vue并没有考虑引⼊shouldComponentUpdate这种⼿动优化的⽣命周期.
Vue中的key到底有什么⽤?
key 是为Vue中的vnode标记的唯⼀id,通过这个key,我们的diff操作可以更准确、更快速
diff算法的过程中,先会进⾏新旧节点的⾸尾交叉对⽐,当⽆法匹配的时候会⽤新节点的 key 与旧节点进⾏⽐对,然后超出差异.
diff程可以概括为:oldCh和newCh各有两个头尾的变量StartIdx和EndIdx,它们的2个变量相互⽐较,⼀共有4种
⽐较⽅式。如果4种⽐较都没匹配,如果设置了key,就会⽤key进⾏⽐较,在⽐较的过程中,变量会往中间靠,
⼀旦StartIdx>EndIdx表明oldCh和newCh⾄少有⼀个已经遍历完了,就会结束⽐较,这四种⽐较⽅式就是⾸、尾、旧尾新头、旧头新尾.
准确: 如果不加 key ,那么vue会选择复⽤节点(Vue的就地更新策略),导致之前节点的状态被保留下来,会产⽣⼀系列的bug.
快速: key的唯⼀性可以被Map数据结构充分利⽤,相⽐于遍历查找的时间复杂度O(n),Map的时间复杂度仅仅为O(1).
前端安全⾯试题
有哪些可能引起前端安全的的问题?
跨站脚本 (Cross-Site Scripting, XSS): ⼀种代码注⼊⽅式, 为了与 CSS 区分所以被称作 XSS. 早期常⻅于⽹络论坛, 起因是⽹站没有对⽤户的输⼊进⾏严格的限制, 使得攻击者可以将脚本上传到帖⼦让其他⼈浏览到有恶意脚本的⻚
⾯, 其注⼊⽅式很简单包括但不限于 JavaScript / VBScript / CSS / Flash 等
iframe的滥⽤: iframe中的内容是由第三⽅来提供的,默认情况下他们不受我们的控制,他们可以在iframe中运⾏JavaScirpt脚本、Flash插件、弹出对话框等等,这可能会破坏前端⽤户体验
跨站点请求伪造(Cross-Site Request Forgeries,CSRF): 指攻击者通过设置好的陷阱,强制对已完成认证的⽤户进⾏⾮预期的个⼈信息或设定信息等某些状态更新,属于被动攻击
恶意第三⽅库: ⽆论是后端服务器应⽤还是前端应⽤开发,绝⼤多数时候我们都是在借助开发框架和各种类库进⾏快速开发,⼀旦第三⽅库被植⼊恶意代码很容易引起安全问题,⽐如event-stream的恶意代码事件,2018年11⽉21⽇, 名为 FallingSnow的⽤户在知名JavaScript应⽤库event-stream在github Issuse中发布了针对植⼊的恶意代码的疑 问,表示event-stream中存在⽤于窃取⽤户数字钱包的恶意代码
XSS分为哪⼏类?
根据攻击的来源,XSS 攻击可分为存储型、反射型和 DOM 型三种。
存储区:恶意代码存放的位置。
插⼊点:由谁取得恶意代码,并插⼊到⽹⻚上。
存储型 XSS
存储型 XSS 的攻击步骤:
反射型 XSS
反射型 XSS 的攻击步骤:
POST 的内容也可以触发反射型 XSS,只不过其触发条件⽐较苛刻(需要构造表单提交⻚⾯,并引导⽤户点击),所以⾮常少⻅。
DOM 型 XSS
DOM 型 XSS 的攻击步骤:
如何预防XSS?
XSS 攻击有两⼤要素:
输⼊过滤
在⽤户提交时,由前端过滤输⼊,然后提交到后端。这样做是否可⾏呢?
答案是不可⾏。⼀旦攻击者绕过前端过滤,直接构造请求,就可以提交恶意代码了。
那么,换⼀个过滤时机:后端在写⼊数据库前,对输⼊进⾏过滤,然后把“安全的”内容,返回给前端。这样是否可⾏呢?
我们举⼀个例⼦,⼀个正常的⽤户输⼊了 5 < 7 这个内容,在写⼊数据库前,被转义,变成了 5 < 7 。问题是:在提交阶段,我们并不确定内容要输出到哪⾥。
这⾥的“并不确定内容要输出到哪⾥”有两层含义:
当 5 < 7 通过 Ajax 返回,然后赋值给 JavaScript 的变量时,前端得到的字符串就是转义后的字符。这个内容不能直接⽤于 Vue 等模板的展示,也不能直接⽤于内容⻓度计算。不能⽤于标题、alert 等
所以,输⼊侧过滤能够在某些情况下解决特定的 XSS 问题,但会引⼊很⼤的不确定性和乱码问题。在防范 XSS 攻击时应避免此类⽅法
当然,对于明确的输⼊类型,例如数字、URL、电话号码、邮件地址等等内容,进⾏输⼊过滤还是必要的既然输⼊过滤并⾮完全可靠,我们就要通过“防⽌浏览器执⾏恶意代码”来防范 XSS。这部分分为两类:
防⽌ HTML 中出现注⼊
防⽌ JavaScript 执⾏时,执⾏恶意代码
预防存储型和反射型 XSS 攻击
存储型和反射型 XSS 都是在服务端取出恶意代码后,插⼊到响应 HTML ⾥的,攻击者刻意编写的“数据”被内嵌到“代码”中,被浏览器所执⾏。
预防这两种漏洞,有两种常⻅做法:
改成纯前端渲染,把代码和数据分隔开。对 HTML 做充分转义。
纯前端渲染
纯前端渲染的过程:
转义 HTML
如果拼接 HTML 是必要的,就需要采⽤合适的转义库,对 HTML 模板各处插⼊点进⾏充分的转义。
常⽤的模板引擎,如 doT.js、ejs、FreeMarker 等,对于 HTML 转义通常只有⼀个规则,就是把 & < > " ’ / 这⼏个字符转义掉,确实能起到⼀定的 XSS 防护作⽤,但并不完善:
|XSS 安全漏洞|简单转义是否有防护作⽤| |-|-| |HTML 标签⽂字内容|有| |HTML 属性值|有| |CSS 内联样式|⽆| |内联JavaScript|⽆| |内联 JSON|⽆| |跳转链接|⽆|
所以要完善 XSS 防护措施,我们要使⽤更完善更细致的转义策略。
例如 Java ⼯程⾥,常⽤的转义库为 org.owasp.encoder 。以下代码引⽤⾃ org.owasp.encoder 的官⽅说明。
可⻅,HTML 的编码是⼗分复杂的,在不同的上下⽂⾥要使⽤相应的转义规则。
预防 DOM 型 XSS 攻击
DOM 型 XSS 攻击,实际上就是⽹站前端 JavaScript 代码本身不够严谨,把不可信的数据当作代码执⾏了。
在使⽤ .innerHTML 、 .outerHTML 、 document.write() 时要特别⼩⼼,不要把不可信的数据作为 HTML 插到⻚⾯上,
⽽应尽量使⽤ .textContent 、 .setAttribute() 等。
如果⽤ Vue/React 技术栈,并且不使⽤ /
innerHTML 、 outerHTML 的 XSS 隐患。
功能,就在前端 render 阶段避免
DOM 中的内联事件监听器,如 location 、 onclick 、 onerror 、 onload 、 onmouseover 等, 标签的 href 属性,JavaScript 的 eval() 、 setTimeout() 、 setInterval() 等,都能把字符串作为代码运⾏。如果不可信的数据拼接到字符串中传递给这些 API,很容易产⽣安全隐患,请务必避免。
如果项⽬中有⽤到这些的话,⼀定要避免在字符串中拼接不可信数据。
其他 XSS 防范措施
虽然在渲染⻚⾯和执⾏ JavaScript 时,通过谨慎的转义可以防⽌ XSS 的发⽣,但完全依靠开发的谨慎仍然是不够的。以下介绍⼀些通⽤的⽅案,可以降低 XSS 带来的⻛险和后果。
Content Security Policy
严格的 CSP 在 XSS 的防范中可以起到以下的作⽤: 禁⽌加载外域代码,防⽌复杂的攻击逻辑
禁⽌外域提交,⽹站被攻击后,⽤户的数据不会泄露到外域
禁⽌内联脚本执⾏(规则较严格,⽬前发现 GitHub 使⽤)
禁⽌未授权的脚本执⾏(新特性,Google Map 移动版在使⽤) 合理使⽤上报可以及时发现 XSS,利于尽快修复问题
输⼊内容⻓度控制
对于不受信任的输⼊,都应该限定⼀个合理的⻓度。虽然⽆法完全防⽌ XSS 发⽣,但可以增加 XSS 攻击的难度。
其他安全措施
HTTP-only Cookie: 禁⽌ JavaScript 读取某些敏感 Cookie,攻击者完成 XSS 注⼊后也⽆法窃取此 Cookie。验证码:防⽌脚本冒充⽤户提交危险操作。
过滤 Html 标签能否防⽌ XSS? 请列举不能的情况?
⽤户除了上传
还可以使⽤图⽚ url 等⽅式来上传脚本进⾏攻击
还可以使⽤各种⽅式来回避检查, 例如空格, 回⻋, Tab
还可以通过各种编码转换 (URL 编码, Unicode 编码, HTML 编码, ESCAPE 等) 来绕过检查
CSRF是什么?
CSRF(Cross-site request forgery)跨站请求伪造:攻击者诱导受害者进⼊第三⽅⽹站,在第三⽅⽹站中,向被攻击⽹站发送跨站请求。利⽤受害者在被攻击⽹站已经获取的注册凭证,绕过后台的⽤户验证,达到冒充⽤户对被攻击的⽹站 执⾏某项操作的⽬的。
⼀个典型的CSRF攻击有着如下的流程:
受害者登录 a.com ,并保留了登录凭证(Cookie) 攻击者引诱受害者访问了 b.com
b.com 向 a.com 发送了⼀个请求: a.com/act=xx 浏览器会默认携带a.com的Cookie
a.com接收到请求后,对请求进⾏验证,并确认是受害者的凭证,误以为是受害者⾃⼰发送的请求a.com以受害者的名义执⾏了act=xx
攻击完成,攻击者在受害者不知情的情况下,冒充受害者,让a.com执⾏了⾃⼰定义的操作
CSRF的攻击类型?
GET类型的CSRF
GET类型的CSRF利⽤⾮常简单,只需要⼀个HTTP请求,⼀般会这样利⽤:
在 受 害 者 访 问 含 有 这 个 img 的 ⻚ ⾯ 后 , 浏 览 器 会 ⾃ 动 向 http://bank.example/withdraw? account=xiaoming&amount=10000&for=hacker 发出⼀次HTTP请求。bank.example就会收到包含受害者登录信息的⼀次跨域请求。
POST类型的CSRF
这种类型的CSRF利⽤起来通常使⽤的是⼀个⾃动提交的表单,如:
访问该⻚⾯后,表单会⾃动提交,相当于模拟⽤户完成了⼀次POST操作。
POST类型的攻击通常⽐GET要求更加严格⼀点,但仍并不复杂。任何个⼈⽹站、博客,被⿊客上传⻚⾯的⽹站都有可能是发起攻击的来源,后端接⼝不能将安全寄托在仅允许POST上⾯。
链接类型的CSRF
链接类型的CSRF并不常⻅,⽐起其他两种⽤户打开⻚⾯就中招的情况,这种需要⽤户点击链接才会触发。这种类型通 常是在论坛中发布的图⽚中嵌⼊恶意链接,或者以⼴告的形式诱导⽤户中招,攻击者通常会以⽐较夸张的词语诱骗⽤户点击,例如:
由于之前⽤户登录了信任的⽹站A,并且保存登录状态,只要⽤户主动访问上⾯的这个PHP⻚⾯,则表示攻击成功。
如何预防CSRF?
CSRF通常从第三⽅⽹站发起,被攻击的⽹站⽆法防⽌攻击发⽣,只能通过增强⾃⼰⽹站针对CSRF的防护能⼒来提升安全性。
CSRF的两个特点:
CSRF(通常)发⽣在第三⽅域名。
CSRF攻击者不能获取到Cookie等信息,只是使⽤。
针对这两点,我们可以专⻔制定防护策略,如下: 阻⽌不明外域的访问
同源检测
Samesite Cookie
提交时要求附加本域才能获取的信息
CSRF Token
双重Cookie验证
因此我们可以针对性得进⾏预防
同源检测
既然CSRF⼤多来⾃第三⽅⽹站,那么我们就直接禁⽌外域(或者不受信任的域名)对我们发起请求:
使⽤Origin Header确定来源域名: 在部分与CSRF有关的请求中,请求的Header中会携带Origin字段,如果Origin存在,那么直接使⽤Origin中的字段确认来源域名就可以
使⽤Referer Header确定来源域名: 根据HTTP协议,在HTTP头中有⼀个字段叫Referer,记录了该HTTP请求的来源地址
CSRF Token
CSRF的另⼀个特征是,攻击者⽆法直接窃取到⽤户的信息(Cookie,Header,⽹站内容等),仅仅是冒⽤Cookie中的信息。
⽽CSRF攻击之所以能够成功,是因为服务器误把攻击者发送的请求当成了⽤户⾃⼰的请求。那么我们可以要求所有的
⽤户请求都携带⼀个CSRF攻击者⽆法获取到的Token。服务器通过校验请求是否携带正确的Token,来把正常的请求和攻击的请求区分开,也可以防范CSRF的攻击:
CSRF Token的防护策略分为三个步骤:
将CSRF Token输出到⻚⾯中
⻚⾯提交的请求携带这个Token 服务器验证Token是否正确
双重Cookie验证
在会话中存储CSRF Token⽐较繁琐,⽽且不能在通⽤的拦截上统⼀处理所有的接⼝
那么另⼀种防御措施是使⽤双重提交Cookie。利⽤CSRF攻击不能获取到⽤户Cookie的特点,我们可以要求Ajax和表单请求携带⼀个Cookie中的值
双重Cookie采⽤以下流程:
在⽤户访问⽹站⻚⾯时,向请求域名注⼊⼀个Cookie,内容为随机字符串(例如 csrfcookie=v8g9e4ksfhw )。在前端向后端发起请求时,取出Cookie,并添加到URL的参数中(接上例 POST https://www.a.com/comment? csrfcookie=v8g9e4ksfhw )。
后端接⼝验证Cookie中的字段与URL参数中的字段是否⼀致,不⼀致则拒绝。
Samesite Cookie属性
Google起草了⼀份草案来改进HTTP协议,那就是为Set-Cookie响应头新增Samesite属性,它⽤来标明这个 Cookie是个“同站 Cookie”,同站Cookie只能作为第⼀⽅Cookie,不能作为第三⽅Cookie,Samesite 有两个属性值:
Samesite=Strict: 这种称为严格模式,表明这个 Cookie 在任何情况下都不可能作为第三⽅ Cookie
Samesite=Lax: 这种称为宽松模式,⽐ Strict 放宽了点限制,假如这个请求是这种请求且同时是个GET请求,则这个
Cookie可以作为第三⽅Cookie
⽹络劫持有哪⼏种?
⽹络劫持⼀般分为两种:
DNS劫持: (输⼊京东被强制跳转到淘宝这就属于dns劫持)
DNS强制解析: 通过修改运营商的本地DNS记录,来引导⽤户流量到缓存服务器
302跳转的⽅式: 通过监控⽹络出⼝的流量,分析判断哪些内容是可以进⾏劫持处理的,再对劫持的内存发起302
跳转的回复,引导⽤户获取内容
HTTP劫持: (访问⾕歌但是⼀直有贪玩蓝⽉的⼴告),由于http明⽂传输,运营商会修改你的http响应内容(即加⼴告)
如何应对⽹络劫持?
DNS劫持由于涉嫌违法,已经被监管起来,现在很少会有DNS劫持,⽽http劫持依然⾮常盛⾏.
最有效的办法就是全站HTTPS,将HTTP加密,这使得运营商⽆法获取明⽂,就⽆法劫持你的响应内容.
HTTPS⼀定是安全的吗?
⾮全站HTTPS并不安全
以国内的⼯商银⾏为例
⼯商银⾏的⾸⻚不⽀持HTTPS
⽽⼯商银⾏的⽹银⻚⾯是⽀持HTTPS的
可能有⼈会问,登录⻚⾯⽀持HTTPS不就⾏了,⾸⻚⼜没有涉及账户信息. 其实这是⾮常不安全的⾏为,⿊客会利⽤这⼀点进⾏攻击,⼀般是以下流程:
中间⼈攻击
中间⼈ (Man-in-the-middle attack, MITM) 是指攻击者与通讯的两端分别创建独⽴的联系, 并交换其所收到的数据, 使通讯的两端认为他们正在通过⼀个私密的连接与对⽅直接对话, 但事实上整个会话都被攻击者完全控制. 在中间⼈攻击中, 攻击者可以拦截通讯双⽅的通话并插⼊新的内容.
⼀般的过程如下:
客户端发送请求到服务端,请求被中间⼈截获服务器向客户端发送公钥
中间⼈截获公钥,保留在⾃⼰⼿上。然后⾃⼰⽣成⼀个【伪造的】公钥,发给客户端客户端收到伪造的公钥后,⽣成加密hash值发给服务器
中间⼈获得加密hash值,⽤⾃⼰的私钥解密获得真秘钥,同时⽣成假的加密hash值,发给服务器服务器⽤私钥解密获得假密钥,然后加密数据传输给客户端
HTTPS中间⼈攻击实践
强烈建议阅读下⾯两篇前端安全⽂章:
前端安全系列(⼀):如何防⽌XSS攻击?
前端安全系列(⼆):如何防⽌CSRF攻击?
webpack⾯试题
webpack是事实上的前端打包标准,相关的⾯试题也是⾯试的热点.
webpack与grunt、gulp的不同?
Grunt、Gulp是基于任务运⾏的⼯具:
它们会⾃动执⾏指定的任务,就像流⽔线,把资源放上去然后通过不同插件进⾏加⼯,它们包含活跃的社区,丰富的插件,能⽅便的打造各种⼯作流。
Webpack是基于模块化打包的⼯具:
⾃动化处理模块,webpack把⼀切当成模块,当 webpack 处理应⽤程序时,它会递归地构建⼀个依赖关系图
(dependency graph),其中包含应⽤程序需要的每个模块,然后将所有这些模块打包成⼀个或多个 bundle。
因此这是完全不同的两类⼯具,⽽现在主流的⽅式是⽤npm script代替Grunt、Gulp,npm script同样可以打造任务流.
webpack、rollup、parcel优劣?
webpack适⽤于⼤型复杂的前端站点构建: webpack有强⼤的loader和插件⽣态,打包后的⽂件实际上就是⼀个⽴即执⾏函数,这个⽴即执⾏函数接收⼀个参数,这个参数是模块对象,键为各个模块的路径,值为模块内容。⽴即执
⾏函数内部则处理模块之间的引⽤,执⾏模块等,这种情况更适合⽂件依赖复杂的应⽤开发.
rollup适⽤于基础库的打包,如vue、d3等: Rollup 就是将各个模块打包进⼀个⽂件中,并且通过 Tree-shaking 来删除⽆⽤的代码,可以最⼤程度上降低代码体积,但是rollup没有webpack如此多的的如代码分割、按需加载等⾼级功 能,其更聚焦于库的打包,因此更适合库的开发.
parcel适⽤于简单的实验性项⽬: 他可以满⾜低⻔槛的快速看到效果,但是⽣态差、报错信息不够全⾯都是他的硬伤,除了⼀些玩具项⽬或者实验项⽬不建议使⽤
有哪些常⻅的Loader?
file-loader:把⽂件输出到⼀个⽂件夹中,在代码中通过相对 URL 去引⽤输出的⽂件
url-loader:和 file-loader 类似,但是能在⽂件很⼩的情况下以 base64 的⽅式把⽂件内容注⼊到代码中去
source-map-loader:加载额外的 Source Map ⽂件,以⽅便断点调试
image-loader:加载并且压缩图⽚⽂件babel-loader:把 ES6 转换成 ES5
css-loader:加载 CSS,⽀持模块化、压缩、⽂件导⼊等特性
style-loader:把 CSS 代码注⼊到 JavaScript 中,通过 DOM 操作去加载 CSS。eslint-loader:通过 ESLint 检查 JavaScript 代码
有哪些常⻅的Plugin?
define-plugin:定义环境变量
html-webpack-plugin:简化html⽂件创建
uglifyjs-webpack-plugin:通过 UglifyES 压缩 ES6 代码webpack-parallel-uglify-plugin: 多核压缩,提⾼压缩速度webpack-bundle-analyzer: 可视化webpack输出⽂件的体积mini-css-extract-plugin: CSS提取到单独的⽂件中,⽀持按需加载
分别介绍bundle,chunk,module是什么
bundle:是由webpack打包出来的⽂件
chunk:代码块,⼀个chunk由多个模块组合⽽成,⽤于代码的合并和分割
module:是开发中的单个模块,在webpack的世界,⼀切皆模块,⼀个模块对应⼀个⽂件,webpack会从配置的entry中递归开始找出所有依赖的模块
Loader和Plugin的不同?
不同的作⽤:
Loader直译为"加载器"。Webpack将⼀切⽂件视为模块,但是webpack原⽣是只能解析js⽂件,如果想将其他⽂件也打包的话,就会⽤到 loader 。 所以Loader的作⽤是让webpack拥有了加载和解析⾮JavaScript⽂件的能⼒。Plugin直译为"插件"。Plugin可以扩展webpack的功能,让webpack具有更多的灵活性。 在 Webpack 运⾏的⽣命周期中会⼴播出许多事件,Plugin 可以监听这些事件,在合适的时机通过 Webpack 提供的 API 改变输出结果。
不同的⽤法:
Loader在 module.rules 中配置,也就是说他作为模块的解析规则⽽存在。 类型为数组,每⼀项都是⼀
个 Object ,⾥⾯描述了对于什么类型的⽂件( test ),使⽤什么加载( loader )和使⽤的参数( options )
Plugin在 plugins 中单独配置。 类型为数组,每⼀项是⼀个 plugin 的实例,参数都通过构造函数传⼊。
webpack的构建流程是什么?
Webpack 的运⾏流程是⼀个串⾏的过程,从启动到结束会依次执⾏以下流程:
是否写过Loader和Plugin?描述⼀下编写loader或plugin的思路?
Loader像⼀个"翻译官"把读到的源⽂件内容转义成新的⽂件内容,并且每个Loader通过链式操作,将源⽂件⼀步步翻译成想要的样⼦。
编写Loader时要遵循单⼀原则,每个Loader只做⼀种"转义"⼯作。 每个Loader的拿到的是源⽂件内容( source ),可以通过返回值的⽅式将处理后的内容输出,也可以调⽤ this.callback() ⽅法,将内容返回给webpack。 还可以通过
this.async() ⽣成⼀个 callback 函数,再⽤这个callback将处理后的内容输出出去。 此外 webpack 还为开发者准备了开发loader的⼯具函数集—— loader-utils 。
相对于Loader⽽⾔,Plugin的编写就灵活了许多。 webpack在运⾏的⽣命周期中会⼴播出许多事件,Plugin 可以监听这些事件,在合适的时机通过 Webpack 提供的 API 改变输出结果。
webpack的热更新是如何做到的?说明其原理?
webpack的热更新⼜称热替换(Hot Module Replacement),缩写为HMR。 这个机制可以做到不⽤刷新浏览器⽽将新变更的模块替换掉旧的模块。
原理:
⾸先要知道server端和client端都做了处理⼯作
配置决定是刷新浏览器呢还是进⾏模块热更新。当然如果仅仅是刷新浏览器,也就没有后⾯那些步骤了。
6. HotModuleReplacement.runtime 是客户端 HMR 的中枢,它接收到上⼀步传递给他的新模块的 hash 值,它通过JsonpMainTemplate.runtime 向 server 端发送 Ajax 请求,服务端返回⼀个 json,该 json 包含了所有要更新的模块的 hash 值,获取到更新列表后,该模块再次通过 jsonp 请求,获取到最新的模块代码。这就是上图中 7、8、9 步骤。
7. ⽽第 10 步是决定 HMR 成功与否的关键步骤,在该步骤中,HotModulePlugin 将会对新旧模块进⾏对⽐,决定是否更新模块,在决定更新模块后,检查模块之间的依赖关系,更新模块的同时更新模块间的依赖引⽤。
8. 最后⼀步,当 HMR 失败后,回退到 live reload 操作,也就是进⾏浏览器刷新来获取最新打包代码。
详细原理解析来源于知乎饿了么前端Webpack HMR 原理解析
如何⽤webpack来优化前端性能?
⽤webpack优化前端性能是指优化webpack的输出结果,让打包的最终结果在浏览器运⾏快速⾼效。压缩代码:删除多余的代码、注释、简化代码的写法等等⽅式。可以利⽤webpack
的 UglifyJsPlugin 和 ParallelUglifyPlugin 来压缩JS⽂件, 利⽤ cssnano (css-loader?minimize)来压缩css
利⽤CDN加速: 在构建过程中,将引⽤的静态资源路径修改为CDN上对应的路径。可以利⽤webpack对于 output 参数和各loader的 publicPath 参数来修改资源路径
Tree Shaking: 将代码中永远不会⾛到的⽚段删除掉。可以通过在启动webpack时追加参数 --optimize-minimize 来实现
Code Splitting: 将代码按路由维度或者组件分块(chunk),这样做到按需加载,同时可以充分利⽤浏览器缓存
提取公共第三⽅库: SplitChunksPlugin插件来进⾏公共模块抽取,利⽤浏览器缓存可以⻓期缓存这些⽆需频繁变动的公共代码
详解可以参照前端性能优化-加载
如何提⾼webpack的打包速度?
happypack: 利⽤进程并⾏编译loader,利⽤缓存来使得 rebuild 更快,遗憾的是作者表示已经不会继续开发此项⽬,类似的替代者是thread-loader
外部扩展(externals): 将不怎么需要更新的第三⽅库脱离webpack打包,不被打⼊bundle中,从⽽减少打包时间,⽐如jQuery⽤script标签引⼊
dll: 采⽤webpack的 DllPlugin 和 DllReferencePlugin 引⼊dll,让⼀些基本不会改动的代码先打包成静态资源,避免反复编译浪费时间
利⽤缓存: webpack.cache 、babel-loader.cacheDirectory、 HappyPack.cache 都可以利⽤缓存提⾼rebuild效率
缩⼩⽂件搜索范围: ⽐如babel-loader插件,如果你的⽂件仅存在于src中,那么可以 include: path.resolve( dirname, ‘src’) ,当然绝⼤多数情况下这种操作的提升有限,除⾮不⼩⼼build了node_modules⽂件
实战⽂章推荐使⽤webpack4提升180%编译速度 Tool
如何提⾼webpack的构建速度?
多⼊⼝情况下,使⽤ CommonsChunkPlugin 来提取公共代码
通过 externals 配置来提取常⽤库
利⽤ DllPlugin 和 DllReferencePlugin 预编译资源模块 通过 DllPlugin 来对那些我们引⽤但是绝对不会修改的npm 包来进⾏预编译,再通过 DllReferencePlugin 将预编译的模块加载进来。
使⽤ Happypack 实现多线程加速编译
使⽤ webpack-uglify-parallel 来提升 uglifyPlugin 的压缩速度。 原理上 webpack-uglify-parallel 采⽤了多核并⾏压缩来提升压缩速度
使⽤ Tree-shaking 和 Scope Hoisting 来剔除多余代码
怎么配置单⻚应⽤?怎么配置多⻚应⽤?
单⻚应⽤可以理解为webpack的标准模式,直接在 entry 中指定单⻚应⽤的⼊⼝即可,这⾥不再赘述
多⻚应⽤的话,可以使⽤webpack的 AutoWebPlugin 来完成简单⾃动化的构建,但是前提是项⽬的⽬录结构必须遵守他预设的规范。 多⻚应⽤中要注意的是:
每个⻚⾯都有公共的代码,可以将这些代码抽离出来,避免重复的加载。⽐如,每个⻚⾯都引⽤了同⼀套css样式表
随着业务的不断扩展,⻚⾯可能会不断的追加,所以⼀定要让⼊⼝的配置⾜够灵活,避免每次添加新⻚⾯还需要修改构建配置
算法⾯试题
算法相关的题在前端⾯试中的⽐重越来越⾼,当然最有效的⽅法是去LeetCode上刷题,关于JavaScript版的LeetCode解题思路可以参考此项⽬leetcode题解,记录⾃⼰的leetcode解题之路
如何分析时间复杂度?
当问题规模即要处理的数据增⻓时,基本操作要重复执⾏的次数必定也会增⻓,那么我们关⼼地是这个执⾏次数以什么样的数量级增⻓。
我们⽤⼤O表示法表示⼀下常⻅的时间复杂度量级:
常数阶O(1) 线性阶O(n) 对数阶O(logn) 线性对数阶O(nlogn) 平⽅阶O(n²) 当然还有指数阶和阶乘阶这种⾮常极端的复杂度量级,我们就不讨论了。
O(1)
传说中的常数阶的复杂度,这种复杂度⽆论数据规模n如何增⻓,计算时间是不变的。举⼀个简单的例⼦:
不管n如何增⻓,都不会影响到这个函数的计算时间,因此这个代码的时间复杂度都是O(1)。
O(n)
线性复杂度,随着数据规模n的增⻓,计算时间也会随着n线性增⻓。典型的O(n)的例⼦就是线性查找。
线性查找的时间消化与输⼊的数组数量n成⼀个线性⽐例,随着n规模的增⼤,时间也会线性增⻓。
O(logn)
对数复杂度,随着问题规模n的增⻓,计算时间也会随着n对数级增⻓。典型的例⼦是⼆分查找法。
在⼆分查找法的代码中,通过while循环,成 2 倍数的缩减搜索范围,也就是说需要经过 log2^n 次即可跳出循环。
事实上在实际项⽬中, O(logn) 是⼀个⾮常好的时间复杂度,⽐如当 n=100 的数据规模时,⼆分查找只需要7次,线性查找需要100次,这对于计算机⽽⾔差距不⼤,但是当有10亿的数据规模的时候,⼆分查找依然只需要30次,⽽线性查找需要惊⼈的10亿次, O(logn) 时间复杂度的算法随着数据规模的增⼤,它的优势就越明显。
O(nlogn)
线性对数复杂度,随着数据规模n的增⻓,计算时间也会随着n呈线性对数级增⻓。这其中典型代表就是归并排序,我们会在对应⼩节详细分析它的复杂度。
O(n²)
平⽅级复杂度,典型情况是当存在双重循环的时候,即把 O(n) 的代码再嵌套循环⼀遍,它的时间复杂度就是 O(n²)
了,代表应⽤是冒泡排序算法。
排序算法
排序算法有很多种,我们只讲最具代表性的⼏种算法: 冒泡排序、希尔排序、归并排序、快速排序
排序算法主体内容采⽤的是⼗⼤经典排序算法总结(JavaScript描述),更详细的内容可以移步,因为作者的内容与教科书上的内容有较⼤冲突,因此我们重写了快速排序部分的内容,以教科书为准,因此建议重点读⼀下本⽂的快速排序部分.
冒泡排序(Bubble Sort)
实现思路:
改进1: 设置⼀标志性变量pos,⽤于记录每趟排序中最后⼀次进⾏交换的位置。由于pos位置之后的记录均已交换到位,故在进⾏下⼀趟排序时只要扫描到pos位置即可。
改进2: 传统冒泡排序中每⼀趟排序操作只能找到⼀个最⼤值或最⼩值,我们考虑利⽤在每趟排序中进⾏正向和反向两遍冒泡的⽅法⼀次可以得到两个最终值(最⼤者和最⼩者) , 从⽽使排序趟数⼏乎减少了⼀半。
动画:
希尔排序(Shell Sort)
1959年Shell发明; 第⼀个突破O(n^2)的排序算法;是简单插⼊排序的改进版;它与插⼊排序的不同之处在于, 它会优先⽐较距离较远的元素。希尔排序⼜叫缩⼩增量排序
算法简介
希尔排序的核⼼在于间隔序列的设定。既可以提前设定好间隔序列,也可以动态的定义间隔序列。动态定义间隔序列的算法是《算法(第4版》的合著者Robert Sedgewick提出的。
算法描述和实现
先将整个待排序的记录序列分割成为若⼲⼦序列分别进⾏直接插⼊排序,具体算法描述:
希尔排序图示(图⽚来源⽹络):
算法分析
最佳情况:T(n) = O(nlog2 n) 最坏情况:T(n) = O(nlog2 n) 平均情况:T(n) =O(nlog n)
归并排序(Merge Sort)
和选择排序⼀样,归并排序的性能不受输⼊数据的影响,但表现⽐选择排序好的多,因为始终都是O(n log n)的时间复杂度。代价是需要额外的内存空间。
算法简介
归并排序是建⽴在归并操作上的⼀种有效的排序算法。该算法是采⽤分治法(Divide and Conquer)的⼀个⾮常典型的应⽤。归并排序是⼀种稳定的排序⽅法。将已有序的⼦序列合并,得到完全有序的序列;即先使每个⼦序列有序,再使⼦序列段间有序。若将两个有序表合并成⼀个有序表,称为2-路归并。
算法描述和实现
具体算法描述如下:
归并排序动图演示:
算法分析
最佳情况:T(n) = O(n)
最差情况:T(n) = O(nlogn)
平均情况:T(n) = O(nlogn)
快速排序(Quick Sort) 算法简介
快速排序的基本思想:通过⼀趟排序将待排记录分隔成独⽴的两部分,其中⼀部分记录的关键字均⽐另⼀部分的关键字
⼩,则可分别对这两部分记录继续进⾏排序,以达到整个序列有序。
算法描述和实现
算法分析
最佳情况:T(n) = O(nlogn) 最差情况:T(n) = O(n2) 平均情况:T(n) = O(nlogn)
查找算法
⼆分查找法算法简介
折半查找算法要求查找表的数据是线性结构存储,还要求查找表中的顺序是由⼩到⼤排序(由⼤到⼩排序)
算法思路及实现
算法分析
最佳情况:T(n) = O(logn) 最差情况:T(n) = O(logn) 平均情况:T(n) = O(logn)
线性查找
算法简介及实现
线性查找很简单,只需要进⾏简单的遍历即可.
算法分析
最佳情况:T(n) = O(n) 最差情况:T(n) = O(n) 平均情况:T(n) = O(n)
字符串类⾯试题
解析 URL Params 为对象
模板引擎实现
转化为驼峰命名
查找字符串中出现最多的字符和个数
例: abbcccddddd -> 字符最多的是d,出现了5次
字符串查找
请使⽤最基本的遍历来实现判断字符串 a 是否被包含在字符串 b 中,并返回第⼀次出现的位置(找不到返回 -1)。
实现千位分隔符
正则表达式(运⽤了正则的前向声明和反前向声明):
判断是否是电话号码
验证是否是邮箱
验证是否是身份证
参考:
前端⾯试遇到的算法题
JavaScript笔试部分
实现防抖函数(debounce)
防抖函数原理:在事件被触发n秒后再执⾏回调,如果在这n秒内⼜被触发,则重新计时。那么与节流函数的区别直接看这个动画实现即可。
⼿写简化版:
适⽤场景:
按钮提交场景:防⽌多次提交按钮,只执⾏最后提交的⼀次
服务端验证场景:表单验证需要服务端配合,只执⾏⼀段连续的输⼊事件的最后⼀次,还有搜索联想词功能类似
⽣存环境请⽤lodash.debounce
实现节流函数(throttle)
防抖函数原理:规定在⼀个单位时间内,只能触发⼀次函数。如果这个单位时间内触发多次函数,只有⼀次⽣效。
// ⼿写简化版
适⽤场景:
拖拽场景:固定时间内只执⾏⼀次,防⽌超⾼频次触发位置变动缩放场景:监控浏览器resize
动画场景:避免短时间内多次触发动画引起性能问题
深克隆(deepclone)
简单版:
局限性:
flag = typeString === “[object Array]”; break;
case “Date”:
flag = typeString === “[object Date]”; break;
case “RegExp”:
flag = typeString === “[object RegExp]”; break;
default:
flag = false;
}
return flag;
};
// 处理正则
const getRegExp = re => { var flags = “”;
if (re.global) flags += “g”;
if (re.ignoreCase) flags += “i”; if (re.multiline) flags += “m”; return flags;
};
// 维护两个储存循环引⽤的数组const parents = []; const children = [];
const _clone = parent => {
if (parent === null) return null;
if (typeof parent !== “object”) return parent;
let child, proto;
if (isType(parent, “Array”)) {
// 对数组做特殊处理
child = [];
} else if (isType(parent, “RegExp”)) {
// 对正则对象做特殊处理
child = new RegExp(parent.source, getRegExp(parent));
if (parent.lastIndex) child.lastIndex = parent.lastIndex;
} else if (isType(parent, “Date”)) {
// 对Date对象做特殊处理
child = new Date(parent.getTime());
} else {
// 处理对象原型
proto = Object.getPrototypeOf(parent);
// 利⽤Object.create切断原型链
child = Object.create(proto);
}
// 处理循环引⽤
const index = parents.indexOf(parent);
if (index != -1) {
// 如果⽗数组存在本对象,说明之前已经被引⽤过,直接返回此对象
return children[index];
}
parents.push(parent); children.push(child);
for (let i in parent) {
// 递 归
child[i] = _clone(parent[i]);
}
return child;
};
return _clone(parent);
};
局限性:
实现Event(event bus)
event bus既是node中各个模块的基⽯,⼜是前端组件通信的依赖⼿段之⼀,同时涉及了订阅-发布设计模式,是⾮常重要的基础。
简单版:
⾯试版:
};
// 监听名为type的事件
EventEmeitter.prototype.addListener = function(type, fn) {
// 将type事件以及对应的fn函数放⼊this._events中储存
if (!this._events.get(type)) { this._events.set(type, fn);
}
};
// 触发名为type的事件
EventEmeitter.prototype.emit = function(type, …args) { let handler;
handler = this._events.get(type); if (Array.isArray(handler)) {
// 如果是⼀个数组说明有多个监听者,需要依次此触发⾥⾯的函数
for (let i = 0; i < handler.length; i++) { if (args.length > 0) {
handler[i].apply(this, args);
} else { handler[i].call(this);
}
}
} else {
// 单个函数的情况我们直接触发即可
if (args.length > 0) { handler.apply(this, args);
} else { handler.call(this);
}
}
return true;
};
// 监听名为type的事件
EventEmeitter.prototype.addListener = function(type, fn) {
const handler = this._events.get(type); // 获取对应事件名称的函数清单
if (!handler) { this._events.set(type, fn);
} else if (handler && typeof handler === “function”) {
// 如果handler是函数说明只有⼀个监听者
this._events.set(type, [handler, fn]); // 多个监听者我们需要⽤数组储存
} else {
handler.push(fn); // 已经有多个监听者,那么直接往数组⾥push函数即可
}
};
EventEmeitter.prototype.removeListener = function(type, fn) { const handler = this._events.get(type); // 获取对应事件名称的函数清单
// 如果是函数,说明只被监听了⼀次
if (handler && typeof handler === “function”) { this._events.delete(type, fn);
} else {
let postion;
// 如果handler是数组,说明被监听多次要找到对应的函数
for (let i = 0; i < handler.length; i++) { if (handler[i] === fn) {
postion = i;
} else { postion = -1;
}
}
// 如果找到匹配的函数,从数组中清除
if (postion !== -1) {
// 找到数组对应的位置,直接清除此回调
handler.splice(postion, 1);
// 如果清除后只有⼀个函数,那么取消数组,以函数形式保存
实现具体过程和思路⻅实现event
实现instanceOf
模拟new
new操作符做了这些事:
它创建了⼀个全新的对象
它会被执⾏[[Prototype]](也就是proto)链接它使this指向新创建的对象
通过new创建的每个对象将最终被[[Prototype]]链接到这个函数的prototype对象上
如果函数没有返回对象类型Object(包含Functoin, Array, Date, RegExg, Error),那么new表达式中的函数调⽤将返回该对象引⽤
实现⼀个call
call做了什么:
将函数设为对象的属性执⾏&删除这个函数
指定this到函数并传⼊给定参数执⾏函数如果不传⼊参数,默认指向为 window
具体实现参考JavaScript深⼊之call和apply的模拟实现
实现apply⽅法
apply原理与call很相似,不多赘述
实现bind
实现bind要做什么
返回⼀个函数,绑定this,传递预置参数
bind返回的函数可以作为构造函数使⽤。故作为构造函数时应使得this失效,但是传⼊的参数依然有效
详解请移步JavaScript深⼊之bind的模拟实现 #12
模拟Object.create
Object.create()⽅法创建⼀个新对象,使⽤现有的对象来提供新创建的对象的proto。
实现类的继承
类的继承在⼏年前是重点内容,有n种继承⽅式各有优劣,es6普及后越来越不重要,那么多种写法有点『回字有四样写法』的意思,如果还想深⼊理解的去看红宝书即可,我们⽬前只实现⼀种最理想的继承⽅式。
实现JSON.parse
此⽅法属于⿊魔法,极易容易被xss攻击,还有⼀种 new Function ⼤同⼩异。简单的教程看这个半⼩时实现⼀个 JSON 解析器
实现Promise
我很早之前实现过⼀版,⽽且注释很多,但是居然找不到了,这是在⽹络上找了⼀版带注释的,⽬测没有⼤问题, 具体过程可以看这篇史上最易读懂的 Promise/A+ 完全实现
}.bind(this),
// onRejected function (reason2) {
if (thenAlreadyCalledOrThrow) return thenAlreadyCalledOrThrow = true resolveOrReject.bind(this, ‘rejected’, reason2)()
}.bind(this)
)
} else {
// 拥有then 但是then不是⼀个函数 所以也不是thenable resolveOrReject.bind(this, ‘resolved’, value)()
}
} catch (e) {
if (thenAlreadyCalledOrThrow) return thenAlreadyCalledOrThrow = true resolveOrReject.bind(this, ‘rejected’, e)()
}
} else {
// 基本类型 直接返回
resolveOrReject.bind(this, ‘resolved’, value)()
}
}
function resolveOrReject (status, data) { if (this.status !== ‘pending’) return this.status = status
this.data = data
if (status === ‘resolved’) {
for (var i = 0; i < this.resolveList.length; ++i) { this.resolveListi
}
} else {
for (i = 0; i < this.rejectList.length; ++i) { this.rejectListi
}
}
}
function Promise (executor) {
if (!(this instanceof Promise)) {
throw Error(‘Promise can not be called without new !’)
}
if (typeof executor !== ‘function’) {
// ⾮标准 但与Chrome⾕歌保持⼀致
throw TypeError(‘Promise resolver ’ + executor + ’ is not a function’)
}
this.status = ‘pending’ this.resolveList = [] this.rejectList = []
try {
executor(tryToResolve.bind(this), resolveOrReject.bind(this, ‘rejected’))
} catch (e) {
resolveOrReject.bind(this, ‘rejected’, e)()
}
}
Promise.prototype.then = function (onFullfilled, onRejected) {
// 返回值穿透以及错误穿透, 注意错误穿透⽤的是throw⽽不是return,否则的话
// 这个then返回的promise状态将变成resolved即接下来的then中的onFullfilled
// 会被调⽤, 然⽽我们想要调⽤的是onRejected
if (typeof onFullfilled !== ‘function’) { onFullfilled = function (data) {
return data
}
}
if (typeof onRejected !== ‘function’) { onRejected = function (reason) {
throw reason
}
}
var executor = function (resolve, reject) { setTimeout(function () {
try {
// 拿到对应的handle函数处理this.data
// 并以此为依据解析这个新的Promise
var value = this.status === ‘resolved’
? onFullfilled(this.data)
: onRejected(this.data) resolve(value)
} catch (e) { reject(e)
}
}.bind(this))
}
// then 接受两个函数返回⼀个新的Promise
// then ⾃身的执⾏永远异步与onFullfilled/onRejected的执⾏
if (this.status !== ‘pending’) {
return new Promise(executor.bind(this))
} else {
// pending
return new Promise(function (resolve, reject) { this.resolveList.push(executor.bind(this, resolve, reject)) this.rejectList.push(executor.bind(this, resolve, reject))
}.bind(this))
}
}
// for prmise A+ test
Promise.deferred = Promise.defer = function () { var dfd = {}
dfd.promise = new Promise(function (resolve, reject) { dfd.resolve = resolve
dfd.reject = reject
})
return dfd
}
// for prmise A+ test
if (typeof module !== ‘undefined’) { module.exports = Promise
}
return Promise
})()
PromisePolyfill.all = function (promises) { return new Promise((resolve, reject) => {
const result = [] let cnt = 0
for (let i = 0; i < promises.length; ++i) { promises[i].then(value => {
cnt++
result[i] = value
if (cnt === promises.length) resolve(result)
}, reject)
}
})
}
PromisePolyfill.race = function (promises) { return new Promise((resolve, reject) => {
for (let i = 0; i < promises.length; ++i) {
基础篇
1、列举Java和JavaScript之间的区别?
Java是一门十分完整、成熟的编程语言。相比之下,JavaScript是一个可以被引入HTML页面的编程语言。这两种语言并不完全相互依赖,而是针对不同的意图而设计的。 Java是一种面向对象编程(OOPS)或结构化编程语言,类似的如C ++或C,而JavaScript是客户端脚本语言,它被称为非结构化编程。
2、什么是负无穷大?
负无穷大是JavaScript中的一个数字,可以通过将负数除以零来得到。
3、什么是未声明和未定义的变量?
未声明的变量是程序中不存在且未声明的变量。如果程序尝试读取未声明变量的值,则会遇到运行时错误。未定义的变量是在程序中声明但尚未给出任何值的变量。如果程序尝试读取未定义变量的值,则返回未定义的值。
4、什么是全局变量?这些变量如何声明,使用全局变量有哪些问题?
全局变量是整个代码长度可用的变量,也就是说这些变量没有任何作用域。var关键字用于声明局部变量或对象。如果省略var关键字,则声明一个全局变量。
例:// Declare a global globalVariable = “Test”;
使用全局变量所面临的问题是本地和全局变量名称的冲突。此外,很难调试
5、解释JavaScript中定时器的工作?如果有,也可以说明使用定时器的缺点?
定时器用于在设定的时间执行一段代码,或者在给定的时间间隔内重复该代码。这通过使用函数setTimeout,setInterval和clearInterval来完成。
setTimeout(function,delay)函数用于启动在所述延迟之后调用特定功能的定时器。
setInterval(function,delay)函数用于在提到的延迟中重复执行给定的功能,只有在取消时才停止。
clearInterval(id)函数指示定时器停止。
定时器在一个线程内运行,因此事件可能需要排队等待执行。
6、什么是=运算符?
=被称为严格等式运算符,当两个操作数具有相同的值而没有任何类型转换时,该运算符返回true。
7、说明如何使用JavaScript提交表单?
要使用JavaScript提交表单,请使用
document.form [0] .submit();
8、说明“”和“=”之间的区别?
“”仅检查值相等,而“=”是一个更严格的等式判定,如果两个变量的值或类型不同,则返回false。
9、3 + 2 +“7”的结果是什么?
由于3和2是整数,它们将直接相加。由于7是一个字符串,它将会被直接连接,所以结果将是57。
10、Javascript中的NULL是什么意思?
NULL用于表示无值或无对象。它意味着没有对象或空字符串,没有有效的布尔值,没有数值和数组对象。
11、什么是JavaScript Cookie?
Cookie是用来存储计算机中的小型测试文件,当用户访问网站以存储他们需要的信息时,它将被创建。
12、在JavaScript中使用innerHTML的缺点是什么?
如果在JavaScript中使用innerHTML,缺点是:内容随处可见;不能像“追加到innerHTML”一样使用;即使你使用+ = like“innerHTML = innerHTML +‘html’”旧的内容仍然会被html替换;整个innerHTML内容被重新解析并构建成元素,因此它的速度要慢得多;innerHTML不提供验证,因此我们可能会在文档中插入有效的和破坏性的HTML并将其中断。
13、break和continue语句的作用?
Break语句从当前循环中退出。
continue语句继续下一个循环语句。
14、JavaScript中不同类型的错误有几种?
有三种类型的错误:
Load time errors:该错误发生于加载网页时,例如出现语法错误等状况,称为加载时间错误,并且会动态生成错误。
Run time errors:由于在HTML语言中滥用命令而导致的错误。
15、解释window.onload和onDocumentReady?
logical Errors:这是由于在具有不同操作的函数上执行了错误逻辑而发生的错误。
在载入页面的所有信息之前,不运行onload函数。这导致在执行任何代码之前会出现延迟。onDocumentReady在加载DOM之后加载代码。这允许早期的代码操纵。
16、解释延迟脚本在JavaScript中的作用?
默认情况下,在页面加载期间,HTML代码的解析将暂停,直到脚本停止执行。这意味着,如果服务器速度较慢或者脚本特别沉重,则会导致网页延迟。在使用Deferred时,脚本会延迟执行直到HTML解析器运行。这减少了网页加载时间,并且它们的显示速度更快。
17、如何在不支持JavaScript的旧浏览器中隐藏JavaScript代码
在
23、介绍一下你了解的CSS3?
Css3新增了一些属性,比如:
border-radius,可以用来给div加圆角,
box-shadow 用来给盒子加阴影。
text-shadow用来给文字加阴影。
Box-sizing用来重新定义盒子模型:
content-box(w3c标准的盒子模型,盒子的宽度就是内容的宽度,是默认的);
border-box(是ie的盒子模型,盒子的宽度等于内容+padding+border);
linear-gradient:用来做渐变色。
24、绑定事件:
主流浏览器.
addEventListener // .removeEventListener
IE8以及以下:.
attachEvent //.detachEvent
25、常见内存泄露的原因?
全局变量引起的内存泄露
闭包引起的内存泄露:慎用闭包
dom清空或删除时,事件未清除导致的内存泄漏
循环引用带来的内存泄露
26、浏览器加载资源(html、图片、js、css)的顺序
html 图片 css js
27、说一下ie,谷歌和火狐的兼容性问题?
常见的兼容性问题大都出现在ie8以下的浏览器,比如ie6的双边距问题,ie6的3像素问题,盒子模型的计算宽度不一样。Ie6,7中li底部有三像素问题增加浮动解决。
Ie一般用css前缀过滤对不同版本的浏览器兼容实现样式。其他的部分就是一些css3新增的属性,各个浏览器相互不兼容,需要加前缀:
-webkit- -moz- -o- -ms-
Js部分:
Firefox中没有removenode方法。node.parentNode.removeChild(node)
绑定事件:
主流浏览器 .addEventListener//.removeEventListener
Ie8以及以下 .attachEvent//.detachEvent
28、http请求流程
1)、web服务器和浏览器服务器 建立连接
2)、web服务器向浏览器服务器 发送命令
3)、web服务器向浏览器服务器 发送请求头
4)、浏览器服务器向web服务器 应答
5)、浏览器服务器向web服务器 发送应答头
6)、web服务器向浏览器服务器 发送数据
7)、web服务器向浏览器服务器 断开连接
29、js 闭包的作用
闭包可以用在许多地方。它的最大用处有两个,一个是前面提到的可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中。
30、jsonp原理
JSONP (json with padding) 通过javascript callback 实现跨域访问的一种机制,由于同源策略的机制,XMLhttpRequest只允许访问同域名 同协议 同端口下的资源,所以使用 带有src 属性的标签 能够使浏览器返回数据,从而解决跨域请求问题
31、js中使用typeof能得到哪些类型?
undefined、string、number、boolean、object、function
32、描述new一个对象的过程
1.创建一个新对象
2.this指向这个新对象
3.执行代码,即对this赋值
4.返回this
33、前端使用异步的场景有哪些
1)、setTimeout、setInverval
2)、ajax请求、动态加载
3)、事件请求
(特点:都需要等待,由js是单线程语言所决定)
34、浏览器从输入网址到页面展示的过程之间发生了什么?
浏览器向DNS服务器查找输入URL对应的IP地址
DNS服务器返回网站的IP地址
DNS服务器根据IP地址与目标web服务器在80端口上建立TCP连接
浏览器获取请求页面的html代码
浏览器在显示的窗口内渲染html
浏览器窗口关闭时,终止与服务器的连接
35、localstorage存放在哪里?不同浏览器之间可以公用吗?
localStorage保存的数据,一般情况下是永久保存的,也就是说只要采用localstorage保存信息,数据便一直存储在用户的客户端中。即使用户关闭当前web浏览器后重新启动,数据依然存在。直到用户或程序明确制定删除,数据的生命周期才会结束。
在安全性方面,localstorage是域内安全的,即localstorage是基于域的。任何在该域内的所有页面,都可以访问localstorage数据。但仍然存在一个问题,就是各个浏览器厂商的浏览器之间的数据是各自独立的。也就是说,如果在firefox中使用localstorage存储一组数据,在chrome浏览器下是无法读取的。同样,由于localstorage数据是保存在用户的设备中的,因此同一个应用程序在不同设备上保存的数据是不同的。
36、Flex布局与bootstrap的区别?
在Bootstrap中采用12栅格的布局,12份随意分配,但是不能解决5等分,7等分的问题。所以flex布局来协助。
Flex比Bootstrap的布局适应性更强,因为flex是基于灵活布局,而Bootstrap是自定义宽度布局,当删除元素时这些显得尤为明显。
Flex布局和Bootstrap两者相同的设计理念
内部的孩子节点无margin,元素之间的空隙用padding和border进行间隔,以及box-sizing:bording-box进行宽高的界定。
两者都完美适配手机
37、说出几种IE6 BUG的解决方法
1)、双边距Bug,由float所引起,通过使用display解决
2)、3像素问题,由使用float引起,使用display:inline -3px;解决
3)、超链接hover,点击后失效,使用正确的书写顺序:link visited hover active
4)、z-index问题,给父级添加position:relative
5)、png透明,使用js代码进行修改
6)、min-height最小高度,使用!important解决
7)、select在IE6下遮盖,使用iframe嵌套
8)、为什么没有办法定义1px左右宽度的宽度容器
(IE6默认的行高造成的,使用overflow:hidden;zoom:0.08;line-height:1px;解决)
38、什么是垃圾回收机制
当一个变量的引用次数为0的时候他在内存中就被销毁了
当一个对象数据在一定时间后,没有被使用的话,垃圾回收机制会自动把他销毁
当js代码执行完毕的时候也会自动销毁
39、iframe的优缺点?
1.优点:
解决加载缓慢的第三方内容如图标和广告等的加载问题
Security sandbox
并行加载脚本
2.的缺点
iframe会阻塞主页面的Onload事件;
即使内容为空,加载也需要时间
没有语意
40、null和undefined的区别?
undefined是一个表示"无"的原始值,转为数值时为 当声明的变量还未被初始化时,变量的默认值为null用来表示尚未存在的对象,常用来表示函数企图返回一个不存在的对象。
41、documen.write和 innerHTML的区别
document.write只能重绘整个页面
innerHTML可以重绘页面的一部分
42、你有哪些性能优化的方法?
(1) 减少http请求次数:CSS Sprites, JS、CSS源码压缩、图片大小控制合适;网页Gzip,CDN托管,data缓存 ,图片服务器。
(2) 前端模板 JS+数据,减少由于HTML标签导致的带宽浪费,前端用变量保存AJAX请求结果,每次操作本地变量,不用请求,减少请求次数
(3) 用innerHTML代替DOM操作,减少DOM操作次数,优化javascript性能。
(4) 当需要设置的样式很多时设置className而不是直接操作style。
(5) 少用全局变量、缓存DOM节点查找的结果。减少IO读取操作。
(6) 避免使用CSS Expression(css表达式)又称Dynamic properties(动态属性)。
(7)图片预加载,将样式表放在顶部,将脚本放在底部 加上时间戳。
43、变量声明提升
先看一段代码:
以下这段代码,因为,没有用var声明,所以出错
function testf(){
console.log(myName); //这句话会提示 myName is not definded;
}
再看一段代码:
function testf(){
var myName; //声明一个变量,没有赋值,但是经过预编译,会给该变量赋值为undefined;
console.log(myName); //这句话就显示undefined;
44、假如一个页面左边是固定的200px宽度,右边是自适应布局,如何实现?右边的宽度是如何获取的
1,左边固定宽度;右边100%,左浮动 padding-left = 左边的宽度
2,父元素:
display:flex,justify-content:center和align-items:flex-start
45、事件捕获和冒泡的区别
1)、事件捕获
捕获型事件(event capturing):事件从最不精确的对象(document 对象)开始触发,然后到最精确(也可以在窗口级别捕获事件,不过必须由开发人员特别指定)
2)、事件冒泡
冒泡型事件:事件按照从最特定的事件目标到最不特定的事件目标(document对象)的顺序触发、捕获和冒泡过程图
事件捕获和事件冒泡属于两个相反的过程,这里可以有一个我感觉十分恰当的比喻,当你把一个可以漂浮在水面上的物品,使劲向水里砸下去,它会首先有一个下降的过程,这个过程就可以理解为从最顶层向事件发生的最具体元素(目标点)的捕获过程;之后由于浮力大于物体自身的重力,物体会在到达最低点( 最具体元素)之后漂浮到水面上,这个过程相对于事件捕获是一个回溯的过程,即事件冒泡。
46、事件委托
1).什么是事件委托
本来是要注册给自己的事件,注册给了父元素.事件触发后的事情,委托给父元素执行
2.)事件委托的优点:
1.>document对象可以很快访问到,而且可以在页面生命周期的任何时点为它添加事件处理程序,(无需等待DOMContentLoaded或load事件)。换句话说,只要可单击的元素呈现在页面上,就可以立即具备适当的功能.
2.>在页面中设置事件处理程序所需的时间更少。只添加一个事件处理程序所需要的DOM引用更少,所花的时间更少.
3.>整个页面占用的内存空间更少,能够提升整体性能。
事件委托的原理 : 事件冒泡
47、字体图标和雪碧图的区别
设想一个实际场景:在一个页面为了展示,我们放置了很多独立的小图片,浏览器在显示页面的时候,就需要向服务器就会发送很多请求,来获取并加载这些小图片,但是这样的话,就会导致请求数量太多,造成资源浪费,以及访问速度变慢。
碰到这样的情况,可以使用两种方式解决这种问题:CSS雪碧图以及字体图标。但是这两种方式也都有不同的适用场景,需要根据实际需求来做取舍。
图标字体
可以缩放的矢量图标。你可以使用CSS对它们进行修改:大小,颜色,阴影等。体积特别的小。可能几百个图标才几十KB。
雪碧图
除了叫雪碧图外,它还有很多名字,css sprite, css 精灵等。原理就是将一些小图标合并到一张图片上,然后用css的背景定位来显示需要显示的部分。
48、使用闭包的注意点
由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。
闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。
49、闭包的优缺点是什么?
优点:
1、可以将一个变量长期驻扎在内存中;
2、避免全局变量的污染;
3、私有成员的存在。
缺点:
1、会使函数的变量被保存在内存中,内存消耗极大,会造成网页性能问题,在IE中会导致内存泄漏。
解决办法:在退出函数之前,将不使用的局部变量设置为null。
2、闭包会在父函数外部,改变父函数内部变量的值,所以如果把父函数当做对象使用,会把闭包当做它的公用方法,把内部变量当做它的私有属性,所以使用时一定要小心,不要随便改变父函数内部变量的值。一阶段常见的面试题(初稿)
50、常见浏览器兼容性问题
不同的浏览器对同一段代码解析不同导致显示效果不同的问题叫做浏览器兼容性问题。
1.双倍浮动bug
描述:块元素设置浮动后,又设置了横向的margin值,在IE6下,显示的比设置的值要大,并且是2倍关系
解决方案: 给浮动的块元素设置display:inline;
2.表单元素行高不一致
解决方案:
a) input{float:left;}
b) input{vertical-align:top|middle|bottom;}
3.图片默认有空隙
解决方案:
a) img{display:block;}
b) img{float:left;}
c) img{vertical-align:top|middle|bottom;}
4.给img添加超链接时,在某些浏览器中(如ie)会出现带有颜色的边框
解决方案:
img{border:none;} 或 img{border:0;}
5.鼠标指针bug
描述: cursor:hand; 在IE8以上浏览器不识别设置为手的形状
解决方案: cursor:pointer;
2.优雅降级(由高到低)
刚开始就构建网站的完整功能,然后针对各版本浏览器进行调试和修复。
渐进增强
eg1: .box{
-webkit-transition:all 1s;
-moz-transition:all 1s;
-o-transition:all 1s;
-ms-transition:all 1s;
transition:all 1s;
}
优雅降级
eg2: .box{
transition:all 1s;
-webkit-transition:all 1s;
-moz-transition:all 1s;
-o-transition:all 1s;
-ms-transition:all 1s;
}
55、常见移动端布局方案
1.百分比布局(流式布局)
特点:不管分辨率怎么变,顶部和底部的高度和位置都不变,文字流式,控件弹性,图片等比缩放
典型案例:拉勾网
2.等比例缩放布局(rem布局)
特点:使用rem为主要单位进行页面布局,很好的实现了在不同设备上页面等比例缩放
3.混合布局
特点:将多种单位(px,rem,vw等),多种布局方式(flex布局,圣杯布局)融合在一起实现移动端的屏幕适配的方案
56、移动端相关单位
1.px
像素,相对于屏幕分辨率而言
2.em
相对于父元素字体大小的单位
默认情况下: 1em=16px=100%=12pt=medium
3.rem
相对于根元素字体大小的单位
注:我们在移动端一般采用rem布局,因为根元素字体大小固定,而父元素字体大小不固定,经常发生变化,容易造成逐层的连锁反应
57、link和@import引入外部样式的区别
1.老祖宗区别
link是html标签,除了可以引入css文件,还可以引入其他文件
@import属于css范畴,只能引入css文件。
2.加载顺序不同
link引入的css文件和页面同时加载,@import引入的css文件在页面加载完成后载入
3.浏览器支持不同
link引入css文件无兼容性问题,@import是css2.1提出的,低版本浏览器不支持
4.是否支持js控制DOM
link属于html标签,支持js控制DOM改变样式,@import不支持
58、rgba模式和opacity的区别
Rgba模式是给元素的背景添加一定的透明度,容器内的图片和文字不会跟随透明;
Opacity是给容器添加一定的透明度,容器内的文字和图片会跟随透明
语法:background:rgba(r,g,b,a); a代表透明度 取值范围为0~1
59、http协议属于七层协议中的哪一层,下一层是什么
七层结构:物理层、数据链路层、网络层、传输层、会话层、表示层、应用层
TCP 属于传输层;
HTTP 属于应用层。
HTTP的下一层是表现层
60、sessionStorage和localstorage能跨域拿到吗?比如我在www.baidu.com设置的值能在m.baidu.com能拿到吗?为什么?
localStorage会跟cookie一样受到跨域的限制,会被document.domain影响
cookie、sessionStorage、LocalStorage不能跨域,不能跨浏览器, cookie、LocalStorage跨域需要特殊处理。
61、new操作符具体干了什么呢?
1)创建一个空对象,并且 this 变量引用该对象,同时还继承了该函数的原型。
2)属性和方法被加入到 this 引用的对象中。
3)新创建的对象由 this 所引用,并且最后隐式的返回 this 。
62、form中的input可以设置为readonly和disable,请问2者有什么区别?
readonly不可编辑,但可以选择和复制;值可以传递到后台
disabled不能编辑,不能复制,不能选择;值不可以传递到后台
63、用CSS实现一个三角形
64、bind,call和apply的区别
1、相同点:
三个函数都会改变this的指向(调用这三个函数的函数内部的this)
2、不同点:
1)、bind会产生新的函数,(把对象和函数绑定死后,产生新的函数)
2)、call和apply不会产生新的函数,只是在调用时,绑定一下而已。
3)、call和apply的区别,第一个参数都是要绑定的this,apply第二个参数是数组(是函数的所有参数),call把apply的第二个参数单列出来。
65、let和const是什么意思
1、let声明的变量
1)、let声明的变量是块级作用域(所在花括号里),var是函数作用域和全局作用域
注意:let是可以定义全局变量,局部变量,块级作用域的变量。
2)、let声明的变量不会声明提升,var会声明提升
3)、从代码的写法上,let不能声明同名的变量,var可以。
2、const声明的变量
1)、const修饰的变量是只读,不能修改的,即是常量
2)、const修饰的是直接指向(修饰)的内存
66、请问parseInt(),parseFloat(),Number()的区别?
1、parseInt()字符串转换成整型,parseFloat()字符串转换成浮点型,Number()字符串转换成数字型;
2、Number():看的是整体,只要字符串内的内容不是合法的数字,则结果为NaN;否则,就会正常转换为数字类型。
parseInt()和parseFloat()的转换规则比较接近(类似);
从前朝后,如果第一个字符是非数字,那么,结果为NaN;如果第一个字符是数字:
1)、parseInt():如果遇到小数点或者其它非数字字符或结尾,那么就把前面的内容正常转换为数字
2)、parseFloat():如果遇到第二个小数点或者其它非数字字符或结尾,那么就把前面的内容正常转换为数字
67、使用console和alert的区别?
盒模型转换语法:box-sizing:content-box(标准盒模型)/boder-box(怪异盒模型)
69、请说出三种减少页面加载时间的方法?
(1)减少http请求(合并文件、合并图片)
(2)优化图片文件,减小其尺寸
(3)图像格式的选择(GIF:提供的颜色较少,可用在一些对颜色要求不高的地方)
(4)压缩Javascript、CSS代码
(5)元素标明高度和宽度
(6)网址后面加上“/”
70、怎么清空数组?怎么去除数组重复的元素?
1、清空数组:
(1)给数组的length赋值为0,arr.length=0;
(2)给数组重新赋值为【】,arr=[ ];
(3)arr.splice(0,arr.length)
2、去重:
1)第一种方法:
function method01(){
var arr=[]; //定义一个临时数组
for(var i = 0; i < this.length; i++){ //循环遍历当前数组
//判断当前数组下标为i的元素是否已经保存到临时数组
//如果已保存,则跳过,否则将此元素保存到临时数组中
if(arr.indexOf(this[i]) == -1){
arr.push(this[i]);
}
}
return arr;
}
2)第二种方法:
function method02(){
//直接定义结果数组
var arr=[ ] ;
for(var i = 1; i < this.length; i++){ //从数组第二项开始循环遍历此数组
//对元素进行判断:
//如果数组当前元素在此数组中第一次出现的位置不是i
//那么我们可以判断第i项元素是重复的,否则直接存入结果数组
if(this.indexOf(this[i]) == i){
arr.push(this[i]);
}
}
return arr;
}
71、jQuery源码中值得借鉴的?
1.使用模块化思想,模块间保持独立,不会导致多个开发人员合作市产生冲突
2.在设计程序时,要结构清晰,高内聚,低耦合
3、利用多态的方式,实现方法 的重载,提高代码的复用率
4.jQuery的链式调用以及回溯
5.jQuery.fn.extend与jQuery.extend方法来实现扩展静态方法或实例方法
72、WEB安全——你所了解到的Web攻击技术
1.XSS攻击
2.CSFR攻击
(跨站请求伪造(英语:Cross-site request forgery),也被称为 one-click attack 或者 session riding,通常缩写为 CSRF 或者 XSRF, 是一种挟制用户在当前已登录的Web应用程序上执行非本意的操作的攻击方法。跟跨网站脚本(XSS)相比,XSS 利用的是用户对指定网站的信任,CSRF 利用的是网站对用户网页浏览器的信任。)
3.网络劫持攻击
4.控制台注入代码
5.钓鱼
如何防止XSS攻击
1.将前端输出数据都进行转义
2.将输出的字符串的\进行转义
3.从url中获取的信息,防止方法是由后端获取,在前端进行输出
4.使用cookie的HttpOnly属性,保护好cookie
73、this指针问题
this:是函数的内置对象,只能出现在函数内部。
this是这个的意思,是代名词。代表谁,需要看场景
1、当this所在函数是事件处理函数时,this是事件源
2、当this所在函数是构造函数时,this是new出来的对象
3、当this所在函数是类的方法时,this是调用函数的对象(函数的所属对象)。
4、当this所在函数普通函数(不是以上情况),this是window对象。
74、position有几种?有什么区别?哪几个是脱离文档流的?
1.static(静态)默认值,不受top、bottom、left、right属性影响,不脱离文档流的布局
2.Relative(相对):相对定位,受top、bottom、left、right属性影响,只改变自身的位置, 不脱离文档流的布局
3.Absolute(绝对):绝对定位,定位的起始位置为最近的父元素(position不为static), 脱离文档流的布局
4.fixed(固定):固定定位,元素的位置相对于浏览器窗口是固定位置。脱离文档流的布局
75、左边固定,右边自适应的布局
76、百度移动端首页秒开是如何做到的?
2.使用:
①如果dom元素频繁地显示和隐藏,那么用v-show,这样效率高(因为dom元素的添加和删除会引起页面的重绘和重排)
②如果dom元素不会频繁地显示和隐藏,用v-if。
84、请你谈谈Cookie的弊端
a. 每个特定的域名下最多生成的cookie个数有限制
b. IE和Opera 会清理近期最少使用的cookie,Firefox会随机清理cookie
c. cookie的最大大约为4096字节,为了兼容性,一般不能超过4095字节
d. 安全性问题。如果cookie被人拦截了,那人就可以取得所有的session信息。
85、解释响应式布局,怎么实现的?优缺点?
响应式布局根据不同的浏览器分辨率和尺寸来展示页面结构,行为,表现的设计方式
原理:通过媒体查询检验不同的设备屏幕尺寸做处理,页面头部必须有meta声明viewport
优点:解决多设备适应问题,灵活性更强
缺点:工作量大,加载时间变长
86、什么是HTTPS,做什么用的呢?如何开启HTTPS?
(1)什么是HTTPS
https是http的加密版本,是在http请求的基础上,采用ssl进行加密传输。
(2)作用
加密数据,反劫持,SEO
(3)如何开启
生成私钥与证书,配置nginx,重启nginx
87、请问您对DOM事件流怎么理解?
事件流:就是事件的流向,即事件触发的顺序。
DOM事件流分为三个阶段:
1、第一个阶段是捕获阶段
2、第二个阶段是事件源
3、第三个阶段是冒泡阶段
88、jQuery是如何处理缓存的?
要处理缓存就是禁用缓存。
①、通过 . p o s t ( ) 方 法 来 获 取 数 据 , 它 的 默 认 就 是 禁 用 缓 存 的 。 ② 、 通 过 .post()方法来获取数据,它的默认就是禁用缓存的。 ②、通过 .post()方法来获取数据,它的默认就是禁用缓存的。②、通过get()方法来获取数据,可以通过设置时间戳来获取避免缓存。
(在url后面jia+(+new Date))
③、通过 . a j a x 方 法 来 获 取 数 据 , 只 要 设 置 c a c h e : f a l s e 就 可 以 了 89 、 .ajax方法来获取数据,只要设置cache:false就可以了 89、 .ajax方法来获取数据,只要设置cache:false就可以了89、(this)和this关键字在jquery中有何不同?
( t h i s ) 他 是 返 回 一 个 j Q u e r y 对 象 , 你 可 以 调 用 多 个 j Q u e r y 方 法 t h i s 代 表 当 前 这 个 元 素 , 他 是 J a v a S c r i p t 关 键 词 中 的 一 个 , 表 示 上 下 文 中 的 当 前 d o m 元 素 。 你 不 能 对 他 调 用 j Q u e r y 方 法 , 直 到 他 被 (this)他是返回一个jQuery对象,你可以调用多个jQuery方法 this 代表当前这个元素,他是JavaScript关键词中的一个,表示上下文中的当前dom元素。你不能对他调用jQuery方法,直到他被 (this)他是返回一个jQuery对象,你可以调用多个jQuery方法this代表当前这个元素,他是JavaScript关键词中的一个,表示上下文中的当前dom元素。你不能对他调用jQuery方法,直到他被()函数包裹
90、移动端是如何调试的?
真机调试之android手机+Chrome
真机调试之iphone +Safari
UC浏览器
模拟手机调试
微信内置浏览器调试
Debuggap(移动端调试工具)
抓包
为什么虚拟dom会提高性能?
虚拟dom相当于在js和真实dom中间加了一个缓存,利用dom diff算法避免了没有必要的dom操作,从而提高性能。具体实现步骤如下:
用JavaScript对象结构表示DOM树的结构;然后用这个树构建一个真正的DOM树,插到文档当中当状态变更的时候, 重新构造一棵新的对象树。然后用新的树和旧的树进行比较,记录两棵树差异把2所记录的差 异应用到步骤1所构建的真正的DOM树上,视图就更新了。
92、页面导入样式时,使用link和@import有什么区别?
相同的地方,都是外部引用CSS方式,
区别:
95、简述for…in和for…of的区别
102、isicroll和Swiper
Swiper常用于移动端网站的内容触摸滑动
Swiper是纯javascript打造的滑动特效插件,面向手机、平板电脑等移动终端,以及PC端网站。
Swiper能实现触屏焦点图、触屏Tab切换、触屏多图切换等常用效果。
Swiper开源、免费、稳定、使用简单、功能强大,是架构移动终端网站的重要选择!
isicroll主要是页面内的定位,定位光标,显示滚动条等
iScroll是一个高性能,资源占用少,无依赖,多平台的javascript滚动插件。一般用来做 例如:上拉加载、下拉刷新
103、说一下自己是怎么写响应式布局的?rem是怎么计算的?
响应式布局主要是用的媒体查询@media,支持IE9以上及其它浏览器。
可以查询设备分辨率,浏览器宽度等,设置不同的样式或者直接引入不同的样式表。
rem是根据(根元素)html的font-size来设定的。
104、了解几种跨域的方法,jsonp跨域原理?
跨域的方法:jsonp,webSocket,postMessage,window,name+iframe,cors.jsonp
跨域原理:利用
136、什么是逻辑短路?
逻辑短路是对于逻辑运算而言,是指仅计算逻辑表达式中的一部分便能确定结果,而不对整个表达式进行计算的现象。
137、的作用是什么?
包裹动态组件时,会缓存不活动的组件实例,主要用于保留组件状态或避免重新渲染。
eg:
比如有一个列表和一个详情,那么用户就会经常执行打开详情=>返回列表=>打开详情…这样的话列表和详情都是一个频率很高的页面,那么就可以对列表组件使用进行缓存,这样用户每次返回列表的时候,都能从缓存中快速渲染,而不是重新渲染
138、style标签写在body后与body前有什么区别?
页面加载自上而下 当然是先加载样式。
写在body标签后由于浏览器以逐行方式对HTML文档进行解析,
当解析到写在尾部的样式表(外联或写在style标签)会导致浏览器停止之前的渲染,等待加载且解析样式表完成之后重新渲染,在windows的IE下可能会出现FOUC现象(即样式失效导致的页面闪烁问题)
139、iframe的优缺点?
优点:
a. 解决加载缓慢的第三方内容如图标和广告等的加载问题
b. iframe无刷新文件上传(https://blog.csdn.net/lee_sire/article/details/65936104)
c. iframe跨域通信
缺点:
a. iframe会阻塞主页面的Onload事件
b. 无法被一些搜索引擎索引到
c. 页面会增加服务器的http请求
d. 会产生很多页面,不容易管理。
140、call和apply的区别
call和apply的作用是一样的,区别在于传入参数的不同
两者的区别:
apply()方法有两个参数,分别是运行函数的作用域,另一个是参数数组(可以是Array也可以是arguments)。
Call()方法的第一个参数和apply()的第一个参数一样,其它参数就是调用函数的参数(相当于把,apply第二个参数的每个元素单列出来)
(解释call和apply是干什么的)
每个函数都有两个非继承而来的方法apply()和call(),这两个方法的用途都是用来调用函数(在特定的作用域中),实际上等于设置函数体内的this对象的值。调用函数,实际上就是调用该函数对象的call内部方法。
141、Vue的双向数据绑定原理是什么?
v-model实际就是v-bind,v-on
vue.js 是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。
142、谈谈你对生命周期的理解
总共分为8个阶段创建前/后,载入前/后,更新前/后,销毁前/后。
创建前/后:
在beforeCreate阶段,vue实例的挂载元素el和数据对象data都为undefined,还未初始化。
在created阶段,vue实例的数据对象data有了,el还没有。
载入前/后:
在beforeMount阶段,vue实例的$el和data都初始化了,但还是挂载之前为虚拟的dom节点,data.message还未替换。
在mounted阶段,vue实例挂载完成,data.message成功渲染。
更新前/后:
当data变化时,会触发beforeUpdate和updated方法。
销毁前/后:
在执行destroy方法后,对data的改变不会再触发周期函数,说明此时vue实例已经解除了事件监听以及和dom的绑定,但是dom结构依然存在
143、什么是vue生命周期?
Vue 实例从创建到销毁的过程,就是生命周期。也就是从开始创建、初始化数据、编译模板、挂载Dom→渲染、更新→渲染、卸载等一系列过程,我们称这是 Vue 的生命周期。
144、第一次页面加载会触发哪几个钩子?
第一次页面加载时会触发 beforeCreate, created, beforeMount, mounted 这几个钩子。
145、DOM渲染在哪个周期中就已完成?
DOM 渲染在 mounted 中就已经完成了。
146、vuex有哪几种属性?
5种,分别是state、getter、mutation、action、module
1、state(保存数据 )
2、getter类似vue的计算属性(从基本数据派生的数据 )
3、mutation (修改state中的数据与跟踪状态有关)store.commit(提交更改数据的方法,同步!
4、action 可以提交mutation 在action中可以执行store.commit,并且action中可以有异步操作,如果要使用action,则需要执行store.dispatch
5、Module 就是模块化Vuex
147、说说你对SPA单页面的理解,它的优缺点分别是什么?
SPA(single page application)单页面应用,即一旦页面加载完成,SPA不会因为用户的操作而进行页面的重新加载或跳转,而是由路由机制实现HTML内容的变换
优点:
用户体验好,内容的改变不需要重新加载整个页面,避免了不必要的跳转和重复渲染,所以SPA相对对服务器的压力小
前后端职责分离,架构清晰,前端进行交互逻辑,后端负责数据处理
缺点:
初次加载耗时多
不利于SEO优化
不支持低版本的浏览器,最低只支持到IE9
不可以使用浏览器的导航按钮,需要自行配置路由实现前进、后退。
148、怎样理解单向数据流
这个概念出现在组件通信。父组件是通过 prop 把数据传递到子组件的,但是这个 prop 只能由父组件修改,子组件不能修改,否则会报错。
子组件想修改时,只能通过 e m i t 派 发 一 个 自 定 义 事 件 , 父 组 件 接 收 到 后 , 由 父 组 件 修 改 。 也 可 以 基 于 此 方 法 实 现 兄 弟 组 件 ( 父 子 组 件 、 隔 代 组 件 ) 之 间 的 信 息 通 信 。 149 、 v u e 常 用 的 事 件 修 饰 符 ? 1 、 . p r e v e n t : 阻 止 默 认 行 为 ; 2 、 . s t o p : 阻 止 单 击 事 件 冒 泡 ; 3 、 . s e l f : 当 事 件 发 生 在 该 元 素 本 身 时 候 会 触 发 ; 4 、 . c a p t u r e : 事 件 侦 听 , 事 件 发 生 的 时 候 会 调 用 ( 使 用 捕 获 , 冒 泡 的 时 候 是 不 理 的 ) 5 、 . o n c e 事 件 只 会 触 发 一 次 150 、 自 定 义 指 令 ( v − c h e c k 、 v − f o c u s ) 的 方 法 有 哪 些 ? 它 有 哪 些 钩 子 函 数 ? 还 有 哪 些 钩 子 函 数 参 数 ? ( 1 ) 1 、 全 局 定 义 指 令 : 在 v u e 对 象 的 d i r e c t i v e 方 法 里 面 有 两 个 参 数 , 一 个 是 指 令 名 称 , 另 外 一 个 是 函 数 v u e . d i r e c t i v e 2 、 组 件 内 定 义 指 令 : d i r e c t i v e s ( 2 ) 钩 子 函 数 : b i n d ( 绑 定 事 件 触 发 ) 、 i n s e r t e d ( 节 点 插 入 的 时 候 触 发 ) 、 u p d a t e ( 组 件 内 相 关 更 新 ) c o m p o n e n t U p d a t e d : 指 令 所 在 组 件 的 节 点 全 部 更 新 后 调 用 。 u n b i n d : 只 调 用 一 次 , 指 令 与 元 素 解 绑 时 调 用 。 ( 3 ) 钩 子 函 数 参 数 : e l 、 b i n d i n g 、 v n o d e : 虚 拟 节 点 。 o l d V n o d e : 上 一 个 虚 拟 节 点 。 151 、 构 建 的 v u e − c l i 工 程 都 用 了 哪 些 技 术 , 它 们 的 作 用 分 别 是 什 么 ? 1 、 v u e . j s : v u e − c l i 工 程 的 核 心 , 主 要 特 点 是 双 向 数 据 绑 定 和 组 件 化 系 统 。 2 、 v u e − r o u t e r : v u e 官 方 推 荐 使 用 的 路 由 框 架 。 3 、 v u e x : 专 为 V u e . j s 应 用 项 目 开 发 的 状 态 管 理 器 , 主 要 用 于 维 护 v u e 组 件 间 共 用 的 一 些 变 量 和 方 法 。 4 、 a x i o s ( 或 者 f e t c h 、 a j a x ) : 用 于 发 起 G E T 、 或 P O S T 等 h t t p 请 求 , 基 于 P r o m i s e 设 计 。 ∗ ∗ ∗ f e t c h 是 原 生 j s 写 的 , t h e n 两 次 , t h e n 回 来 的 是 r e s p o n s e ( 响 应 对 象 ) 对 象 , 赋 给 r e s o l v e a x i o s 是 封 装 好 的 , t h e n 一 次 5 、 v u x 等 : 一 个 专 为 v u e 设 计 的 移 动 端 U I 组 件 库 。 6 、 创 建 一 个 e m i t . j s 文 件 , 用 于 v u e 事 件 机 制 的 管 理 。 7 、 w e b p a c k : 模 块 加 载 和 v u e − c l i 工 程 打 包 器 。 152 、 路 由 跳 转 编 程 式 导 航 : t h i s . emit 派发一个自定义事件,父组件接收到后,由父组件修改。也可以基于此方法实现兄弟组件(父子组件、隔代组件)之间的信息通信。 149、vue常用的事件修饰符? 1、.prevent: 阻止默认行为; 2、.stop: 阻止单击事件冒泡; 3、.self: 当事件发生在该元素本身时候会触发; 4、.capture: 事件侦听,事件发生的时候会调用(使用捕获,冒泡的时候是不理的) 5、.once 事件只会触发一次 150、自定义指令(v-check、v-focus)的方法有哪些?它有哪些钩子函数?还有哪些钩子函数参数? (1) 1、全局定义指令:在vue对象的directive方法里面有两个参数,一个是指令名称,另外一个是函数vue.directive 2、组件内定义指令:directives (2) 钩子函数:bind(绑定事件触发)、inserted(节点插入的时候触发)、update(组件内相关更新) componentUpdated:指令所在组件的节点全部更新后调用。unbind:只调用一次,指令与元素解绑时调用。 (3) 钩子函数参数:el、binding、vnode:虚拟节点。oldVnode:上一个虚拟节点。 151、构建的 vue-cli 工程都用了哪些技术,它们的作用分别是什么? 1、vue.js:vue-cli工程的核心,主要特点是 双向数据绑定 和 组件化系统。 2、vue-router:vue官方推荐使用的路由框架。 3、vuex:专为 Vue.js 应用项目开发的状态管理器,主要用于维护vue组件间共用的一些 变量 和 方法。 4、axios( 或者 fetch 、ajax ):用于发起 GET 、或 POST 等 http请求,基于 Promise 设计。 *** fetch是原生js写的,then两次,then回来的是response(响应对象)对象,赋给resolve axios是封装好的,then一次 5、vux等:一个专为vue设计的移动端UI组件库。 6、创建一个emit.js文件,用于vue事件机制的管理。 7、webpack:模块加载和vue-cli工程打包器。 152、路由跳转 编程式导航:this. emit派发一个自定义事件,父组件接收到后,由父组件修改。也可以基于此方法实现兄弟组件(父子组件、隔代组件)之间的信息通信。149、vue常用的事件修饰符?1、.prevent:阻止默认行为;2、.stop:阻止单击事件冒泡;3、.self:当事件发生在该元素本身时候会触发;4、.capture:事件侦听,事件发生的时候会调用(使用捕获,冒泡的时候是不理的)5、.once事件只会触发一次150、自定义指令(v−check、v−focus)的方法有哪些?它有哪些钩子函数?还有哪些钩子函数参数?(1)1、全局定义指令:在vue对象的directive方法里面有两个参数,一个是指令名称,另外一个是函数vue.directive2、组件内定义指令:directives(2)钩子函数:bind(绑定事件触发)、inserted(节点插入的时候触发)、update(组件内相关更新)componentUpdated:指令所在组件的节点全部更新后调用。unbind:只调用一次,指令与元素解绑时调用。(3)钩子函数参数:el、binding、vnode:虚拟节点。oldVnode:上一个虚拟节点。151、构建的vue−cli工程都用了哪些技术,它们的作用分别是什么?1、vue.js:vue−cli工程的核心,主要特点是双向数据绑定和组件化系统。2、vue−router:vue官方推荐使用的路由框架。3、vuex:专为Vue.js应用项目开发的状态管理器,主要用于维护vue组件间共用的一些变量和方法。4、axios(或者fetch、ajax):用于发起GET、或POST等http请求,基于Promise设计。∗∗∗fetch是原生js写的,then两次,then回来的是response(响应对象)对象,赋给resolveaxios是封装好的,then一次5、vux等:一个专为vue设计的移动端UI组件库。6、创建一个emit.js文件,用于vue事件机制的管理。7、webpack:模块加载和vue−cli工程打包器。152、路由跳转编程式导航:this.router.push()
声明式跳转:< router-link to=””>
153、谈一谈Vue组件之间的参数传递?
父组件传给子组件:子组件通过props方法接收数据;
子组件传给父组件:$emit方法传递参数;
兄弟间组件通信:利用Vuex实现。
154、什么是MVVM?
(1) MVVM是Model-View-ViewModel的缩写。MVVM是一种设计思想。Model 层代表数据模型,也可以在Model中定义数据修改和操作的业务逻辑;View 代表UI 组件,它负责将数据模型转化成UI 展现出来,ViewModel 是一个同步View 和 Model的对象(桥梁)。在MVVM架构下,View 和 Model 之间并没有直接的联系,而是通过ViewModel进行交互, Model 和 ViewModel 之间的交互是双向的, 因此View 数据的变化会同步到Model中,而Model 数据的变化也会立即反应到View 上。
(2) ViewModel 通过双向数据绑定把 View 层和 Model 层连接了起来,而View 和 Model 之间的同步工作完全是自动的,无需人为干涉,因此开发者只需关注业务逻辑,不需要手动操作DOM, 不需要关注数据状态的同步问题,复杂的数据状态维护完全由 MVVM 来统一管理。
155、mvvm和mvc区别?
mvc和mvvm其实区别并不大。都是一种设计思想。主要就是mvc中Controller 演变成mvvm中的viewModel。
mvvm主要解决了mvc中大量的DOM 操作使页面渲染性能降低,加载速度变慢,影响用户体验。
156、的作用是什么?
包裹动态组件时,会缓存不活动的组件实例,主要用于保留组件状态或避免重新渲染。
157、v-show和v-if指令的共同点和不同点
v-show指令是通过修改元素的display的CSS属性让其显示或者隐藏
v-if指令是直接销毁和重建DOM达到让元素显示和隐藏的效果
如何通过HR⾯
HR通常是程序员⾯试的最后⼀⾯,讲道理刷⼈的⼏率不⼤,但是依然有⼈倒在了这最后⼀关上,我们会从HR的⻆度出发来分析如何应对HR⾯.
HR⾯的⽬的
HR⾯往往是把控⼈才质量的最后⼀关,与前⾯的技术⾯不同,HR⾯往往侧重员⼯⻛险的评估与基本的员⼯素质.
录⽤⻛险评估,这部分是评估候选⼈是否具备稳定性,是否会带来额外的管理⻛险,是否能⻢上胜任⼯作,⽐如频繁的跳槽会带了稳定性的⻛险,HR会慎重考虑这⼀点,⽐如在⾯试中候选⼈体现出了「杠精」潜质,HR会担⼼候选⼈在⼯作中会难以 与他⼈协作或者不服从管理,带来管理⻛险,再⽐如,虽然国家明确规定在招聘中不得有性别、年龄等歧视,但是⼀个⼤龄 已婚妇⼥会有近期产⼦的可能性,可能会有⻓期的产假,HR也会做出评估。
员⼯素质评估,这部分评估候选⼈是否具备职场的基本素质,是否有基本的沟通能⼒,是否有团队精神和合作意识等等,⽐如
⼀个表现极为内向的候选⼈,HR可能会对其沟通能⼒产⽣怀疑.
所以在与HR交流中要尽量保持踏实稳重、积极乐观的态度,切忌暴露出夸夸其谈、负能量、浮躁等性格缺陷。
HR⾯的常⻅问题
你对未来3-5年的职业规划
⽬的: 这个问题就是考察候选⼈对未来的规划能⼒,主要想通过候选⼈的规划来嗅出候选⼈对⼯作的态度、稳定性和对技术的追求.
分析: ⼀定要在你的回到中体现对技术的追求、对团队的贡献、对⼯作的态度,不要谈⼀些假⼤空的东⻄,或者薪资、职位这些太过于功利的东⻄,⽽且最好体现出你的稳定性,如果是校招⽣或者⼯作没⼏年的新⼈最好不要涉及创业这种话题,⼀⽅⾯职场新⼈计划没⼏年就创业,这种很不切实际,说明候选⼈没法按实际出发,另⼀⽅⾯说明候选⼈的稳定性不够.
还真有候选⼈因为谈创业被HR刷的建议分三部分谈:
如何看待加班(996)?
⽬的: 考察候选⼈的抗压能⼒和责任⼼
分析: 这个问题⼏乎是必问的,虽然996ICU事件闹得沸沸扬扬,但是官⽅的态度很暧昧,只⼝头批评从没有实际⾏动,基本上是默许企业违反劳动法的,除了个别外企在国内基本没可能找到不加班的公司,所以在这个⾯试题中尽量体现出⾃⼰愿意 牺牲⾃我时间来帮助团队和企业的意愿就⾏了,⽽且要强调⾃⼰的责任⼼,如果真的是碰到⽆意义加班,好好学习怎么⽤vscode刷LeetCode划⽔是正道.
建议:
⾯对⼤量超过⾃⼰承受能⼒且时间有限的⼯作时你会怎么办?
⽬的: 考察候选⼈时间管理和处理⼤量任务的能⼒,当然也会涉及⼀定的沟通能⼒
分析: 程序员的⼯作内容可能⼤部分时间并不在写代码上,⽽是要处理各种会议、需求和沟通,通常都属于⼯作超负荷的状态,⾯对上⾯这种问题不建议以加班的⽅式来解决,因为主要考察的是你的时间管理能⼒和沟通能⼒,这些要素要在回答中 体现出来
建议:
你之前在上海为什么现在来北京发展?
⽬的: 考察候选⼈的稳定性和职业选择
分析: 这个问题⼀般是上份⼯作在异地的情况下⼤概率出现,HR主要担⼼候选⼈异地换⼯作可能会不稳定,有短期内离职
⻛险,这个时候不建议说"北京互联⽹公司多,机会多"这种话(合着觉得北京好跳槽?),回答最好要体现出⾃⼰的稳定性,⽐ 如"⼥朋友在北京,⻓期异地,准备来北京⼀起发展" “家在北京,回北京发展” 等等,潜台词就是以后会在北京发展,不会在多地之间来回摇摆.
为什么从上⼀家公司离职?
⽬的: 考察离职原因,候选⼈离职⻛险评估
分析: 这个问题经常会在跳槽的时候问到,这个时候切忌吐槽上⼀家公司或者⾃⼰的上⼀任⽼板,尽量从职业发展的⻆度来回答,凸显⾃⼰的稳定性和渴望学习上升的决⼼,⾄于⼀些敏感话题,⽐如加班太多、薪资太低这种问题也是可以谈的, 毕竟你跳槽的诉求就是解决上家公司碰到的问题,但是不能触碰刚才提到的底线问题,切忌吐槽向.
建议:
你还有其他公司的Offer吗?
⽬的: 评估候选⼈是否有短时间内⼊职其他公司的可能性
分析: 很多时候并不是候选⼈完美符合⼀个岗位的要求,HR当然想要⼀个技术更好、要钱更少、技术更匹配的候选⼈, 但是候选⼈⼀般都会有这样或者那样的⼩问题。
⽐如,你的表现是可以胜任⽬前的岗位的,但是这个岗位不是很紧急,HR可能把你当做备胎,来找⼀个性价⽐更⾼的候选⼈.
⽐如,你的表现很好,履历优秀,HR不知道能不能100%拿下你.
所以如果你很希望加⼊这个公司,最好要做到「欲擒故纵」,既要体现⾃身的市场竞争⼒,⼜要给到HR⼀定的压⼒.
所以,即使你已经拿了全北京城互联⽹公司的offer了,也不要说⾃⼰offer多如⽜⽑,⼀副满不在乎的样⼦,这样会给HR造成他⼊职可能性不⼤的错觉,因为他的选择太多了.
当然,也不要跪在地上舔:“加⼊公司是我的梦想,我只等这⼀个offer”,放⼼吧,⼀定被hr放到备胎⼈才库中. 建议:
如何与HR谈薪资?
HR与你谈论薪资经常有如下套路:
HR: 您期望的薪资是多少? 你: 25K。
OK,你已经被HR成功套路。这个时候你的最⾼价就是25K了,然后HR会顺着这个价往下砍,所以你最终的薪资⼀般都会低于25K。等你接到offer,你的⼼⾥肯定充满了各种“悔恨”:其实当时报价26、27甚⾄28、29也是可以的。
正确的回答可以这样,并且还能够反套路⼀下HR:
HR: 您期望的薪资是多少?
你: 就我的⾯试表现,贵公司最⾼可以给多少薪⽔?
哈哈,如果经验不够⽼道的HR可能就真会说出⼀个报价(如25K)来,然后,你就可以很开⼼地顺着这个价慢慢地往上谈了。所以这种情况下,你最终的薪资肯定是⼤于25K的。当然,经验⽼道的HR会给你⼀句很官⽅的套话:
HR: 您期望的薪资是多少?
你: 就我的⾯试表现,贵公司最⾼可以给多少薪⽔?
HR: 这个暂且没法确定,要结合您⼏轮⾯试结果和⽤⼈部⻔的意⻅来综合评定。
如果HR这么回答你,我的建议是这样的:
虽然薪资很重要,但是我个⼈觉得这不是最重要的。我有以下建议:
如果你觉得你技术⾯试效果很好,可以报⼀个⾼⼀点的薪资,这样如果HR想要你,会找你商量的。如果你觉得技术⾯试效果⼀般,但是你⽐较想进这家公司,可以报⼀个折中的薪资。
如果你觉得⾯试效果很好,但是你不想进这家公司,你可以适当“漫天要价”⼀下。 如果你觉得⾯试效果不好,但是你想进这家公司,你可以开⼀个稍微低⼀点的⼯资。
需要注意的是,⾯试求职是⼀个双向选择的过程。⾯试应该做到不卑不亢,千万不要因为⾯试结果不好,就低声下⽓地乞求⼯作,每个⼈的⼯作经历和经验都是不⼀样的,技术⾯试不好,知道⾃⼰的短板针对性地补缺补差就⾏,⽽不是在
⼈事关系上动歪脑筋。
参考:
⾯试技巧 | 技术岗位⾯试如何与HR谈薪
⾯试回答问题的技巧
技术⾯试通常⾄少三轮:
⾃我介绍
⼏乎所有的⾯试都是从⾃我介绍这个环节开始的,所以我们得搞清楚为什么⾃我介绍通常作为⼀个⾯试的开头.
为什么需要⾃我介绍
⾸先,有⼀个很普遍的问题就是⾯试官很可能才刚拿到你的简历,他需要在你⾃我介绍的时候快速浏览你的简历,因为技术
⾯试的⾯试官很多是⼀线的员⼯,⾯试候选⼈只是其⼯作中的⼀⼩部分,很多情况下是没有提前看过你的简历的.
其次,⾃我介绍其实是⼀个热身,⾯试官和候选⼈其实是陌⽣⼈,⾃我介绍不管是⾯试还是其他情况下,都是两个陌⽣⼈彼此交流的起点,也是缓解候选⼈与⾯试官之间尴尬的⼀种热身⽅式.
最后,⾃我介绍是展示⾃我、引出接下来技术⾯试的引⼦,是你⾃⼰指定技术⾯试⽅向的⼀次机会。知道了以上原因,我们才能进⾏准备更好的⾃我介绍。
⾃我介绍的⼏个必备要素
⾃我介绍归根到底是⼀个热身运动,因此切忌占⽤⼤量的篇幅,上来就把⾃⼰从出⽣的经历到⼤学像流⽔账⼀样吐出来的, 往往会被没耐⼼的⾯试官打断,⽽这也暴露了候选⼈讲话缺乏重点、沟通能⼒⼀般的缺点。
但是,⼀些关键信息是必须体现的,就我个⼈⽽⾔,以下信息是必备的:
个⼈信息: ⾄少要体现出⾃⼰的姓名、岗位和⼯作年限,应届⽣则必须要介绍⾃⼰的教育背景,如果⾃⼰的前东家是个⼤⼚(⽐如BAT)最好提及,⾃⼰的学历是亮点(985或者硕博或者类似于北邮这种CS强校)最好提及,其他的什么有没有⼥朋友、是不是独⽣⼦没⼈在意,不要占⽤篇幅。这个部分重点在于「你是谁?」。
技术能⼒: 简要地介绍⾃⼰的技术栈,切忌把⾃⼰只是简单使⽤过,写过⼏个Demo或者看了看⽂档的所谓「技术栈」也说出来,⼀旦后⾯问到算是⾃找尴尬。这个部分的重点在于「你会什么?」。
技能擅⻓: 重点介绍⾃⼰擅⻓的技术,⽐如性能优化、⾼并发、系统架构设计或者是沟通协调能⼒等等,切忌夸⼤其词,要实事求是,这是之后考察的重点。这个部分重点⾃在于「你擅⻓什么?」。
⾃我介绍要有⽬的性
要重点匹配当前岗位的技术栈
你的⾯试简历可能包含了各种各样的技术栈,但是在⾃我介绍过程中需要匹配当前岗位的技术要求.
就⽐如你⽬前⾯试的是移动端H5前端的开发岗位,就重点在⾃我介绍中突出⾃⼰在移动前端的经验,⽽此时⼤篇幅得讲述
⾃⼰如何⽤Node⽀撑公司的web项⽬就显得很不明智.
要在⾃我介绍中做刻意引导
如果你的⾃我介绍跟流⽔账⼀样,没有任何重点,其实⾯试官也很难办,因为他都没法往下接话…
⽽只要你稍作引导,绝⼤部分⾯试官就会接你的话茬,⽐如「你在⾃我介绍中重点提及了⼀个项⽬,碰到了⼀些难点,然后被你攻克了,效果如何如何好等等」,如果我是⾯试官⼀定会问「你的xx项⽬的xx难点后来是怎么解决的?」。
⾯试官的⽬的是考察候选⼈的能⼒,对候选⼈做出评估,因此需要知道候选⼈擅⻓什么,是否匹配岗位,⾯试官绝⼤多数情况下很乐意你这种有意⽆意的引导,这样双⽅的沟通和评估会很顺利,⽽不是故意刁难候选⼈。
如何准备⾃我介绍
其实最好的⽅法也是最笨的⽅法就是把⾃我介绍写下来,这个⾃我介绍⼀定要体现上⾯提到的⼏⼤必备要素,在⾯试前简单过⼏遍,能把⾃我介绍的内容顺利得表达出来即可,切忌跟背课⽂⼀样.
⾃我介绍的时间最好控制在1-3分钟之间,这些时间⾜够⾯试官把你的简历过⼀遍了,⾯试官看完简历后正好接着你的⾃我介绍进⾏提问是最舒服的节奏,别上来开始10分钟的演讲,⾯试官等待的时候会很尴尬,这么⻓的篇幅说明你的⾃我介绍⼀定是流⽔账式的.
技术考察
⼀个好的技术考察的开始,必须得有⾃我介绍部分好的铺垫和引导,有⼀种情况我们经常遇⻅:
候选⼈说了⼀⼤堆⾮重点的⾃我介绍,⾯试官⼀时语塞,完全get不到候选⼈的重点,也不知道候选⼈擅⻓什么、有什么亮点项⽬,然后就在他简历的技术栈中选了本公司也在⽤的技术,候选⼈这个时候也开始冒汗,因为这个技术 栈并不是他的擅⻓,回答的也磕磕绊绊,⾯试官的引导和深⼊追问也没有达到很好的效果,⾯试就在这种尴尬的
⽓氛中展开了,⾯试结束后⾯试官对候选⼈的评价是技术不熟练、没有深⼊理解原理,候选⼈的感受是,⾯试官专挑⾃⼰不会的问。
所以在前⾯的部分,⼀定要做好引导,把⾯试官的问题引到我们擅⻓的领域,但是这样还不够,正所谓不打⽆准备之仗,我们依然需要针对可能出现的问题进⾏准备.
那么如何准备可能的⾯试题?
⽐如你擅⻓前端的性能优化,在⾃我介绍的部分已经做好了引导,接下来⾯试官⼀定会重点考察你性能优化的能⼒,很可能会涉及很有深度的问题,即使你擅⻓这⽅⾯的技术,但是如果没有准备也可能临场乱了阵脚.
多重提问
⾃我多重提问的意思是,当⼀个技术问题抛出的时候,你可能⾯对更深层次的追问
依旧以前端性能优化为例,⾯试官可能的提问:
答题法则
很多⾯试相关的宝典都推荐使⽤STAR法则进⾏问题的应答,我们不想引⼊这个额外的概念,基础技术⾯试的部分⽼⽼实实回答⾯试官的问题即可,通常需要问题运⽤到这个法则的是项⽬⾯,⽐如让你介绍⼀下你最得意的项⽬,回答问题的法则有 这⼏个要点:
项⽬背景: 简要说⼀下项⽬的背景,让⾯试官知道这个项⽬是做什么的个⼈⻆⾊: 让⾯试官知道你在这个项⽬中扮演的⻆⾊
难点: 让⾯试官知道你在项⽬开发过程中碰到的难点
解决⽅案: 针对上⾯的难点你有哪⼀些解决⽅案,是如何结合业务进⾏取舍的
总结沉淀: 在攻克上述的难点后有没有沉淀出⼀套通⽤的解决⽅案,有没有将⾃⼰的⽅案在⼤部⻔进⾏推⼴等等
重点就在于后⾯三条,也是最体现你个⼈综合素质的⼀部分,我是⾯试官的话会⾮常欣赏那种可以发现问题、找到多种⽅案、能对多种⽅案进⾏⽐对取舍还可以总结沉淀出通⽤解决⽅案回馈团队的⼈。
从上述⼏点可以体现出⼀个⼈的技术热情、解决问题的能⼒和总结提⾼的能⼒。
刻意引导
是的,在回答⾯试官提问的时候也可以做到刻意引导。我们就举⼏个简单的例⼦:
除了Vue还⽤过Angular吗? 这个时候很多候选⼈就很实诚回答「没有」,其实我们可以回答的更好,把你知道的说出来展示⾃⼰的能⼒才是最重要的,你可以说「我虽然没⽤过,但是在学习双向绑定原理的时候了解了⼀下Angular脏检查的原理,在学习Nestjs的时候了解了依赖注⼊的原理,跟Angular也是类似的」,⾯试官⼀定会接着 问你脏检查和依赖注⼊的问题,虽然你没有⽤过Angular,但是Angular的基本原理你都懂,这是很好的加分项,说明候选⼈有深⼊理解原理的意愿和触类旁通的能⼒
Vue如何实现双向绑定的? 很多候选⼈⽼⽼实实答了 object.defineproperty 如何如何操作,然后就没有了,其实你可以在回答完之后加上⼀嘴「Vue 3.0则选择了更好⽤的Proxy来替代object.defineproperty」或者「除了object.defineproperty这种数据劫持的⽅式,观察者模式和脏检查都可以实现双向绑定」,⾯试官⼤概率会问
「Proxy好在哪?」或者「聊聊脏检查」等等,这样下⼀个问题就会依然在你的可控范围内
我们第⼀个例⼦把本来回答不上来的问题,转化为了成功展示⾃⼰能⼒的加分项,第⼆个例⼦让⾃⼰更多的展示了⾃⼰的能⼒,⽽且始终使⾯试官的问题在⾃⼰的可控范围内。
向⾯试官提问
这个部分基本到了⾯试尾声了,属于做好了不影响⼤局,但是可能加分,如果做不好很容易踩雷的区域.
⾸先我们声明⼏个雷区:
切忌问结果: 问了也⽩问,绝⼤部分公司规定不会透露结果的,你这样让⼤家很尴尬
切忌问⼯资: 除了HR跟你谈⼯资的时候,千万别跟技术⾯试官谈⼯资,⼯资是所有公司的⾼压线,没法谈论切忌问技术问题: 别拿⾃⼰不会的技术难题反问⾯试官,完全没意义,⾯试官答也不是不答也不是
有⼏个⽐较好的提问可供参考:
如果我⼊职这个岗位的话,前三个⽉你希望我能做到些什么? 我的这个岗位的前任是为什么离职的,我什么地⽅能做的更好? 你对这个职位理想⼈选的要求是什么?
尽量围绕你的岗位进⾏提问,这可以使得你更快得熟悉你的⼯作内容,也让⾯试官看到你对此岗位的兴趣和热情,重要的是这些问题对于⾯试官⽽⾔既可以简略回答,也可以详细的给你讲解,如果他很热情得跟你介绍此岗位相关的情况,说明你可能表现得不错,否则的话,你可能不在他的备选名单⾥,这个时候就需要你早做打算了.
总结
我们⽤⼤量篇幅介绍了技术⾯试中的⼀些应试技巧,但是归根到底候选⼈的基本功和丰富的项⽬经验才是硬道理.
如果你看完了整篇⽂章,并进⾏了精⼼的准备,他是可以让你从75分到85分的实⽤技巧,⽽不是让你从55到85的什么秘籍.
⾯试官到底想看什么样的简历?
⾯试⼀直是程序员跳槽时期⾮常热⻔的话题,虽然现在已经过了跳槽的旺季,下⼀轮跳槽季需要到年底才会出现,但是当跳槽季的时候你再看这篇⽂章可能已经晚了,过冬的粮⻝永远不是冬天准备的,⽽是秋收的时候。
简历准备
简历是你进⼊⾯试的敲⻔砖,也是留给意向公司的第⼀印象,所以这个很重要,必须在这上⾯做⾜了⽂章,⼀份优秀的
⾯试简历是整个⾯试成败的重中之重,我们会详细分析如何准备简历才能保证简历不被刷掉。
简历通常有这⼏部分构成:
准备简历模板
万事开头难,简历的编写如果从头开始需要浪费很多时间,其实最快速也最聪明的办法就是先找⼀份还不错的简历模板,之后我们只需要填写信息即可。
简历模板的选择很讲究,有些简历基本不看内容就会被刷掉,这些简历⼀般会对⾯试官进⾏视觉攻击,让简历给⾯试官的第⼀印象就是反感。
有两种坑爹的简历模板:
⼀种是经典简历模板,真是堪称『经典』,这种简历模板在我上⼩学的时候就有了,以现在的眼光看有点不够看了,配
⾊也⽐较『魔幻』,加上表格类的简历属于low到底端的简历类型,基本上扫⼀眼就扔了,这种简历只需要3秒钟就能被
⾯试官扔到垃圾堆。
另⼀种是设计感⼗⾜的简历模板,这种简历设计感⼗⾜,这五颜六⾊的配⾊⼀定能亮瞎⾯试官的双眼,这种花⾥胡哨的简历同样也是3秒钟沉到垃圾堆底部的简历。
以上两类简历模板堪称⾯试官杀⼿,我相信只要你⽤了上述两类模板,绝对连让⾯试官看第⼆眼的兴趣都没有。
⾯试官筛简历要的是⾼效、清晰、内容突出,不管是HR还是技术⾯试官都想在最快速的情况下看到有效信息,你眼中 所谓的『视觉效果』在别⼈眼⾥就是『视觉噪⾳』或者『视觉垃圾』,严重影响看简历的⼼情和寻找有效信息的速度。
其实我发现不仅仅是在互联⽹技术招聘这个领域,⼤部分企业招聘的简历要求都很简单,清晰、简洁即可,最重要的是要内容清晰,突出主题。
就像这样,颜⾊不超过⿊⽩灰三⾊,把强调的内容讲清楚,让⾯试官⼀眼就看到重点即可:
准备个⼈信息
个⼈信息部分主要包括姓名、电话、点⼦邮箱、求职意向,当然这四个是必填的,其它的都是选填,填好了是加分项, 否则很可能减分。
接下来才是重点:
准备专业技能
对于程序员的专业技能其实就是技术栈,对于⾃⼰的技术栈如何描述是个很难的问题,⽐如什么算是精通?什么算是了解?什么是熟悉?
关于对技术技能的描述有很多种,有五种的也有三种的,⽽且每个⼈对词汇的理解都不⼀样,我结合相关专家的理解和
⾃⼰的理解来简单阐述下描述词汇的区别,我们这⾥只讲三种的了解、熟悉、精通。
了解:使⽤过某⼀项技术,能在别⼈指导下完成⼯作,但不能胜任复杂⼯作,也不能独⽴解决问题。
熟悉:⼤量运⽤过的某⼀项技术,能独⽴完成⼯作,且能独⽴完成有⼀定复杂度的⼯作,在技术的应⽤层⾯不会有太⼤问题,甚⾄理解⼀点原理。
精通:不仅可以运⽤某⼀⻔技术完成复杂项⽬,⽽且理解这项技术背后的原理,可以对此技术进⾏⼆次开发,甚⾄本身就是技术源码的贡献者。
我们就以Vue这个框架为例,如果你可以⽤vue写⼀些简单的⻚⾯,单独完成某⼏个⻚⾯的开发,但是⽆法脱离公司脚
⼿架⼯作,也⽆法独⽴从0完成⼀个有⼀定复杂度的项⽬,只能称之为了解。
如果你有⼤量运⽤vue的经验,有从0独⽴完成⼀定复杂度项⽬的能⼒,可以完全脱离脚⼿架进⾏开发,且对vue的原理有⼀定的了解,可以称之为熟悉。
如果你⽤vue完成过复杂度很⾼的项⽬,⽽且⾮常熟悉vue的原理,是vue源码的主要贡献者,亦或者根据vue源码进⾏过魔改(⽐如mpvue),你可以称得上精通。
那么有两个坑是候选⼈经常犯的,『杂』和『精』,这种两个坑⼤量集中在应届⽣和刚毕业每两年的新⼿身上,其主要特点是『急于表现⾃我』、『对技术深度与⼴度出现⽆知⽽导致的过度⾃信』。
⾸先说说杂,⽐如你要应聘⼀个Java后端,⽼⽼实实把⾃⼰的java技术栈写好就⾏了,强调⼀下⾃⼰擅⻓什么即可,最好专精某领域⽐如『⾼并发』、『⾼可⽤』等等,这个时候⼀些简历⾮要给⾃⼰加戏,⾃⼰会的不会的⼀股脑往上堆, 什么逆向、密码学、图形、驱动、AI都要体现出来,越杂越好,这种简历给⼈的印象就是个什么都不懂的半吊⼦。
再说说精,⼀个刚毕业的应届⽣,出来简历就各种精通,精通Java、精通Java虚拟机、精通spring全家桶、精通kafka 等等,请放⼼,这种简历是不会没头没脑投过来了,这种在⼤学⾥就精通各种的天才早被他的各种学⻓介绍进了⼤⼚或者外企做某某Star重点培养了,往往看到的这种也是半吊⼦。
再给⼤家⼀个技术栈模板:
这样写的后果就在于让⾯试官⼀眼就看出你是个吹⽜的半吊⼦,那些各种精通的全才在业界早就出名了,根本不可能还在投简历。
准备⼯作经历
⼯作经历本身不⽤花太多笔墨去写,⾯试官主要想看的就是每段⼯作经历的持续时间、在不同公司担任的职责如何、是否有⼤⼚的⼯作经验等等。
那么什么简历在这⾥给⾯试官减分呢?
频繁跳槽:⽐如三年换了四家公司,每个公司呆的时⻓不要超过⼀年常年初级岗:⽐如⼯作五六年之后依然在完成⼀些简单的项⽬开发
末流公司经历:在技术招聘届,⼤⼚的优先级最⾼⽐如BAT、TMD甚⾄微软、⾕歌等外企,知名度独⻆兽其次,⽐如商汤、旷视等等,⼀般的互联⽹公司排在第三,就是⼯作中⼩型的互联⽹公司⼀般⼤家叫不上名字,排在最后的就是外包和传统企业的经历
所以,如果你有频繁跳槽的经历怎么办?在本公司⽼⽼实实等到满⼀年再跳槽。
如果常年初级岗怎么办?想办法晋升或者参与⼀些业界知名项⽬,再或者写⼀个有⼀定复杂度的私⼈项⽬。
如果有末流公司经历怎么办?如果是很久以前的末流公司经验可以直接不写,也没⼈在乎你很早之前的⼯作经历,如果你现在就在末流公司,赶紧想办法跳槽,去不了⼤⼚,去⾮知名的互联⽹公司也算是胜利⼤逃亡了。
不建议任何形式的简历造假,如果去⼀些⼤⼚,分分钟背调出来,与其简历造假,不如现在就⾏动起来,⽐如从现在到年底跳槽季,深度参与⼀个知名开源项⽬或者做⼀个有⼀定复杂度的私⼈项⽬绰绰有余,除⾮996.
准备项⽬经历
项⽬经历不管对于社招还是校招都是重中之重,很多时候成败就在于项⽬经历这块,⼀个普通本科可以通过优秀的项⽬经历逆袭985,⼀个⼩⼚的员⼯也可以获得⼤⼚的⾯试机会。
但是必须要说⼀下项⽬经历的编写很讲究,这是为后⾯⾯试部分铺路的绝佳机会,也是直接让你的简历扑街的重点沦陷区域。
先说容易让简历扑街的⼏个坑位。
切忌流⽔账写法
项⽬经历流⽔账写法是绝⼤多数简历的通病,通篇下来就讲了⼀件事『我⼲了啥』。
⼤部分简历却是这样的:
⽤Vue、Vuex、Vue-router、axios等技术开发电商⽹站的前端部分,主要负责⾸⻚、店铺详情、商品详情、商品列表、订单详情、订单中⼼等相关⻚⾯的开发⼯作,与设计师与后端配合,可要⾼度还原设计稿。
这个描述有什么问题?
其实看似也没啥问题,但是这种流⽔账写法太多了,完全⽆法突出⾃⼰的优势展现⾃⼰的能⼒。
项⽬经历是考察重点,⾯试官想知道候选⼈在⼀次项⽬经历中扮演的⻆⾊、负责的模块、碰到的问题、解决的思路、达成的效果以及最后的总结与沉淀。
⽽上⾯的描述只显示了『我⼲了啥』,所以这种项⽬描述⼏乎是没意义的,因为对于⾯试官⽽⾔他看不到有效信息,没有有效信息的项⽬描述基本就没价值了,如果这个时候你还没有⼤⼚经历或者名校背书,基本上也就凉了。
切忌堆积项⽬
堆积项⽬这种现象往往出现在没有什么优秀项⽬经历的简历身上,候选⼈企图以数量优势掩盖质量的劣势,其实往往适得其反,项⽬经历的⼀栏最好放2-3个项⽬,⾮常优秀的项⽬可能放⼀个就⾜够了,举个极端例⼦如果有⼀天尤⾬溪写 简历,其实只需要在项⽬经历那些⼀⾏『Vue.js作者』就⾏了,当然,他并不需要投简历。
有⼀些项⽬切忌放上去:
demo级项⽬:很多简历居然还在放⼀些仿xx官⽹的demo,这是⼗⾜的减分项,有⼀些则是东拼⻄凑抄了⼀些框架的源码搞了个玩具项⽬,也没有任何价值。
烂⼤街的项⽬:这种以vue技术栈的为最,由于视频⽹站的某⻔课程流⾏,导致⼤量的仿饿了么、仿qq⾳乐、仿美团、仿去哪⼉,同样Java的同学也是仿电商⽹站、仿⼤众点评等等,⼗份简历5份⼀模⼀样的项⽬,你是⾯试官会怎么想。
低质量的开源项⽬:⼀个⼤原则就是低star的尽量别放(除⾮是⾼质量代码的冷⻔项⽬),⻓期弃坑的也不要放, 不要为了凑数量把低质量的项⽬暴露出来,好好藏着。
如果只放两个项⽬,最好的搭配是⼀个公司内部挑⼤梁的项⽬和⼀个社区内的开源项⽬,后者之所以可以占据⼀席之 地,是因为通过你的开源项⽬,⾯试官可以通过commit完整看到你的创造过程,⽐如⼯程化建设、commit规范、代码规范、协作⽅式、代码能⼒、沟通能⼒等等,这甚⾄⽐⾯试都有⽤,没有⽐开源项⽬更能展示你综合素质的东⻄了。
切忌放虚假项⽬
⼀个项⽬做没做过只要是有经验的⾯试官⼀问便知,如果你真的靠假项⽬忽悠过了⾯试,那这个公司⼋成也有问题,⼈才把关不过硬,你可以想象你的队友都是什么⽔平,在这种公司⼤成⻓价值也不⼤。
好,如果你说实在没项⽬可写了,我只能造假了,那么你应该想⼀下这多层追问。
⽐如你说你优化了⼀个前端项⽬的⾸屏性能,降低了⽩屏时间,那么⾯试官对这个性能优化问题会进⾏深挖,来考察候选⼈的实际⽔平:
合格的项⽬经历如何写
合格的项⽬经历必须要有以下⼏点: 项⽬概述
个⼈职责项⽬难点
⼯作成果
如果你不怕字太多,还可以选择性加⼊解决⽅案、选型思路等等,但是由于篇幅限制和为⾯试铺垫就不太建议写得太多。
项⽬概述的⽬的是让⾯试官理解项⽬,不是每个⼈⾯试官都做过你的那种项⽬,所以需⼀个简述⽅便⾯试官理解。
个⼈职责就是告诉⾯试官你在本项⽬中扮演的⻆⾊,是领导者?主导者?还是跟随者,你负责了哪些模块,承担了多⼤的⼯作量,以此来评估你在团队中的作⽤。
项⽬难点的⽬的在于让⾯试官看到你碰到的技术难题,⽅便后续⾯试对项⽬进⾏⼀系列讨论。
⼯作成果就很明显了,⾯试官需要看到你在做了上述⼯作到底达成了什么成绩,这个时候最好以数据说话,⽐如访问量、⽩屏时间等等。
像这种项⽬经历描述就⽐较合适:
这个时候也切忌展开⻓篇⼤论,把技术细节⼀个个写上去,甚⾄还写了⼼路历程的都是⼤忌,⼀⽅⾯篇幅太⼤会造成视觉混乱,另⼀⽅⾯⾯试官想看到的是『简』历,不是技术总结,⾯试官要⾯对上百份简历没那么时间来看你⻓篇⼤论,
⻓篇⼤论⼤可以在⾯试中展开。
最好的⽅法就是⼀⾏⽂字简单得说清楚即可,反正项⽬⾯的时候⼀定会问到,到时候好好把你准备的内容讲给⾯试官, 掌握⾯试的主动权就是从项⽬经历这⼀栏中开始。
教育背景
应届⽣可以写得更详细⼀点,⽐如绩点排名怎么样,有没有突出的科⽬,社招就不要写太多了,简单的⼊学时间、学校、专业即可,⽽且写你的最⾼学历即可,没必要从初中就开始写学历流⽔账,没有⼈看的。
⼏点注意事项
⾃我评价不建议写:技术⾯试⼏乎没⼈看你的⾃我评价,连⾯试技术问题都嫌『talk is cheap show me the code』,你的⾃我评价除了占篇幅没啥⽤处,充其量算是⾯试官的⼲扰信息。
简历封⾯千万别搞:这都是⼀些简历制作⽹站骗⽤户付费的伎俩,不仅是互联⽹⾏业,其它⾏业我也没⻅过要简历封⾯这种⽆⽤操作的。
证书不建议写:应届⽣可以酌情考虑弄个六级证书什么的,对于社招⽽⾔,列⼀堆证书甚⾄是减分项,国内的各种证你也懂的,是有多不⾃信才沦落到靠⼀堆证书来证明⾃⼰的价值。
千万别⽤技能图表:⾸先⽤90分、80分来评价⾃⼰的技术本身就没有什么说服⼒,也不可能这么精准,⽽且什么是90分、什么是80根本就没有⼀个公论,所以⽤⼀般的⽐较通⽤的熟悉、精通描述即可,千万别加戏,⾯试官或者 HR没那么多闲⼯夫去理解你的图表,⽼⽼实实按最通⽤⾼效的⽅式描述⾃⼰的技术栈。
简历最好⼀⻚:程序员⼜不是设计师有时候需要作品呈现,如果你的简历超过⼀⻚那么⼀定是出问题了,要么项
⽬、技术栈描述太多太杂占据⼤量篇幅,要么加了⼀堆图表或者图画来加戏,当然往往是犯前⼀个错误的更多。
这是我在⽹上找到的⼀个例⼦很能说明问题:
简历的版⾯⼨⼟⼨⾦,别说话跟裹脚布⼀样,精炼的⼀句话即可描述你的问题。
不建议⽤任何简历制作⽹站或者开源的简历制作器:我之前不仅⽤过上述的东⻄,还付过费,完全是浪费时间和浪费⾦钱,先说简历制作⽹站基本上都是那种花⾥胡哨的简历,看起来炫但是基本是⾯试官最讨厌的那种形式,开源的简历制作器也是类似的,我甚⾄还为了⾃⼰的简历魔改过这种制作器,到头来也是浪费时间,记住简历『⿊⽩ 灰』三个配⾊,简洁即可,切勿让简历形式喧宾夺主。
这是我整理的简历范本(项⽬经历可以多写⼀个):
你可能的疑问
如果你读到这⾥,谢谢你的耐⼼,可能你也会有疑问–『你这篇⽂章,这不让写,那不让写,我的简历填都填不满,怎么办?』。
实际上⼀份简历很多部分是已经固定了的,⽐如个⼈信息、教育背景、⼯作经历等等,其实能做⽂章的部分也只有技术栈和项⽬经历,也就是说后⾯两个部分是可以靠当下努⼒来改变的。
举个简单的例⼦,⽐如你做了3年的Java开发,公司还是⽤很⽼旧的SSM技术栈,⾃⼰其实有点沦为框架⼩⼦的意思, 只能做⼀些增删改查这种类型的⼯作,虽然⼯作内容都能胜任,但是根本做不了更有挑战性的事情,⽽外⾯对Java⼯程师的要求已经越来越⾼了.
我们完全可以花半年到⼀年的时间对某个细分领域进⾏专⻔的学习和实践,我们可以通过写私⼈项⽬、参与开源项⽬的
⽅式增加⾃⼰的项⽬经验和项⽬履历,⼀段时间后你肯定在某个细分领域⾄少处于⼀个进阶⽔平,你的简历也不可能填都填不满。
对于前端⼯程师也是⼀样,如果你觉得你逐渐沦为⻚⾯仔,⾃⼰也没有拿得出⼿的项⽬,也不妨多思考之前的项⽬是不是有的性能部分可以优化,是不是平时的⼯作有很多重复性的,能不能通过node⼯具或者vscode插件来提⾼效率,⼜ 或者公司的框架⽤起来太繁琐,可不可以进⾏改造升级提⾼⽣产⼒。
这个时候可能有⼈⼜问,『我⾃⼰⼯作都多的不⾏,凭什么还想为公司写什么⼯具框架?公司会额外付钱吗?』
你写的框架和⼯具是你未来跳槽中的简历的重要部分,即使它现在不会变现,在你跳槽过程中⼀定会变现,总之这些额外⼯作是为你⾃⼰打⼯的,你的现任公司只是因此额外受益了⽽已。
总结
我知道现在并不是跳槽的旺季,可能很多⼈不会看这篇⽂章,但是当真正跳槽季来临的时候,往往很多⼈⼜开始为填满
⾃⼰的简历⽽发愁,当⾃⼰的简历⽯沉⼤海,⼜会冒出这种⾔论:
哎呀,还是⾃⼰学历不够好,我能⼒没问题就是吃了学历的亏
⾃⼰没有⼤⼚的履历真是吃亏,⾃⼰能⼒没问题,就是没⼤⼚背书所在的公司都是⼀些⽼技术栈,我的简历就太吃亏了,都怪公司
实际情况是,⼤⼚履历、名校经历、出⾊项⽬只要有⼀项拿得出⼿,就会成为抢⼿货,更何况随着时间的推移,教育背景就越发不重要,更重要的还是⼯作履历和项⽬经历。
与其今后发愁如何填满简历,不如现在⾏动为⾃⼰的简历『打⼯』。
一、HTML和CSS
1、你做的页面在哪些浏览器测试过?这些浏览器的内核分别是什么?
IE: trident内核
Firefox:gecko内核
Safari:webkit内核
Opera:以前是presto内核,Opera现已改用Google Chrome的Blink内核
Chrome:Blink(基于webkit,Google与Opera Software共同开发)
2、每个HTML文件里开头都有个很重要的东西,Doctype,知道这是干什么的吗?
3、Quirks模式是什么?它和Standards模式有什么区别
从IE6开始,引入了Standards模式,标准模式中,浏览器尝试给符合标准的文档在规范上的正确处理达到在指定浏览器中的程度。
在IE6之前CSS还不够成熟,所以IE5等之前的浏览器对CSS的支持很差, IE6将对CSS提供更好的支持,然而这时的问题就来了,因为有很多页面是基于旧的布局方式写的,而如果IE6 支持CSS则将令这些页面显示不正常,如何在即保证不破坏现有页面,又提供新的渲染机制呢?
在写程序时我们也会经常遇到这样的问题,如何保证原来的接口不变,又提供更强大的功能,尤其是新功能不兼容旧功能时。遇到这种问题时的一个常见做法是增加参数和分支,即当某个参数为真时,我们就使用新功能,而如果这个参数 不为真时,就使用旧功能,这样就能不破坏原有的程序,又提供新功能。IE6也是类似这样做的,它将DTD当成了这个“参数”,因为以前的页面大家都不会去写DTD,所以IE6就假定 如果写了DTD,就意味着这个页面将采用对CSS支持更好的布局,而如果没有,则采用兼容之前的布局方式。这就是Quirks模式(怪癖模式,诡异模式,怪异模式)。
区别:
总体会有布局、样式解析和脚本执行三个方面的区别。
盒模型:在W3C标准中,如果设置一个元素的宽度和高度,指的是元素内容的宽度和高度,而在Quirks 模式下,IE的宽度和高度还包含了padding和border。
设置行内元素的高宽:在Standards模式下,给等行内元素设置wdith和height都不会生效,而在quirks模式下,则会生效。
设置百分比的高度:在standards模式下,一个元素的高度是由其包含的内容来决定的,如果父元素没有设置百分比的高度,子元素设置一个百分比的高度是无效的用margin:0 auto设置水平居中:使用margin:0 auto在standards模式下可以使元素水平居中,但在quirks模式下却会失效。
(还有很多,答出什么不重要,关键是看他答出的这些是不是自己经验遇到的,还是说都是看文章看的,甚至完全不知道。)
4、div+css的布局较table布局有什么优点?
改版的时候更方便 只要改css文件。
页面加载速度更快、结构化清晰、页面显示简洁。
表现与结构相分离。
易于优化(seo)搜索引擎更友好,排名更容易靠前。
5、 img的alt与title有何异同? strong与em的异同?
a:alt(alt text):为不能显示图像、窗体或applets的用户代理(UA),alt属性用来指定替换文字。替换文字的语言由lang属性指定。(在IE浏览器下会在没有title时把alt当成 tool tip显示)
title(tool tip):该属性为设置该属性的元素提供建议性的信息。
strong:粗体强调标签,强调,表示内容的重要性
em:斜体强调标签,更强烈强调,表示内容的强调点
6、你能描述一下渐进增强和优雅降级之间的不同吗?
渐进增强 progressive enhancement:针对低版本浏览器进行构建页面,保证最基本的功能,然后再针对高级浏览器进行效果、交互等改进和追加功能达到更好的用户体验。
优雅降级 graceful degradation:一开始就构建完整的功能,然后再针对低版本浏览器进行兼容。
区别:优雅降级是从复杂的现状开始,并试图减少用户体验的供给,而渐进增强则是从一个非常基础的,能够起作用的版本开始,并不断扩充,以适应未来环境的需要。降级(功能衰减)意味着往回看;而渐进增强则意味着朝前看,同时保证其根基处于安全地带。
“优雅降级”观点
“优雅降级”观点认为应该针对那些最高级、最完善的浏览器来设计网站。而将那些被认为“过时”或有功能缺失的浏览器下的测试工作安排在开发周期的最后阶段,并把测试对象限定为主流浏览器(如 IE、Mozilla 等)的前一个版本。
在这种设计范例下,旧版的浏览器被认为仅能提供“简陋却无妨 (poor, but passable)” 的浏览体验。你可以做一些小的调整来适应某个特定的浏览器。但由于它们并非我们所关注的焦点,因此除了修复较大的错误之外,其它的差异将被直接忽略。
“渐进增强”观点
“渐进增强”观点则认为应关注于内容本身。
内容是我们建立网站的诱因。有的网站展示它,有的则收集它,有的寻求,有的操作,还有的网站甚至会包含以上的种种,但相同点是它们全都涉及到内容。这使得“渐进增强”成为一种更为合理的设计范例。这也是它立即被 Yahoo! 所采纳并用以构建其“分级式浏览器支持 (Graded Browser Support)”策略的原因所在。
那么问题来了。现在产品经理看到IE6,7,8网页效果相对高版本现代浏览器少了很多圆角,阴影(CSS3),要求兼容(使用图片背景,放弃CSS3),你会如何说服他?
7、为什么利用多个域名来存储网站资源会更有效?
CDN缓存更方便
突破浏览器并发限制
节约cookie带宽
节约主域名的连接数,优化页面响应速度
防止不必要的安全问题
8、请谈一下你对网页标准和标准制定机构重要性的理解。
网页标准和标准制定机构都是为了能让web发展的更‘健康’,开发者遵循统一的标准,降低开发难度,开发成本,SEO也会更好做,也不会因为滥用代码导致各种BUG、安全问题,最终提高网站易用性。
9、请描述一下cookies,sessionStorage和localStorage的区别?
sessionStorage用于本地存储一个会话(session)中的数据,这些数据只有在同一个会话中的页面才能访问并且当会话结束后数据也随之销毁。因此sessionStorage不是一种持久化的本地存储,仅仅是会话级别的存储。而localStorage用于持久化的本地存储,除非主动删除数据,否则数据是永远不会过期的。
web storage和cookie的区别
Web Storage的概念和cookie相似,区别是它是为了更大容量存储设计的。Cookie的大小是受限的,并且每次你请求一个新的页面的时候Cookie都会被发送过去,这样无形中浪费了带宽,另外cookie还需要指定作用域,不可以跨域调用。
除此之外,Web Storage拥有setItem,getItem,removeItem,clear等方法,不像cookie需要前端开发者自己封装setCookie,getCookie。但是Cookie也是不可以或缺的:Cookie的作用是与服务器进行交互,作为HTTP规范的一部分而存在 ,而Web Storage仅仅是为了在本地“存储”数据而生。
10、简述一下src与href的区别。
src用于替换当前元素,href用于在当前文档和引用资源之间确立联系。
src是source的缩写,指向外部资源的位置,指向的内容将会嵌入到文档中当前标签所在位置;在请求src资源时会将其指向的资源下载并应用到文档内,例如js脚本,img图片和frame等元素。
当浏览器解析到该元素时,会暂停其他资源的下载和处理,直到将该资源加载、编译、执行完毕,图片和框架等元素也如此,类似于将所指向资源嵌入当前标签内。这也是为什么将js脚本放在底部而不是头部。
href是Hypertext Reference的缩写,指向网络资源所在位置,建立和当前元素(锚点)或当前文档(链接)之间的链接,如果我们在文档中添加
标签内的文字是什么颜色的?
123
答案:red。与样式定义在文件中的先后顺序有关,即是后面的覆盖前面的,与在//方法二:未知元素的高宽
#div1{
width: 200px;
height: 200px;
background-color: #6699FF;
margin:auto;
position: absolute; //父元素需要相对定位
left: 0;
top: 0;
right: 0;
bottom: 0;
}
那么问题来了,如何垂直居中一个?(用更简便的方法。)
1
2
3
4
5
6 #container //的容器设置如下
{
display:table-cell;
text-align:center;
vertical-align:middle;
}
28、px和em的区别。
px和em都是长度单位,区别是,px的值是固定的,指定是多少就是多少,计算比较容易。em得值不是固定的,并且em会继承父级元素的字体大小。
浏览器的默认字体高都是16px。所以未经调整的浏览器都符合: 1em=16px。那么12px=0.75em, 10px=0.625em。
29、描述一个”reset”的CSS文件并如何使用它。知道normalize.css吗?你了解他们的不同之处?
重置样式非常多,凡是一个前端开发人员肯定有一个常用的重置CSS文件并知道如何使用它们。他们是盲目的在做还是知道为什么这么做呢?原因是不同的浏览器对一些元素有不同的默认样式,如果你不处理,在不同的浏览器下会存在必要的风险,或者更有戏剧性的性发生。
你可能会用Normalize来代替你的重置样式文件。它没有重置所有的样式风格,但仅提供了一套合理的默认样式值。既能让众多浏览器达到一致和合理,但又不扰乱其他的东西(如粗体的标题)。
在这一方面,无法做每一个复位重置。它也确实有些超过一个重置,它处理了你永远都不用考虑的怪癖,像HTML的audio元素不一致或line-height不一致。
30、Sass、LESS是什么?大家为什么要使用他们?
他们是CSS预处理器。他是CSS上的一种抽象层。他们是一种特殊的语法/语言编译成CSS。
例如Less是一种动态样式语言. 将CSS赋予了动态语言的特性,如变量,继承,运算, 函数. LESS 既可以在客户端上运行 (支持IE 6+, Webkit, Firefox),也可一在服务端运行 (借助 Node.js)。
为什么要使用它们?
结构清晰,便于扩展。
可以方便地屏蔽浏览器私有语法差异。这个不用多说,封装对浏览器语法差异的重复处理,减少无意义的机械劳动。
可以轻松实现多重继承。
完全兼容 CSS 代码,可以方便地应用到老项目中。LESS 只是在 CSS 语法上做了扩展,所以老的 CSS 代码也可以与 LESS 代码一同编译。
31、display:none与visibility:hidden的区别是什么?
display : 隐藏对应的元素但不挤占该元素原来的空间。
visibility: 隐藏对应的元素并且挤占该元素原来的空间。
即是,使用CSS display:none属性后,HTML元素(对象)的宽度、高度等各种属性值都将“丢失”;而使用visibility:hidden属性后,HTML元素(对象)仅仅是在视觉上看不见(完全透明),而它所占据的空间位置仍然存在。
32、CSS中link和@import的区别是:
Link属于html标签,而@import是CSS中提供的
在页面加载的时候,link会同时被加载,而@import引用的CSS会在页面加载完成后才会加载引用的CSS
@import只有在ie5以上才可以被识别,而link是html标签,不存在浏览器兼容性问题
Link引入样式的权重大于@import的引用(@import是将引用的样式导入到当前的页面中)
33、简介盒子模型:
CSS的盒子模型有两种:IE盒子模型、标准的W3C盒子模型模型
盒模型:内容、内边距、外边距(一般不计入盒子实际宽度)、边框
34、为什么要初始化样式?
由于浏览器兼容的问题,不同的浏览器对标签的默认样式值不同,若不初始化会造成不同浏览器之间的显示差异
但是初始化CSS会对搜索引擎优化造成小影响
35、BFC是什么?
BFC(块级格式化上下文),一个创建了新的BFC的盒子是独立布局的,盒子内元素的布局不会影响盒子外面的元素。在同一个BFC中的两个相邻的盒子在垂直方向发生margin重叠的问题
BFC是指浏览器中创建了一个独立的渲染区域,该区域内所有元素的布局不会影响到区域外元素的布局,这个渲染区域只对块级元素起作用
36、html语义化是什么?
当页面样式加载失败的时候能够让页面呈现出清晰的结构
有利于seo优化,利于被搜索引擎收录(更便于搜索引擎的爬虫程序来识别)
便于项目的开发及维护,使html代码更具有可读性,便于其他设备解析。
37、Doctype的作用?严格模式与混杂模式的区别?
严格模式下:页面排版及JS解析是以该浏览器支持的最高标准来执行
混杂模式:不严格按照标准执行,主要用来兼容旧的浏览器,向后兼容
38、IE的双边距BUG:块级元素float后设置横向margin,ie6显示的margin比设置的较大。解决:加入_display:inline
39、HTML与XHTML——二者有什么区别?
元素的每个
元素。
p:last-of-type 选择属于其父元素的最后
元素的每个
元素。
p:only-of-type 选择属于其父元素唯一的
元素的每个
元素。
p:only-child 选择属于其父元素的唯一子元素的每个
元素。
p:nth-child(2) 选择属于其父元素的第二个子元素的每个
元素。
:enabled、:disabled 控制表单控件的禁用状态。
:checked,单选框或复选框被选中。
48、如何居中div,如何居中一个浮动元素?
给div设置一个宽度,然后添加margin:0 auto属性
div{
width:200px;
margin:0 auto;
}
居中一个浮动元素
确定容器的宽高 宽500 高 300 的层
设置层的外边距
.div {
Width:500px ; height:300px;//高度可以不设
Margin: -150px 0 0 -250px;
position:relative;相对定位
background-color:pink;//方便看效果
left:50%;
top:50%;
}
49、浏览器的内核分别是什么?经常遇到的浏览器的兼容性有哪些?原因,解决方法是什么,常用hack的技巧 ?
若此元素为 inline 元素,则 containing block 为能够包含这个元素生成的第一个和最后一个 inline box 的 padding box (除 margin, border 外的区域) 的最小矩形;
否则则由这个祖先元素的 padding box 构成。
根元素所在的 containing block 被称为 initial containing block,在我们常用的浏览器环境下,指的是原点与 canvas 重合,大小和 viewport 相同的矩形;
对于 position 为 static 或 relative 的元素,其 containing block 为祖先元素中最近的 block container box 的 content box (除 margin, border, padding 外的区域);
对于 position:fixed 的元素,其 containing block 由 viewport 建立;
对于 position:absolute 的元素,则是先找到其祖先元素中最近的 position 属性非 static 的元素,然后判断:
如果都找不到,则为 initial containing block。
52、position跟display、margin collapse、overflow、float这些特性相互叠加后会怎么样?
http://www.cnblogs.com/jackyWHJ/p/3756087.html
53、css的基本语句构成是?
选择器{属性1:值1;属性2:值2;……}
54、浏览器标准模式和怪异模式之间的区别是什么?
盒子模型 渲染模式的不同
使用 window.top.document.compatMode 可显示为什么模式
55、说display属性有哪些?可以做什么?
display:block行内元素转换为块级元素
display:inline块级元素转换为行内元素
display:inline-block转为内联元素
56、哪些css属性可以继承?
可继承: font-size font-family color, ul li dl dd dt;
不可继承 :border padding margin width height ;
57、css优先级算法如何计算?
!important > id > class > 标签
!important 比 内联优先级高
*优先级就近原则,样式定义最近者为准;
*以最后载入的样式为准;
58、b标签和strong标签,i标签和em标签的区别?
后者有语义,前者则无。
59、有那些行内元素、有哪些块级元素、盒模型?
1.内联元素(inline element)
a – 锚点
abbr – 缩写
acronym – 首字
b – 粗体(不推荐)
big – 大字体
br – 换行
em – 强调
font – 字体设定(不推荐)
i – 斜体
img – 图片
input – 输入框
label – 表格标签
s – 中划线(不推荐)
select – 项目选择
small – 小字体文本
span – 常用内联容器,定义文本内区块
strike – 中划线
strong – 粗体强调
sub – 下标
sup – 上标
textarea – 多行文本输入框
tt – 电传文本
u – 下划线
var – 定义变量
2、块级元素
address – 地址
blockquote – 块引用
center – 举中对齐块
dir – 目录列表
div – 常用块级容易,也是css layout的主要标签
dl – 定义列表
fieldset – form控制组
form – 交互表单
h1 – 大标题
h2 – 副标题
h3 – 3级标题
h4 – 4级标题
h5 – 5级标题
h6 – 6级标题
hr – 水平分隔线
isindex – input prompt
menu – 菜单列表
noframes – frames可选内容,(对于不支持frame的浏览器显示此区块内容)
noscript – )可选脚本内容(对于不支持script的浏览器显示此内容)
ol – 排序表单
p – 段落
pre – 格式化文本
table – 表格
ul – 非排序列表
3.CSS盒子模型包含四个部分组成:
内容、填充(padding)、边框(border)、外边界(margin)。
60、有哪些选择符,优先级的计算公式是什么?行内样式和!important哪个优先级高?
#ID > .class > 标签选择符 !important优先级高
61.我想让行内元素跟上面的元素距离10px,加margin-top和padding-top可以吗?
margin-top,padding-top无效
62.CSS的盒模型由什么组成?
内容,border ,margin,padding
63、text-align:center和line-height有什么区别?
text-align是水平对齐,line-height是行间。
64、前端页面由哪三层构成,分别是什么?作用是什么?
结构层 Html 表示层 CSS 行为层 js
82、写一个表格以及对应的CSS,使表格奇数行为白色背景,偶数行为灰色,鼠标一上去为黄色背景。
表格标题 | ||||
---|---|---|---|---|
1 | 2 | 3 | 4 | 5 |
1 | 2 | 3 | 4 | 5 |
1 | 2 | 3 | 4 | 5 |
toString.call([],1,2,3)
toString.apply([],[1,2,3])
Object.call(this,obj1,obj2,obj3)
Object.apply(this,arguments)
9、b继承a的方法
考点:继承的多种方式
function b(){}
b.protoototype=new a;
10、JavaScript this指针、闭包、作用域
this:指向调用上下文
闭包:内层作用域可以访问外层作用域的变量
作用域:定义一个函数就开辟了一个局部作用域,整个js执行环境有一个全局作用域
11、事件委托是什么
符合W3C标准的事件绑定addEventLisntener /attachEvent
让利用事件冒泡的原理,让自己的所触发的事件,让他的父元素代替执行!
12、闭包是什么,有什么特性,对页面有什么影响
闭包就是能够读取其他函数内部变量的函数。
闭包的缺点:滥用闭包函数会造成内存泄露,因为闭包中引用到的包裹函数中定义的变量都永远不会被释放,所以我们应该在必要的时候,及时释放这个闭包函数
13、如何阻止事件冒泡和默认事件
e. stopPropagation();//标准浏览器
event.canceBubble=true;//ie9之前
阻止默认事件:
为了不让a点击之后跳转,我们就要给他的点击事件进行阻止
return false
e.preventDefault();
14、添加 删除 替换 插入到某个接点的方法
obj.appendChild()
obj.insertBefore() //原生的js中不提供insertAfter();
obj.replaceChild()//替换
obj.removeChild()//删除
15、javascript的本地对象,内置对象和宿主对象
本地对象为array obj regexp等可以new实例化
内置对象为gload Math 等不可以实例化的
宿主为浏览器自带的document,window 等
16、document load 和document ready的区别
Document.onload 是在结构和样式加载完才执行js
window.onload:不仅仅要在结构和样式加载完,还要执行完所有的样式、图片这些资源文件,全部加载完才会触发window.onload事件
Document.ready原生种没有这个方法,jquery中有 $().ready(function)
17、””和“=”的不同
前者会自动转换类型
后者不会
1==”1”
null==undefined
===先判断左右两边的数据类型,如果数据类型不一致,直接返回false
之后才会进行两边值的判断
18、javascript的同源策略
一段脚本只能读取来自于同一来源的窗口和文档的属性,这里的同一来源指的是主机名、协议和端口号的组合
http,ftp:协议
主机名;localhost
端口名:80:http协议的默认端口
https:默认端口是8083
同源策略带来的麻烦:ajax在不同域名下的请求无法实现,
如果说想要请求其他来源的js文件,或者json数据,那么可以通过jsonp来解决
19、编写一个数组去重的方法
var arr=[1,1,3,4,2,4,7];
=>[1,3,4,2,7]
一个比较简单的实现就是:
1、 先创建一个空数组,用来保存最终的结果
2、 循环原数组中的每个元素
3、 再对每个元素进行二次循环,判断是否有与之相同的元素,如果没有,将把这个元素放到新数组中
4、 返回这个新数组
function oSort(arr) {
var result ={};
var newArr=[];
for(var i=0;i
newArr.push(arr)
result[arr]=1
}
}
return newArr
}
没有标准答案。
运行环境:浏览器中的JS引擎(v8.。。)
语言特性:面向对象,动态语言:
//动态语言的特性
var num=10;//num是一个数字类型
num=“jim”;//此时num又变成一个字符串类型
//我们把一个变量用来保存不同数据类型的语言称之为一个动态语言
//静态语言:c# java c c++
//静态语言在声明一个变量就已经确定了这个变量的数据类型,
// 而且在任何时候都不可以改变他的数据类型
javaScript一种直译式脚本语言,是一种动态类型、弱类型、基于原型的语言,内置支持类型。它的解释器被称为JavaScript引擎,为浏览器的一部分,广泛用于客户端的脚本语言,最早是在HTML网页上使用,用来给HTML网页增加动态功能。JavaScript兼容于ECMA标准,因此也称为ECMAScript。
基本特点
1.是一种解释性脚本语言(代码不进行预编译)。
2.主要用来向HTML(标准通用标记语言下的一个应用)页面添加交互行为。
3.可以直接嵌入HTML页面,但写成单独的js文件有利于结构和行为的分离。
4.跨平台特性,在绝大多数浏览器的支持下,可以在多种平台下运行(如Windows、Linux、Mac、Android、iOS等)。
21、JavaScript的数据类型都有什么?
基本数据类型:String,Boolean,number,undefined,object,Null
引用数据类型:Object(Array,Date,RegExp,Function)
那么问题来了,如何判断某变量是否为数组数据类型?
方法一.判断其是否具有“数组性质”,如slice()方法。可自己给该变量定义slice方法,故有时会失效
方法二.obj instanceof Array 在某些IE版本中不正确
方法三.方法一二皆有漏洞,在ECMA Script5中定义了新方法Array.isArray(), 保证其兼容性,最好的方法如下:
toString.call(18);//”[object Number]”
toString.call(“”);//”[object String]”
解析这种简单的数据类型直接通过typeof就可以直接判断
toString.call常用于判断数组、正则这些复杂类型
toString.call(/[0-9]{10}/)//”[object RegExp]”
if(typeof Array.isArray==="undefined"){
Array.isArray = function(arg){
return Object.prototype.toString.call(arg)==="[object Array]"
};
}
22、已知ID的Input输入框,希望获取这个输入框的输入值,怎么做?(不使用第三方框架)
document.getElementById(“ID”).value
23、希望获取到页面中所有的checkbox怎么做?(不使用第三方框架)
var domList = document.getElementsByTagName(‘input’)
var checkBoxList = [];//返回的所有的checkbox
var len = domList.length; //缓存到局部变量
while (len–) { //使用while的效率会比for循环更高
if (domList[len].type == ‘checkbox’) {
checkBoxList.push(domList[len]);
}
}
24、设置一个已知ID的DIV的html内容为xxxx,字体颜色设置为黑色(不使用第三方框架)
var dom = document.getElementById(“ID”);
dom.innerHTML = “xxxx”
dom.style.color = “#000”
25、当一个DOM节点被点击时候,我们希望能够执行一个函数,应该怎么做?
直接在DOM里绑定事件:
var a;
alert(typeof a); // “undefined”
//alert(b); // 报错
b=10;
alert(typeof b);//”number”
解释:Undefined是一个只有一个值的数据类型,这个值就是“undefined”,在使用var声明变量但并未对其赋值进行初始化时,这个变量的值就是undefined。而b由于未声明将报错。注意未申明的变量和声明了未赋值的是不一样的。
undefined会在以下三种情况下产生:
1、 一个变量定义了却没有被赋值
2、 想要获取一个对象上不存在的属性或者方法:
3、 一个数组中没有被赋值的元素
注意区分undefined跟not defnied(语法错误)是不一样的
27、看下列代码,输出什么?解释原因。
var a = null;
alert(typeof a); //object
解释:null是一个只有一个值的数据类型,这个值就是null。表示一个空指针对象,所以用typeof检测会返回”object”。
28、看下列代码,输出什么?解释原因。
var undefined;//此时undefined这个变量的值是undefined
undefined == null; // true
1 == true; // true
此时会把布尔类型的值转换为数字类型 true=1 false=0
2 == true; // false
0 == false; // true
0 == ‘’; // true
NaN == NaN; // false
[] == false; // true
[] == ![]; // true
• undefined与null相等,但不恒等(=)
一个是number一个是string时,会尝试将string转换为number
尝试将boolean转换为number,0或1
尝试将Object转换成number或string,取决于另外一个对比量的类型
所以,对于0、空字符串的判断,建议使用 “=” 。“===”会先判断两边的值类型,类型不匹配时为false。
那么问题来了,看下面的代码,输出什么,foo的值为什么?
var foo = "11"+2-"1";
console.log(foo);//111
console.log(typeof foo);
执行完后foo的值为111,foo的类型为number。
29、看代码给答案。
var a = new Object();
a.value = 1;
b = a; {value:1}
b.value = 2;
alert(a.value);//2
答案:2(考察引用数据类型细节)
30、已知数组var stringArray = [“This”, “is”, “Baidu”, “Campus”],Alert出”This is Baidu Campus”。
答案:alert(stringArray.join(“ ”))
已知有字符串foo=”get-element-by-id”,写一个function将其转化成驼峰表示法”getElementById”。
//
function combo(msg){
var arr=msg.split("-");//[get,element,by,id]
for(var i=1;i
}
(考察基础API)
31、var numberArray = [3,6,2,4,1,5]; (考察基础API)
实现对该数组的倒排,输出[5,1,4,2,6,3]
实现对该数组的降序排列,输出[6,5,4,3,2,1]
function combo(msg){
var arr=msg.split("-");
for(var i=1;i
}
msg=arr.join("");
return msg;
}
32、输出今天的日期,以YYYY-MM-DD的方式,比如今天是2014年9月26日,则输出2014-09-26
var d = new Date();
// 获取年,getFullYear()返回4位的数字
var year = d.getFullYear();
// 获取月,月份比较特殊,0是1月,11是12月
var month = d.getMonth() + 1;
// 变成两位
month = month < 10 ? ‘0’ + month : month;
// 获取日
var day = d.getDate();
day = day < 10 ? ‘0’ + day : day;
alert(year + ‘-’ + month + ‘-’ + day);
33、将字符串”{ KaTeX parse error: Expected 'EOF', got '}' at position 3: id}̲
var foo = 1;
function(){
console.log(foo);
var foo = 2;
console.log(foo);
}
答案:输出undefined 和 2。上面代码相当于:
var foo = 1;
function(){
var foo;
console.log(foo); //undefined
foo = 2;
console.log(foo); // 2;
}
函数声明与变量声明会被JavaScript引擎隐式地提升到当前作用域的顶部,但是只提升名称不会提升赋值部分。
37、用js实现随机选取10–100之间的10个数字,存入一个数组,并排序。
var iArray = [];
funtion getRandom(istart, iend){
var iChoice = istart - iend +1;
return Math.floor(Math.random() * iChoice + istart;
}
Math.random()就是获取0-1之间的随机数(永远获取不到1)
for(var i=0; i<10; i++){
var result= getRandom(10,100);
iArray.push(result);
}
iArray.sort();
38、把两个数组合并,并删除第二个元素。
var array1 = ['a','b','c'];
var bArray = [‘d’,‘e’,‘f’];
var cArray = array1.concat(bArray);
cArray.splice(1,1);
39、怎样添加、移除、移动、复制、创建和查找节点(原生JS,实在基础,没细写每一步)
1)创建新节点
createDocumentFragment() //创建一个DOM片段
createElement() //创建一个具体的元素
createTextNode() //创建一个文本节点
2)添加、移除、替换、插入
appendChild() //添加
removeChild() //移除
replaceChild() //替换
insertBefore() //插入
3)查找
getElementsByTagName() //通过标签名称
getElementsByName() //通过元素的Name属性的值
getElementById() //通过元素Id,唯一性
40、有这样一个URL:http://item.taobao.com/item.htm?a=1&b=2&c=&d=xxx&e,请写一段JS程序提取URL中的各个GET参数(参数名和参数个数不确定),将其按key-value形式返回到一个json结构中,如{a:’1′, b:’2′, c:”, d:’xxx’, e:undefined}。
答案:
function serilizeUrl(url) {
var urlObject = {};
if (/?/.test(url)) {
var urlString = url.substring(url.indexOf("?") + 1);
var urlArray = urlString.split("&");
for (var i = 0, len = urlArray.length; i < len; i++) {
var urlItem = urlArray[i];
var item = urlItem.split("=");
urlObject[item[0]] = item[1];
}
return urlObject;
}
return null;
}
41、正则表达式构造函数var reg=new RegExp(“xxx”)与正则表达字面量var reg=//有什么不同?匹配邮箱的正则表达式?
答案:当使用RegExp()构造函数的时候,不仅需要转义引号(即\”表示”),并且还需要双反斜杠(即\表示一个\)。使用正则表达字面量的效率更高。
邮箱的正则匹配:
var regMail = /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+((.[a-zA-Z0-9_-]{2,3}){1,2})$/;
24.看下面代码,给出输出结果。
for(var i=1;i<=3;i++){
setTimeout(function(){
console.log(i);
},0);
};
答案:4 4 4。
原因:Javascript事件处理器在线程空闲之前不会运行。追问,如何让上述代码输出1 2 3?
for(var i=1;i<=3;i++){
setTimeout((function(a){ //改成立即执行函数
console.log(a);
})(i),0);
};
1 //输出
2
3
42、写一个function,清除字符串前后的空格。(兼容所有浏览器)
使用自带接口trim(),考虑兼容性:
if (!String.prototype.trim) {
String.prototype.trim = function() {
return this.replace(/^\s+/, “”).replace(/\s+$/,"");
//\s匹配空白字符:回车、换行、制表符tab 空格
}
}
// test the function
var str = " \t\n test string ".trim();
alert(str == “test string”); // alerts “true”
43、Javascript中callee和caller的作用?
arguments.callee:获得当前函数的引用
caller是返回一个对函数的引用,该函数调用了当前函数;
callee是返回正在被执行的function函数,也就是所指定的function对象的正文。
那么问题来了?如果一对兔子每月生一对兔子;一对新生兔,从第二个月起就开始生兔子;假定每对兔子都是一雌一雄,试问一对兔子,第n个月能繁殖成多少对兔子?(使用callee完成)
var result=[];
function fn(n){ //典型的斐波那契数列
if(n1){
return 1;
}else if(n2){
return 1;
}else{
if(result[n]){
return result[n];
}else{
//argument.callee()表示fn()
result[n]=arguments.callee(n-1)+arguments.callee(n-2);
return result[n];
}
}
}
44、Javascript中, 以下哪条语句一定会产生运行错误? 答案( BC )
A、 var _变量=NaN;B、var 0bj = [];C、var obj = //; D、var obj = {};
//正确答案:BC
45、以下两个变量a和b,a+b的哪个结果是NaN? 答案( C )
A、var a=undefind; b=NaN //拼写
B、var a=‘123’; b=NaN//字符串
C、var a =undefined , b =NaN
D、var a=NaN , b=‘undefined’//”Nan”
//var a=10; b=20; c=4; ++b+c+a++
//21+4+10=35;
46、var a=10; b=20; c=4; ++b+c+a++ 以下哪个结果是正确的?答案( B )
A、 34 B、35 C、36 D、37
47、下面的JavaScript语句中,( D )实现检索当前页面中的表单元素中的所有文本框,并将它们全部清空
A. for(vari=0;i< form1.elements.length;i++) {
if(form1.elements.type==”text”)
form1.elements.value=”";}
B. for(vari=0;i
forms[0].elements.value=”";
}
C. if(document.form.elements.type==”text”)
form.elements.value=”";
D. for(vari=0;i
document.forms.elements[j].value=”";
}
}
48、要将页面的状态栏中显示“已经选中该文本框”,下列JavaScript语句正确的是( A )
A. window.status=”已经选中该文本框”
B. document.status=”已经选中该文本框”
C. window.screen=”已经选中该文本框”
D. document.screen=”已经选中该文本框”
49、以下哪条语句会产生运行错误:(A)正确答案:A、D
A.var obj = ();B.var obj = [];C.var obj = {};D.var obj = //;
50、以下哪个单词不属于javascript保留字:(B)
A.with B.parent C.class D.void
51、请选择结果为真的表达式:(C)
A.null instanceof Object B.null === undefined C.null == undefined D.NaN == NaN
52、Javascript中, 如果已知HTML页面中的某标签对象的id=”username”,用____document.getElementById(‘username’)___ 方法获得该标签对象。
53、typeof运算符返回值中有一个跟javascript数据类型不一致,它是_______”function”_________。
typeof Number
typeof Object
54、定义了一个变量,但没有为该变量赋值,如果alert该变量,javascript弹出的对话框中显示___undefined______ 。
55、分析代码,得出正确的结果。
var a=10, b=20 , c=30;
++a;
a++;
e=++a+(++b)+(c++)+a++;
alert(e);
弹出提示对话框:77
var a=10, b=20 , c=30;
++a;//a=11
a++;//a=11
e=++a+(++b)+(c++)+a++;
//a=12 13+21+30+13=77
alert(e);
56、写出函数DateDemo的返回结果,系统时间假定为今天
function DateDemo(){
var d, s=“今天日期是:”;
d = new Date();
s += d.getMonth() + “/”;
s += d.getDate() + “/”;
s += d.getFullYear();
return s;}
结果:今天日期是:7/17/2010
57、写出程序运行的结果?
for(i=0, j=0; i<10, j<6; i++, j++){
k = i + j;}
结果:10
for(i=0, j=0; i<10, j<6; i++, j++){
//j=5 i=5
k = i + j;//k=10
}
//结果:10
58、阅读以下代码,请分析出结果:
var arr = new Array(1 ,3 ,5);
arr[4]=‘z’;//[1,3,5,undefined,’z’]
arr2 = arr.reverse();//arr2=[’z’,undefined,5,3,1];
//arr=[’z’,undefined,5,3,1]
arr3 = arr.concat(arr2);
alert(arr3);
弹出提示对话框:z,5,3,1,z,5,3,1
reverse 方法颠倒数组中元素的位置,并返回该数组的引用。
59、补充按钮事件的函数,确认用户是否退出当前页面,确认之后关闭窗口;
里面的段落
var str = “
里面的段落
第三种(函数对象方式):
var sum3 = new Function(“num1”,“num2”,“return num1+num2”);
69、Javascript如何实现继承?
原型链继承,借用构造函数继承,组合继承,寄生式继承,寄生组合继承
72、Javascript创建对象的几种方式?
工厂方式,构造函数方式,原型模式,混合构造函数原型模式,动态原型方式
73、把 Script 标签 放在页面的最底部的body封闭之前 和封闭之后有什么区别?浏览器会如何解析它们?
如果说放在body的封闭之前,将会阻塞其他资源的加载
如果放在body封闭之后,不会影响body内元素的加载
74、iframe的优缺点?
优点:
解决加载缓慢的第三方内容如图标和广告等的加载问题
Security sandbox
并行加载脚本
缺点:
iframe会阻塞主页面的Onload事件
即时内容为空,加载也需要时间
没有语意
75、请你谈谈Cookie的弊端?
缺点:
1.Cookie
数量和长度的限制。每个domain最多只能有20条cookie,每个cookie长度不能超过4KB,否则会被截掉。
2.安全性问题。如果cookie被人拦截了,那人就可以取得所有的session信息。即使加密也与事无补,因为拦截者并不需要知道cookie的意义,他只要原样转发cookie就可以达到目的了。
3.有些状态不可能保存在客户端。例如,为了防止重复提交表单,我们需要在服务器端保存一个计数器。如果我们把这个计数器保存在客户端,那么它起不到任何作用。
76、DOM操作——怎样添加、移除、移动、复制、创建和查找节点。
创建新节点
createDocumentFragment() // 创建一个DOM片段
createElement() // 创建一个具体的元素
createTextNode() // 创建一个文本节点
添加、移除、替换、插入
appendChild()
removeChild()
replaceChild()
insertBefore() // 在已有的子节点前插入一个新的子节点
查找
getElementsByTagName() // 通过标签名称
getElementsByName() // 通过元素的Name属性的值(IE容错能力较强,会得到一个数组,其中包括id等于name值的)
getElementById() // 通过元素Id,唯一性
77、js延迟加载的方式有哪些?
defer和async
动态创建DOM方式(创建script,插入到DOM中,加载完毕后callBack)
按需异步载入js
78、documen.write和 innerHTML 的区别?
document.write 只能重绘整个页面
innerHTML 可以重绘页面的一部分
79、哪些操作会造成内存泄漏?
内存泄漏指任何对象在您不再拥有或需要它之后仍然存在。
垃圾回收器定期扫描对象,并计算引用了每个对象的其他对象的数量。如果一个对象的引用数量为 0(没有其他对象引用过该对象),或对该对象的惟一引用是循环的,那么该对象的内存即可回收。
setTimeout 的第一个参数使用字符串而非函数的话,会引发内存泄漏。
闭包
控制台日志
循环(在两个对象彼此引用且彼此保留时,就会产生一个循环)
83、判断一个字符串中出现次数最多的字符,统计这个次数
答:var str = ‘asdfssaaasasasasaa’;
var json = {};
for (var i = 0; i < str.length; i++) {
if(!json[str.charAt(i)]){
json[str.charAt(i)] = 1;
}else{
json[str.charAt(i)]++;
}
};
var iMax = 0;
var iIndex = ‘’;
for(var i in json){
if(json[i]>iMax){
iMax = json[i];
iIndex = i;
}
}
alert(‘出现次数最多的是:’+iIndex+‘出现’+iMax+‘次’);
93、写一个获取非行间样式的函数
function getStyle(obj,attr,value)
{
if(!value)
{
if(obj.currentStyle)//ie
{
return obj.currentStyle(attr);
}
else{//标准浏览器
obj.getComputedStyle(attr,false);
}
}
else
{
obj.style[attr] = value;
}
}
94、解释jsonp的原理,以及为什么不是真正的ajax
Jsonp并不是一种数据格式,而json是一种数据格式,jsonp是用来解决跨域获取数据的一种解决方案,具体是通过动态创建script标签,然后通过标签的src属性获取js文件中的js脚本,该脚本的内容是一个函数调用,参数就是服务器返回的数据,为了处理这些返回的数据,需要事先在页面定义好回调函数,本质上使用的并不是ajax技术
99、字符串反转,如将 ‘12345678’ 变成 ‘87654321’
//大牛做法;
//思路:先将字符串转换为数组 split(),利用数组的反序函数 reverse()颠倒数组,再利用 jion() 转换为字符串
var str = ‘12345678’;
str = str.split(’’).reverse().join(’’);
100、将数字 12345678 转化成 RMB形式 如: 12,345,678
//个人方法;
//思路:先将数字转为字符, str= str + ‘’ ;
//利用反转函数,每三位字符加一个 ','最后一位不加; re()是自定义的反转函数,最后再反转回去!
for(var i = 1; i <= re(str).length; i++){
tmp += re(str)[i - 1];
if(i % 3 == 0 && i != re(str).length){
tmp += ‘,’;
}
}
101、生成5个不同的随机数;
//思路:5个不同的数,每生成一次就和前面的所有数字相比较,如果有相同的,则放弃当前生成的数字!
var num1 = [];
for(var i = 0; i < 5; i++){
num1[i] = Math.floor(Math.random()*10) + 1; //范围是 [1, 10]
for(var j = 0; j < i; j++){
if(num1[i] == num1[j]){
i–;
}
}
}
102、去掉数组中重复的数字 方法一;
//思路:每遍历一次就和之前的所有做比较,不相等则放入新的数组中!
//这里用的原型 个人做法;
Array.prototype.unique = function(){
var len = this.length,
newArr = [],
flag = 1;
for(var i = 0; i < len; i++, flag = 1){
for(var j = 0; j < i; j++){
if(this[i] == this[j]){
flag = 0; //找到相同的数字后,不执行添加数据
}
}
flag ? newArr.push(this[i]) : ‘’;
}
return newArr;
}
方法二:
(function(arr){
var len = arr.length,
newArr = [],
flag;
for(var i = 0; i < len; i+=1, flag = 1){
for(var j = 0; j < i; j++){
if(arr[i] == arr[j]){
flag = 0;
}
}
flag?newArr.push(arr[i]):’’;
}
alert(newArr);
})([1, 1, 22, 3, 4, 55, 66]);
103、阶乘函数;98765…*1
//原型方法
Number.prototype.N = function(){
var re = 1;
for(var i = 1; i <= this; i++){
re *= i;
}
return re;
}
var num = 5;
alert(num.N());
104、window.location.search返回的是什么?
答:查询(参数)部分。除了给动态语言赋值以外,我们同样可以给静态页面,并使用javascript来获得相信应的参数值
返回值:?ver=1.0&id=timlq 也就是问号后面的!
//url:http://www.sina.com/getage?number=1&year=2016
105、window.location.hash 返回的是什么?
答:锚点 , 返回值:#love ;
//url:http://www.sina.com/getage?#age
这时就返回”#age”
106、window.location.reload() 作用?
答:刷新当前页面。
107、阻止冒泡函数
function stopPropagation(e) {
e = e || window.event;
if(e.stopPropagation) { //W3C阻止冒泡方法
e.stopPropagation();
} else {
e.cancelBubble = true; //IE阻止冒泡方法
}
}
document.getElementById(‘need_hide’).onclick = function(e) {
stopPropagation(e);
}
108、什么是闭包? 写一个简单的闭包?;
答:我的理解是,闭包就是能够读取其他函数内部变量的函数。在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。
function outer(){
var num = 1;
function inner(){
var n = 2;
alert(n + num);
}
return inner;
}
outer()();
109、javascript 中的垃圾回收机制?
答:在Javascript中,如果一个对象不再被引用,那么这个对象就会被GC回收。如果两个对象互相引用,而不再 被第3者所引用,那么这两个互相引用的对象也会被回收。因为函数a被b引用,b又被a外的c引用,这就是为什么 函数a执行后不会被回收的原因。
110、看题做答:
function f1(){
var tmp = 1;
this.x = 3;
console.log(tmp); //A
console.log(this.x); //B
}
var obj = new f1(); //1
console.log(obj.x) //2
console.log(f1()); //3
分析:
这道题让我重新认识了对象和函数,首先看代码(1),这里实例话化了 f1这个类。相当于执行了 f1函数。所以这个时候 A 会输出 1, 而 B 这个时候的 this 代表的是 实例化的当前对象 obj B 输出 3.。 代码(2)毋庸置疑会输出 3, 重点 代码(3)首先这里将不再是一个类,它只是一个函数。那么 A输出 1, B呢?这里的this 代表的其实就是window对象,那么this.x 就是一个全局变量 相当于在外部 的一个全局变量。所以 B 输出 3。最后代码由于f没有返回值那么一个函数如果没返回值的话,将会返回 underfined ,所以答案就是 : 1, 3, 3, 1, 3, underfined 。
111、下面输出多少?
var o1 = new Object();
var o2 = o1;
o2.name = “CSSer”;
console.log(o1.name);
如果不看答案,你回答真确了的话,那么说明你对javascript的数据类型了解的还是比较清楚了。js中有两种数据类型,分别是:基本数据类型和引用数据类型(object Array)。对于保存基本类型值的变量,变量是按值访问的,因为我们操作的是变量实际保存的值。对于保存引用类型值的变量,变量是按引用访问的,我们操作的是变量值所引用(指向)的对象。答案就清楚了: //CSSer;
112、再来一个
function changeObjectProperty (o) {
o.siteUrl = “http://www.csser.com/”;
o = new Object();
o.siteUrl = “http://www.popcg.com/”;
}
var CSSer = new Object();
changeObjectProperty(CSSer);
console.log(CSSer.siteUrl); //
如果CSSer参数是按引用传递的,那么结果应该是"http://www.popcg.com/",但实际结果却仍是"http://www.csser.com/"。事实是这样的:在函数内部修改了引用类型值的参数,该参数值的原始引用保持不变。我们可以把参数想象成局部变量,当参数被重写时,这个变量引用的就是一个局部变量,局部变量的生存期仅限于函数执行的过程中,函数执行完毕,局部变量即被销毁以释放内存。
(补充:内部环境可以通过作用域链访问所有的外部环境中的变量对象,但外部环境无法访问内部环境。每个环境都可以向上搜索作用域链,以查询变量和函数名,反之向下则不能。)
113、输出多少?
var a = 6;
setTimeout(function () {
var a = 666;//由于变量a是一个局部变量
alert(a); // 输出666,
}, 1000);
a = 66;
因为var a = 666;定义了局部变量a,并且赋值为666,根据变量作用域链,
全局变量处在作用域末端,优先访问了局部变量,从而覆盖了全局变量 。
var a = 6;
setTimeout(function () {
//变量声明提前
alert(a); // 输出undefined
var a = 666;
}, 1000);
a = 66;
因为var a = 666;定义了局部变量a,同样覆盖了全局变量,但是在alert(a);之前
a并未赋值,所以输出undefined。
var a = 6;
setTimeout(function(){
alert(a);
var a = 66;
}, 1000);
a = 666;
alert(a);
//结果:666 undefined
记住: 异步处理,一切OK 声明提前
114、输出多少?
function setN(obj){
obj.name=‘屌丝’;
obj = new Object();
obj.name = ‘腐女’;
};
var per = new Object();
setN(per);
alert(per.name); //屌丝 内部
115、JS的继承性
window.color = ‘red’;
var o = {color: ‘blue’};
function sayColor(){
alert(this.color);
}
考点:1、this的指向
2、call的用法
sayColor(); //red
sayColor.call(this); //red this指向的是window对象
sayColor.call(window); //red
sayColor.call(o); //blue
116、精度问题: JS 精度不能精确到 0.1 所以 。。。。同时存在于值和差值中
var n = 0.3,m = 0.2, i = 0.2, j = 0.1;
alert((n - m) == (i - j)); //false
alert((n-m) == 0.1); //false
alert((i-j)==0.1); //true
117、加减运算
alert(‘5’+3); //53 string
alert(‘5’+‘3’); //53 string
alert(‘5’-3); //2 number
alert(‘5’-‘3’); //2 number
118、什么是同源策略?
指: 同协议、端口、域名的安全策略,由网景(Netscape)公司提出来的安全协议!
120、为什么不能定义1px左右的div容器?
IE6下这个问题是因为默认的行高造成的,解决的方法也有很多,例如:
overflow:hidden | zoom:0.08 | line-height:1px
121、结果是什么?
function foo(){
foo.a = function(){alert(1)};
this.a = function(){alert(2)};
a = function(){alert(3)};
var a = function(){alert(4)};
};
foo.prototype.a = function(){alert(5)};
foo.a = function(){alert(6)};
foo.a(); //6
var obj = new foo();
obj.a(); //2
foo.a(); //1
122、输出结果
var a = 5;
function test(){
a = 0;
alert(a);
alert(this.a); //没有定义 a这个属性
var a;
alert(a)
}
test(); // 0, 5, 0
new test(); // 0, undefined, 0 //由于类它自身没有属性a, 所以是undefined
123、计算字符串字节数:
new function(s){
if(!arguments.length||!s) return null;
if(""==s) return 0; //无效代码,因为上一句!s已经判断过
var l=0;
for(var i=0;i
} //汉字的unCode码大于 255bit 就是两个字节
alert(l);
}(“hello world!”);
124、结果是:
var bool = !!2; alert(bool);//true;
技巧:双向非操作可以把字符串和数字转换为布尔值。
125、声明对象,添加属性,输出属性
var obj = {
name: ‘leipeng’,
showName: function(){
alert(this.name);
}
}
obj.showName();
126、匹配输入的字符:第一个必须是字母或下划线开头,后面就是字母和数字或者下划线构成,长度5-20
var reg = /1[a-zA-Z0-9_]{4,19}/,
name1 = ‘leipeng’,
name2 = ‘0leipeng’,
name3 = ‘你好leipeng’,
name4 = ‘hi’;
alert(reg.test(name1));
alert(reg.test(name2));
alert(reg.test(name3));
alert(reg.test(name4));
127、检测变量类型
function checkStr(str){
typeof str == ‘string’? alert(‘true’):alert(‘false’);
}
checkStr(‘leipeng’);
128、如何在HTML中添加事件,几种方法?
1、标签之中直接添加 οnclick=“fun()”;
2、JS添加 Eobj.onclick = method;
3、现代事件 IE9以前: obj.attachEvent(‘onclick’, method);
标准浏览器: obj.addEventListener(‘click’, method, false);
129、BOM对象有哪些,列举window对象?
1、window对象 ,是JS的最顶层对象,其他的BOM对象都是window对象的属性;
2、document对象,文档对象;
3、location对象,浏览器当前URL信息;
4、navigator对象,浏览器本身信息;
5、screen对象,客户端屏幕信息;
6、history对象,浏览器访问历史信息;
130、请问代码实现 outerHTML
//说明:outerHTML其实就是innerHTML再加上本身;
Object.prototype.outerHTML = function(){
var innerCon = this.innerHTML, //获得里面的内容
outerCon = this.appendChild(innerCon); //添加到里面
alert(outerCon);
}
演示代码:
最佳实现:on() off()
133、typeof 的返回类型有哪些?
alert(typeof [1, 2]); //object
alert(typeof ‘leipeng’); //string
var i = true;
alert(typeof i); //boolean
alert(typeof 1); //number
var a;
alert(typeof a); //undefined
function a(){;};
alert(typeof a) //function
134、简述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不支持。
135、window.onload 和 document.ready的区别?
load要等到图片和包含的文件都加在进来之后执行;
ready是不包含图片和非文字文件的文档结构准备好就执行;
136、 解析URL成一个对象?
String.prototype.urlQueryString = function(){
var url = this.split(’?’)[1].split(’&’),
len = url.length;
this.url = {};
for(var i = 0; i < len; i += 1){
var cell = url[i].split('='),
key = cell[0],
val = cell[1];
this.url[''+key+''] = val;
}
return this.url;
}
var url = '?name=12&age=23';
console.log(url.urlQueryString().age);
137、看下列代码输出什么?
var foo = “11”+2-“1”;
console.log(foo);
console.log(typeof foo);
执行完后foo的值为111,foo的类型为Number。
138、看下列代码,输出什么?
var a = new Object();
a.value = 1;
b = a;
b.value = 2;
alert(a.value);
执行完后输出结果为2
139、已知数组var stringArray = [“This”, “is”, “Baidu”, “Campus”],Alert出”This is Baidu Campus”。
答案:alert(stringArray.join(” “))
140、已知有字符串foo=“get-element-by-id”,写一个function将其转化成驼峰表示法"getElementById”。
答案:function combo(msg){
var arr = msg.split(”-”);
var len = arr.length; //将arr.length存储在一个局部变量可以提高for循环效率
for(var i=1;i
}
msg=arr.join(”");
return msg;
}
142、原生JS的window.onload与Jquery的$(document).ready(function(){})有什么不同?
window.onload()方法是必须等到页面内包括图片的所有元素加载完毕后才能执行。
$(document).ready()是DOM结构绘制完毕后就执行,不必等到加载完毕。
143、你如何优化自己的代码?
代码重用
避免全局变量(命名空间,封闭空间,模块化mvc…)
拆分函数避免函数过于臃肿:单一职责原则
适当的注释,尤其是一些复杂的业务逻辑或者是计算逻辑,都应该写出这个业务逻辑的具体过程
内存管理,尤其是闭包中的变量释放
144、请描述出下列代码运行的结果
function d(){
console.log(this);
}
d();//window
145、需要将变量e的值修改为“a+b+c+d”,请写出对应的代码
var e=”abcd”;
设计一段代码能够遍历下列整个DOM节点
console.log(specify(“hedd____df*(%$#a !!!))))))llo,Wo@@@r ld”)); //h,e,l,l,o,W,o,r,l,d
150、请将一个URL的search部分参数与值转换成一个json对象
//search部分的参数格式:a=1&b=2&c=3
function getJsonFromUrlSearch(search){
var item;
var result={};
if(search.indexOf(’&’)<0){
item=search.split(’=’);
result[item[0]]=item[1];
return result;
}
var splitArray=search.split(’&’);
for (var i = 0; i < splitArray.length; i++) {
var obj = splitArray[i];
item=obj.split(’=’);
result[item[0]]=item[1];
}
return result;
}
var c=getJsonFromUrlSearch(“a=1&b=2&c=3”);
151、请用原生js实现jquery的get\post功能,以及跨域情况下
152、请简要描述web前端性能需要考虑哪方面,你的优化思路是什么?
//参见雅虎14web优化规则
//减少http请求:
//1、小图弄成大图,2、合理的设置缓存
//3、资源合并、压缩
//将外部的js文件置底
153、简述readyonly与disabled的区别
readonly只针对input(text / password)和textarea有效,
而disabled对于所有的表单元素都有效,当表单元素在使用了disabled后,当我们将表单以POST或GET的方式提交的话,这个元素的值不会被传递出去,而readonly会将该值传递出去
155、编写一个方法,去掉一个数组的复重元素
156、写出3个使用this的典型应用
构造函数中使用this,原型中使用this,对象字面量使用this
157、请尽可能详尽的解释ajax的工作原理
思路:先解释异步,再解释ajax如何使用
Ajax的原理简单来说通过XmlHttpRequest对象来向服务器发异步请求,从服务器获得数据,然后用javascript来操作DOM而更新页面。这其中最关键的一步就是从服务器获得请求数据。要清楚这个过程和原理,我们必须对 XMLHttpRequest有所了解。
XMLHttpRequest是ajax的核心机制,它是在IE5中首先引入的,是一种支持异步请求的技术。简单的说,也就是javascript可以及时向服务器提出请求和处理响应,而不阻塞用户。达到无刷新的效果。
158、为什么扩展javascript内置对象不是好的做法?
因为扩展内置对象会影响整个程序中所使用到的该内置对象的原型属性
159、请解释一下javascript的同源策略
域名、协议、端口相同
160、什么是三元表达式?“三元”表示什么意思?
? :
因为运算符会涉及3个表达式
161、浏览器标准模式和怪异模式之间的区别是什么?
标准模式是指,浏览器按W3C标准解析执行代码;
怪异模式则是使用浏览器自己的方式解析执行代码,因为不同浏览器解析执行的方式不一样,所以我们称之为怪异模式。
浏览器解析时到底使用标准模式还是怪异模式,与你网页中的DTD声明直接相关,DTD声明定义了标准文档的类型(标准模式解析)文档类型,会使浏览器使用相应的方式加载网页并显示,忽略DTD声明,将使网页进入怪异模式
162、如果设计中使用了非标准的字体,你该如何去实现?
先通过font-face定义字体,再引用
@font-face
{
font-family: myFirstFont;
src: url(‘Sansation_Light.ttf’),
url(‘Sansation_Light.eot’); /* IE9+ */
}
163、用css分别实现某个div元素上下居中和左右居中
margin:0 auto;
164、module(12,5)//2 实现满足这个结果的modulo函数
function modulo(a,b){
return a%b;//return a/b;
}
165、HTTP协议中,GET和POST有什么区别?分别适用什么场景 ?
get传送的数据长度有限制,post没有
get通过url传递,在浏览器地址栏可见,post是在报文中传递
适用场景:
post一般用于表单提交
get一般用于简单的数据查询,严格要求不是那么高的场景
166、HTTP状态消息200 302 304 403 404 500分别表示什么
200:请求已成功,请求所希望的响应头或数据体将随此响应返回。
302:请求的资源临时从不同的 URI响应请求。由于这样的重定向是临时的,客户端应当继续向原有地址发送以后的请求。只有在Cache-Control或Expires中进行了指定的情况下,这个响应才是可缓存的
304:如果客户端发送了一个带条件的 GET 请求且该请求已被允许,而文档的内容(自上次访问以来或者根据请求的条件)并没有改变,则服务器应当返回这个状态码。304响应禁止包含消息体,因此始终以消息头后的第一个空行结尾。
403:服务器已经理解请求,但是拒绝执行它。
404:请求失败,请求所希望得到的资源未被在服务器上发现。
500:服务器遇到了一个未曾预料的状况,导致了它无法完成对请求的处理。一般来说,这个问题都会在服务器端的源代码出现错误时出现。
167、HTTP协议中,header信息里面,怎么控制页面失效时间(last-modified,cache-control,Expires分别代表什么)
Last-Modified 文 档的最后改动时间。客户可以通过If-Modified-Since请求头提供一个日期,该请求将被视为一个条件GET,只有改动时间迟于指定时间的文档 才会返回,否则返回一个304(Not Modified)状态。Last-Modified也可用setDateHeader方法来设置。
Expires 应该在什么时候认为文档已经过期,从而不再缓存它?
168、HTTP协议目前常用的有哪几个?KEEPALIVE从哪个版本开始出现的?
http1.0
http1.1 keeplive
169、业界常用的优化WEB页面加载速度的方法(可以分别从页面元素展现,请求连接,css,js,服务器等方面介绍)
170、列举常用的web页面开发,调试以及优化工具
sublime vscode webstorm hbuilder dw
httpwatch=>ie
ff:firebug
chrome:
171、解释什么是sql注入,xss漏洞
172、如何判断一个js变量是数组类型
ES5:Array.isArray()
[] instanceof Array
Object.prototype.toString.call([]);//"[object Array]"
173、请列举js数组类型中的常用方法
方法 描述
concat()
连接两个或更多的数组,并返回结果。
join()
把数组的所有元素放入一个字符串。元素通过指定的分隔符进行分隔。
pop()
删除并返回数组的最后一个元素
push()
向数组的末尾添加一个或更多元素,并返回新的长度。
reverse()
颠倒数组中元素的顺序。
shift()
删除并返回数组的第一个元素
slice()
从某个已有的数组返回选定的元素
sort()
对数组的元素进行排序
splice()
删除元素,并向数组添加新元素。
toSource()
返回该对象的源代码。
toString()
把数组转换为字符串,并返回结果。
toLocaleString()
把数组转换为本地数组,并返回结果。
unshift()
向数组的开头添加一个或更多元素,并返回新的长度。
valueOf()
返回数组对象的原始值
174、FF与IE中如何阻止事件冒泡,如何获取事件对象,以及如何获取触发事件的元素
175、列举常用的js框架以及分别适用的领域
jquery:简化了js的一些操作,并且提供了一些非常好用的API
jquery ui、jquery-easyui:在jqeury的基础上提供了一些常用的组件 日期,下拉框,表格这些组件
require.js、sea.js(阿里的玉帛)+》模块化开发使用的
zepto:精简版的jquery,常用于手机web前端开发 提供了一些手机页面实用功能,touch
ext.js:跟jquery差不多,但是不开源,也没有jquery轻量
angular、knockoutjs、avalon(去哪儿前端总监):MV*框架,适合用于单页应用开发(SPA)
176、js中如何实现一个map
数组的map方法:
概述
map() 方法返回一个由原数组中的每个元素调用一个指定方法后的返回值组成的新数组。
语法
array.map(callback[, thisArg])
参数
callback
原数组中的元素经过该方法后返回一个新的元素。
currentValue
callback 的第一个参数,数组中当前被传递的元素。
index
callback 的第二个参数,数组中当前被传递的元素的索引。
array
callback 的第三个参数,调用 map 方法的数组。
thisArg
执行 callback 函数时 this 指向的对象。
实现:
Array.prototype.map2=function(callback){
for (var i = 0; i < this.length; i++) {
this[i]=callback(this[i]);
}
};
177、js可否实现面向对象编程,如果可以如何实现js对象的继承
创建对象的几种方式
实现继承的几种方式
原型链
178、约瑟夫环—已知n个人(以编号1,2,3…分别表示)围坐在一张圆桌周围。从编号为k的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列;依此规律重复下去,直到圆桌周围的人全部出列。
179、有1到10w这个10w个数,去除2个并打乱次序,如何找出那两个数?
180、如何获取对象a拥有的所有属性(可枚举的、不可枚举的,不包括继承来的属性)
Object.keys——IE9+
或者使用for…in并过滤出继承的属性
for(o in obj){
if(obj.hasOwnproperty(o)){
//把o这个属性放入到一个数组中
}
}
181、有下面这样一段HTML结构,使用css实现这样的效果:
左边容器无论宽度如何变动,右边容器都能自适应填满父容器剩余的宽度。
转换为jquery对象: ( d o m V i e w ) 197 、 主 流 浏 览 器 内 核 I E t r i d e n t 火 狐 g e c k o 谷 歌 苹 果 w e b k i t O p e r a : P r e s t o 198 、 如 何 显 示 / 隐 藏 一 个 d o m 元 素 ? 请 用 原 生 的 J a v a S c r i p t 方 法 实 现 d o m . s t y l e . d i s p l a y = ” n o n e ” ; d o m . s t y l e . d i s p l a y = ” ” ; 199 、 J a v a S c r i p t 有 哪 几 种 数 据 类 型 N u m b e r S t r i n g B o o l e a n N u l l U n d e f i n e d O b j e c t 200 、 j Q u e r y 框 架 中 ( domView) 197、主流浏览器内核 IE trident 火狐gecko 谷歌苹果webkit Opera:Presto 198、如何显示/隐藏一个dom元素?请用原生的JavaScript方法实现 dom.style.display=”none”; dom.style.display=””; 199、JavaScript有哪几种数据类型 Number String Boolean Null Undefined Object 200、jQuery框架中 (domView)197、主流浏览器内核IEtrident火狐gecko谷歌苹果webkitOpera:Presto198、如何显示/隐藏一个dom元素?请用原生的JavaScript方法实现dom.style.display=”none”;dom.style.display=””;199、JavaScript有哪几种数据类型NumberStringBooleanNullUndefinedObject200、jQuery框架中.ajax()的常用参数有哪些?
type
类型:String
默认值: “GET”)。请求方式 (“POST” 或 “GET”), 默认为 “GET”。注意:其它 HTTP 请求方法,如 PUT 和 DELETE 也可以使用,但仅部分浏览器支持。
url
类型:String
默认值: 当前页地址。发送请求的地址。
success
类型:Function
请求成功后的回调函数。
参数:由服务器返回,并根据 dataType 参数进行处理后的数据;描述状态的字符串。
这是一个 Ajax 事件。
options
类型:Object
可选。AJAX 请求设置。所有选项都是可选的。
async
类型:Boolean
默认值: true。默认设置下,所有请求均为异步请求。如果需要发送同步请求,请将此选项设置为 false。
注意,同步请求将锁住浏览器,用户其它操作必须等待请求完成才可以执行。
beforeSend(XHR)
类型:Function
发送请求前可修改 XMLHttpRequest 对象的函数,如添加自定义 HTTP 头。
XMLHttpRequest 对象是唯一的参数。
这是一个 Ajax 事件。如果返回 false 可以取消本次 ajax 请求。
cache
类型:Boolean
默认值: true,dataType 为 script 和 jsonp 时默认为 false。设置为 false 将不缓存此页面。
jQuery 1.2 新功能。
contentType
类型:String
默认值: “application/x-www-form-urlencoded”。发送信息至服务器时内容编码类型。
默认值适合大多数情况。如果你明确地传递了一个 content-type 给 $.ajax() 那么它必定会发送给服务器(即使没有数据要发送)。
data
类型:String
发送到服务器的数据。将自动转换为请求字符串格式。GET 请求中将附加在 URL 后。查看 processData 选项说明以禁止此自动转换。必须为 Key/Value 格式。如果为数组,jQuery 将自动为不同值对应同一个名称。如 {foo:[“bar1”, “bar2”]} 转换为 ‘&foo=bar1&foo=bar2’。
dataFilter
类型:Function
给 Ajax 返回的原始数据的进行预处理的函数。提供 data 和 type 两个参数:data 是 Ajax 返回的原始数据,type 是调用 jQuery.ajax 时提供的 dataType 参数。函数返回的值将由 jQuery 进一步处理。
dataType
类型:String
预期服务器返回的数据类型。如果不指定,jQuery 将自动根据 HTTP 包 MIME 信息来智能判断,比如 XML MIME 类型就被识别为 XML。在 1.4 中,JSON 就会生成一个 JavaScript 对象,而 script 则会执行这个脚本。随后服务器端返回的数据会根据这个值解析后,传递给回调函数。可用值:
• “xml”: 返回 XML 文档,可用 jQuery 处理。
• “html”: 返回纯文本 HTML 信息;包含的 script 标签会在插入 dom 时执行。
• “script”: 返回纯文本 JavaScript 代码。不会自动缓存结果。除非设置了 “cache” 参数。注意:在远程请求时(不在同一个域下),所有 POST 请求都将转为 GET 请求。(因为将使用 DOM 的 script标签来加载)
• “json”: 返回 JSON 数据 。
• “jsonp”: JSONP 格式。使用 JSONP 形式调用函数时,如 “myurl?callback=?” jQuery 将自动替换 ? 为正确的函数名,以执行回调函数。
• “text”: 返回纯文本字符串
error
类型:Function
默认值: 自动判断 (xml 或 html)。请求失败时调用此函数。
有以下三个参数:XMLHttpRequest 对象、错误信息、(可选)捕获的异常对象。
如果发生了错误,错误信息(第二个参数)除了得到 null 之外,还可能是 “timeout”, “error”, “notmodified” 和 “parsererror”。
这是一个 Ajax 事件。
写一个post请求并带有发送数据和返回数据的样例
$.ajax({
url:“1.html”,
data:{name:“张三”,age:18},//post数据
dataType:“json”,
type:“POST”,
success:function(data){
//data:返回的数据
},
error:function(){
//异常处理
}
});
201、JavaScript数组元素添加、删除、排序等方法有哪些?
Array.concat( ) 连接数组
Array.join( ) 将数组元素连接起来以构建一个字符串
Array.length 数组的大小
Array.pop( ) 删除并返回数组的最后一个元素
Array.push( ) 给数组添加元素
Array.reverse( ) 颠倒数组中元素的顺序
Array.shift( ) 将元素移出数组
Array.slice( ) 返回数组的一部分
Array.sort( ) 对数组元素进行排序
Array.splice( ) 插入、删除或替换数组的元素
Array.toLocaleString( ) 把数组转换成局部字符串
Array.toString( ) 将数组转换成一个字符串
Array.unshift( ) 在数组头部插入一个元素
202、如何添加html元素的事件,有几种方法?请列举
a、直接在标签里添加:
206、列出3条以上ff和IE的脚本兼容问题
1、在IE下可通过document.frames[“id”];得到该IFRAME对象,
而在火狐下则是通过document.getElementById(“content_panel_if”).contentWindow;
2、IE的写法: _tbody=table.childNodes[0]
在FF中,firefox会在子节点中包含空白则第一个子节点为空白"", 而ie不会返回空白
可以通过if("" != node.nodeName)过滤掉空白子对象
3、模拟点击事件
if(document.all){ //ie下
document.getElementById(“a3”).click();
}
else{ //非IE
var evt = document.createEvent(“MouseEvents”);
evt.initEvent(“click”, true, true);
document.getElementById(“a3”).dispatchEvent(evt);
}
4、事件注册
if (isIE){window.attachEvent(“onload”, init);}else{window.addEventListener(“load”, init, false);}
207、列举可以哪些方面对前端开发进行优化
代码压缩、合并减少http请求,图片制作精灵图、代码优化
208、至少列出一种JavaScript继承的实现方式
209、如现在有一个效果,有显示用户头像、用户昵称、用户其他信息;当用户鼠标移到头像上时,会弹出用户的所有信息;如果是你,你会如何实现这个功能,请用代码实现?
//答案见:J:\代码,PPT,笔记,电子书\面试题\面试题02.html
210、call与apply有什么作用?又有什么什么区别?用callee属性实现函数递归?
apply的参数是数组,call的参数是单个的值,除此之外,两者没有差别,重点理解this的改变,callee已经不推荐使用
211、用正则表达式,写出由字母开头,其余由数字、字母、下划线组成的6~30的字符串?
var reg=/2[\da-zA-Z]{5,29}/;
212、列举浏览器对象模型BOM里常用的至少4个对象,并列举window对象的常用方法至少5个 (10分)
对象:window document location screen history navigator
方法:alert() confirm() prompt() open() close() setInterval() setTimeout() clearInterval() clearTimeout()
(详细参见:J:\代码,PPT,笔记,电子书\面试题\window对象方法.png)
214、对于apply和call两者在作用上是相同的,即是调用一个对象的一个方法,以另一个对象替换当前对象。将一个函数的对象上下文从初始的上下文改变为由 thisObj 指定的新对象。
但两者在参数上有区别的。对于第一个参数意义都一样,但对第二个参数:?apply传入的是一个参数数组,也就是将多个参数组合成为一个数组传入,而call则作为call的参数传入(从第二个参数开始)。?如 func.call(func1,var1,var2,var3)对应的apply写法为:func.apply(func1,[var1,var2,var3]) 。
215、在Javascript中什么是伪数组?如何将伪数组转化为标准数组?
伪数组(类数组):无法直接调用数组方法或期望length属性有什么特殊的行为,但仍可以对真正数组遍历方法来遍历它们。典型的是函数的argument参数,还有像调用getElementsByTagName,document.childNodes之类的,它们都返回NodeList对象都属于伪数组。
可以使用Array.prototype.slice.call(fakeArray)将数组转化为真正的Array对象。
216、写一个函数可以计算 sum(5,0,-5);输出0; sum(1,2,3,4);输出10;
function calc(){
var result=0;
for (var i = 0; i < arguments.length; i++) {
var obj = arguments[i];
result+=obj;
}
return result;
}
alert(calc(1,2,3,4));
Js基本功
217、事件代理怎么实现?
在元素的父节点注册事件,通过事件冒泡,在父节点捕获事件
218、《正则》写出正确的正则表达式匹配固话号,区号3-4位,第一位为0,中横线,7-8位数字,中横线,3-4位分机号格式的固话号
常用正则表达式语法要熟悉
/0[0-9]{2,3}-\d{7,8}/
219、《算法》 一下A,B可任选一题作答,两题全答加分
A:农场买了一只羊,第一年是小羊,第二年底生一只,第三年不生,第四年底再生一只,第五年死掉。
B:写出代码对下列数组去重并从大到小排列{5,2,3,6,8,6,5,4,7,1,9}
先去重再排序
去重方法参考:J:\代码,PPT,笔记,电子书\面试题
220、请写出一张图片的HTML代码,已知道图片地址为“images/abc.jpg”,宽100px,高50px
221、请写一个正则表达式:要求最短6位数,最长20位,阿拉伯数和英文字母(不区分大小写)组成
^(?=.\d)(?=.[a-z])(?=.*[A-Z])[a-zA-Z\d]{6,20}$
222、统计1到400亿之间的自然数中含有多少个1?比如1-21中,有1、10、11、12、13、14、15、16、17、18、19、20、21这么多自然数有13个1
答案参考:J:\代码,PPT,笔记,电子书\面试题\面试题_222.html
223、删除与某个字符相邻且相同的字符,比如fdaffdaaklfjklja字符串处理之后成为“fdafdaklfjklja”
答案参考:J:\代码,PPT,笔记,电子书\面试题\面试题_223.html
224、请写出三种以上的Firefox有但InternetExplorer没有的属性和函数
1、在IE下可通过document.frames[“id”];得到该IFRAME对象,
而在火狐下则是通过document.getElementById(“content_panel_if”).contentWindow;
2、IE的写法: _tbody=_table.childNodes[0]
在FF中,firefox会在子节点中包含空白则第一个子节点为空白"", 而ie不会返回空白
可以通过if("" != node.nodeName)过滤掉空白子对象
3、模拟点击事件
if(document.all){ //ie下
document.getElementById(“a3”).click();
}
else{ //非IE
var evt = document.createEvent(“MouseEvents”);
evt.initEvent(“click”, true, true);
document.getElementById(“a3”).dispatchEvent(evt);
}
4、事件注册
if (isIE){window.attachEvent(“onload”, init);}else{window.addEventListener(“load”, init, false);}
225、请写出一个程序,在页面加载完成后动态创建一个form表单,并在里面添加一个input对象并给它任意赋值后义post方式提交到:http://127.0.0.1/save.php
答案参考:J:\代码,PPT,笔记,电子书\面试题\面试题_225.html
226、用JavaScript实现冒泡排序。数据为23、45、18、37、92、13、24
面试经常遇到的排序,查找算法要熟悉
227、解释一下什么叫闭包,并实现一段闭包代码
简单理解就是函数的嵌套形成闭包,闭包包括函数本身及其外部作用域
228、简述一下什么叫事件委托以及其原理
在元素的父节点注册事件,通过事件冒泡,在父节点捕获事件
229、前端代码优化的方法
var User = { 对象
count = 1,属性
getCount:function(){ 方法
return this.count;
}
}
console.log(User.getCount());
var func = User.getCount;
console.log(func());
1 undefined(window);
230、下列JavaScript代码执行后,依次alert的结果是
(function test(){
var a=b=5;
alert(typeof a);
alert(typeof b);
})();
alert(typeof a);
alert(typeof b);
//number number undefined number
231、下列JavaScript代码执行后,iNum的值是
var iNum = 0;
for(var i = 1; i< 10; i++){
if(i % 5 == 0){
continue;
}
iNum++;
}
分析:
i=1 1
i=2 2
i=3 3
i=4 4
i=5
i=6 6
i=7 7
i=8 8
i=9 9
232、输出结果是多少?
1) var a;
var b = a * 0;
if (b == b) {
console.log(b * 2 + “2” - 0 + 4);
} else {
console.log(!b * 2 + “2” - 0 + 4);
}
答案:26
扩展:关于乘法操作符:J:\代码,PPT,笔记,电子书\面试题\乘性操作符.png
2)
答案:6
3) var t = 10;
function test(t){
var t = t++;//此时的t是一个局部变量,全局变量没有任何变化
console.log(t);//此时的结果又是多少?
}test(t);
console.log(t);
答案:10
4) var t = 10;
function test(test){
var t = test++;
}test(t);
console.log(t);
答案:10
6) var t = 10;
function test(test){
t = test++;
}test(t);
console.log(t);
答案:10
7) var t = 10;
function test(test){
t = t + test;//undefined+10=NaN
console.log(t);
var t = 3;
}test(t);
console.log(t);
答案:NaN 10
8)var a;
var b = a / 0;
if (b == b) {//b=NaN
console.log(!b * 2 + “2” - 0 + 4);
} else {
console.log(!b * 2 + “2” - 0 + 4);
}
答案:26
9)
答案:Infinity24
233、用程序实现找到html中id名相同的元素?
文字包裹在元素中,用以反映内容。例如:
段落包含在
元素中。
顺序表包含在
元素中。
HTML 元素不能用作语义用途以外的其他目的。例如:
包含大段引述,但并非用于文本缩进。 空白段落元素 ( ) 并非用于跳行。 文本并不直接包含任何样式信息。例如: 不使用 或等格式标记。 类或 ID 中不引用颜色或位置。 26.cookie在浏览器和服务器间来回传递。 sessionStorage和localStorage区别 sessionStorage和localStorage的存储空间更大; sessionStorage和localStorage有更多丰富易用的接口; sessionStorage和localStorage各自独立的存储空间; 27、html5有哪些新特性、移除了那些元素?如何处理HTML5新标签的浏览器兼容问题?如何区分 HTML 和 HTML5? * HTML5 现在已经不是 SGML 的子集,主要是关于图像,位置,存储,多任务等功能的增加。 * 绘画 canvas 用于媒介回放的 video 和 audio 元素 本地离线存储 localStorage 长期存储数据,浏览器关闭后数据不丢失; sessionStorage 的数据在浏览器关闭后自动删除 语意化更好的内容元素,比如 article、footer、header、nav、section 表单控件,calendar、date、time、email、url、search 新的技术webworker, websockt, Geolocation * 移除的元素 纯表现的元素:basefont,big,center,font, s,strike,tt,u; 对可用性产生负面影响的元素:frame,frameset,noframes; 支持HTML5新标签: * IE8/IE7/IE6支持通过document.createElement方法产生的标签, 可以利用这一特性让这些浏览器支持HTML5新标签, 浏览器支持新标签后,还需要添加标签默认的样式: * 当然最好的方式是直接使用成熟的框架、使用最多的是html5shim框架 28、如何区分: DOCTYPE声明\新增的结构元素\功能元素 29、语义化的理解? 用正确的标签做正确的事情! html语义化就是让页面的内容结构化,便于对浏览器、搜索引擎解析; 在没有样式CCS情况下也以一种文档格式显示,并且是容易阅读的。 搜索引擎的爬虫依赖于标记来确定上下文和各个关键字的权重,利于 SEO。 使阅读源代码的人对网站更容易将网站分块,便于阅读维护理解。 30、HTML5的离线储存? localStorage 长期存储数据,浏览器关闭后数据不丢失; sessionStorage 数据在浏览器关闭后自动删除。 31、写出HTML5的文档声明方式 32、HTML5和CSS3的新标签 HTML5: nav, footer, header, section, hgroup, video, time, canvas, audio...
CSS3: RGBA, opacity, text-shadow, box-shadow, border-radius, border-image,
border-color, transform…;
33、自己对标签语义化的理解
在我看来,语义化就是比如说一个段落, 那么我们就应该用
标签来修饰,标题就应该用
五、移动web开发
1、移动端常用类库及优缺点
知识面宽度,多多益善
2、Zepto库和JQ区别
Zepto相对jQuery更加轻量,主要用在移动端,jQuery也有对应的jQuerymobile移动端框架d
六、Ajax
1、Ajax 是什么? 如何创建一个Ajax?
Ajax并不算是一种新的技术,全称是asynchronous javascript and xml,可以说是已有技术的组合,主要用来实现客户端与服务器端的异步通信效果,实现页面的局部刷新,早期的浏览器并不能原生支持ajax,可以使用隐藏帧(iframe)方式变相实现异步效果,后来的浏览器提供了对ajax的原生支持
使用ajax原生方式发送请求主要通过XMLHttpRequest(标准浏览器)、ActiveXObject(IE浏览器)对象实现异步通信效果
基本步骤:
var xhr =null;//创建对象
if(window.XMLHttpRequest){
xhr = new XMLHttpRequest();
}else{
xhr = new ActiveXObject(“Microsoft.XMLHTTP”);
}
xhr.open(“方式”,”地址”,”标志位”);//初始化请求
xhr.setRequestHeader(“”,””);//设置http头信息
xhr.onreadystatechange =function(){}//指定回调函数
xhr.send();//发送请求
js框架(jQuery/EXTJS等)提供的ajax API对原生的ajax进行了封装,熟悉了基础理论,再学习别的框架就会得心应手,好多都是换汤不换药的内容
2、同步和异步的区别?
同步:阻塞的
-张三叫李四去吃饭,李四一直忙得不停,张三一直等着,直到李四忙完两个人一块去吃饭
=浏览器向服务器请求数据,服务器比较忙,浏览器一直等着(页面白屏),直到服务器返回数据,浏览器才能显示页面
异步:非阻塞的
-张三叫李四去吃饭,李四在忙,张三说了一声然后自己就去吃饭了,李四忙完后自己去吃
=浏览器向服务器请求数据,服务器比较忙,浏览器可以自如的干原来的事情(显示页面),服务器返回数据的时候通知浏览器一声,浏览器把返回的数据再渲染到页面,局部更新
3、如何解决跨域问题?
理解跨域的概念:协议、域名、端口都相同才同域,否则都是跨域
出于安全考虑,服务器不允许ajax跨域获取数据,但是可以跨域获取文件内容,所以基于这一点,可以动态创建script标签,使用标签的src属性访问js文件的形式获取js脚本,并且这个js脚本中的内容是函数调用,该函数调用的参数是服务器返回的数据,为了获取这里的参数数据,需要事先在页面中定义回调函数,在回调函数中处理服务器返回的数据,这就是解决跨域问题的主流解决方案
4、页面编码和被请求的资源编码如果不一致如何处理?
对于ajax请求传递的参数,如果是get请求方式,参数如果传递中文,在有些浏览器会乱码,不同的浏览器对参数编码的处理方式不同,所以对于get请求的参数需要使用 encodeURIComponent函数对参数进行编码处理,后台开发语言都有相应的解码api。对于post请求不需要进行编码
5、简述ajax 的过程。
14、什么是Ajax和JSON,它们的优缺点。
Ajax是全称是asynchronous JavaScript andXML,即异步JavaScript和xml,用于在Web页面中实现异步数据交互,实现页面局部刷新。
优点:可以使得页面不重载全部内容的情况下加载局部内容,降低数据传输量,避免用户不断刷新或者跳转页面,提高用户体验
缺点:对搜索引擎不友好;要实现ajax下的前后退功能成本较大;可能造成请求数的增加跨域问题限制;
JSON是一种轻量级的数据交换格式,ECMA的一个子集
优点:轻量级、易于人的阅读和编写,便于机器(JavaScript)解析,支持复合数据类型(数组、对象、字符串、数字)
15、http常见的状态码有那些?分别代表是什么意思?
200 - 请求成功
301 - 资源(网页等)被永久转移到其它URL
404 - 请求的资源(网页等)不存在
500 - 内部服务器错误
16、一个页面从输入 URL 到页面加载显示完成,这个过程中都发生了什么?
分为4个步骤:
当发送一个 URL 请求时,不管这个 URL 是 Web 页面的 URL 还是 Web 页面上每个资源的 URL,浏览器都会开启一个线程来处理这个请求,同时在远程 DNS 服务器上启动一个 DNS 查询。这能使浏览器获得请求对应的 IP 地址。
浏览器与远程 Web 服务器通过 TCP 三次握手协商来建立一个 TCP/IP 连接。该握手包括一个同步报文,一个同步-应答报文和一个应答报文,这三个报文在 浏览器和服务器之间传递。该握手首先由客户端尝试建立起通信,而后服务器应答并接受客户端的请求,最后由客户端发出该请求已经被接受的报文。
一旦 TCP/IP 连接建立,浏览器会通过该连接向远程服务器发送 HTTP 的 GET 请求。远程服务器找到资源并使用 HTTP 响应返回该资源,值为 200 的 HTTP 响应状态表示一个正确的响应。
此时,Web 服务器提供资源服务,客户端开始下载资源。
17、ajax请求的时候get 和post方式的区别
get一般用来进行查询操作,url地址有长度限制,请求的参数都暴露在url地址当中,如果传递中文参数,需要自己进行编码操作,安全性较低。
post请求方式主要用来提交数据,没有数据长度的限制,提交的数据内容存在于http请求体中,数据不会暴漏在url地址中。
18、ajax请求时,如何解释json数据
使用eval() 或者JSON.parse() 鉴于安全性考虑,推荐使用JSON.parse()更靠谱,对数据的安全性更好。
20、为什么利用多个域名来存储网站资源会更有效?
确保用户在不同地区能用最快的速度打开网站,其中某个域名崩溃用户也能通过其他郁闷访问网站,并且不同的资源放到不同的服务器上有利于减轻单台服务器的压力。
21、请说出三种减低页面加载时间的方法
1、压缩css、js文件
2、合并js、css文件,减少http请求
3、外部js、css文件放在最底下
4、减少dom操作,尽可能用变量替代不必要的dom操作
22、HTTP状态码都有那些。
200 OK //客户端请求成功
400 Bad Request //客户端请求有语法错误,不能被服务器所理解
403 Forbidden //服务器收到请求,但是拒绝提供服务
404 Not Found //请求资源不存在,输入了错误的URL
500 Internal Server Error //服务器发生不可预期的错误
503 Server Unavailable //服务器当前不能处理客户端的请求,一段时间后可能恢复正常
七、JS高级
1、 JQuery一个对象可以同时绑定多个事件,这是如何实现的?
jQuery可以给一个对象同时绑定多个事件,低层实现方式是使用addEventListner或attachEvent兼容不同的浏览器实现事件的绑定,这样可以给同一个对象注册多个事件。
2、 知道什么是webkit么? 知道怎么用浏览器的各种工具来调试和debug代码么?
Webkit是浏览器引擎,包括html渲染和js解析功能,手机浏览器的主流内核,与之相对应的引擎有Gecko(Mozilla Firefox 等使用)和Trident(也称MSHTML,IE 使用)。
对于浏览器的调试工具要熟练使用,主要是页面结构分析,后台请求信息查看,js调试工具使用,熟练使用这些工具可以快速提高解决问题的效率
3、 如何测试前端代码? 知道BDD, TDD, Unit Test么? 知道怎么测试你的前端工程么(mocha, sinon, jasmin, qUnit…)?
了解BDD行为驱动开发与TDD测试驱动开发已经单元测试相关概念,
4、前端templating(Mustache, underscore, handlebars)是干嘛的, 怎么用?
Web 模板引擎是为了使用户界面与业务数据(内容)分离而产生的,
Mustache 是一个 logic-less (轻逻辑)模板解析引擎,它的优势在于可以应用在 Javascript、PHP、Python、Perl 等多种编程语言中。
Underscore封装了常用的JavaScript对象操作方法,用于提高开发效率。
Handlebars 是 JavaScript 一个语义模板库,通过对view和data的分离来快速构建Web模板。
5、简述一下 Handlebars 的基本用法?
没有用过的话说出它是干什么的即可
官网:http://handlebarsjs.com/
参考:J:\代码,PPT,笔记,电子书\面试题\handlebarDemo
6、简述一下 Handlerbars 的对模板的基本处理流程, 如何编译的?如何缓存的?
学习技术不仅要会用,还有熟悉它的实现机制,这样在开发中遇到问题时才能更好的解决
7、用js实现千位分隔符?
原生js的熟练度,实践经验,实现思路
8、检测浏览器版本版本有哪些方式?
IE与标准浏览器判断,IE不同版本的判断,userAgent var ie = /@cc_on !@/false;
9、我们给一个dom同时绑定两个点击事件,一个用捕获,一个用冒泡,你来说下会执行几次事件,然后会先执行冒泡还是捕获
对两种事件模型的理解
10、实现一个函数clone,可以对JavaScript中的5种主要的数据类型(包括Number、String、Object、Array、Boolean)进行值复制
• 考察点1:对于基本数据类型和引用数据类型在内存中存放的是值还是指针这一区别是否清楚
• 考察点2:是否知道如何判断一个变量是什么类型的
• 考察点3:递归算法的设计
// 方法一:
Object.prototype.clone = function(){
var o = this.constructor === Array ? [] : {};
for(var e in this){
o[e] = typeof this[e] === “object” ? this[e].clone() : this[e];
}
return o;
}
//方法二:
/**
var arr=[1,2,3,3,4,4,5,5,6,1,9,3,25,4];
function deRepeat(){
var newArr=[];
var obj={};
var index=0;
var l=arr.length;
for(var i=0;i
{
obj[arr[i]]=1;
newArr[index++]=arr[i];
}
else if(obj[arr[i]]==1)
continue;
}
return newArr;
}
var newArr2=deRepeat(arr);
alert(newArr2); //输出1,2,3,4,5,6,9,25
12、小贤是一条可爱的小狗(Dog),它的叫声很好听(wow),每次看到主人的时候就会乖乖叫一声(yelp)。从这段描述可以得到以下对象:
function Dog() {
this.wow = function() {
alert(’Wow’);
}
this.yelp = function() {
this.wow();
}
}
小芒和小贤一样,原来也是一条可爱的小狗,可是突然有一天疯了(MadDog),一看到人就会每隔半秒叫一声(wow)地不停叫唤(yelp)。请根据描述,按示例的形式用代码来实。(继承,原型,setInterval)
function MadDog() {
this.yelp = function() {
var self = this;
setInterval(function() {
self.wow();
}, 500);
}
}
MadDog.prototype = new Dog();
//for test
var dog = new Dog();
dog.yelp();
var madDog = new MadDog();
madDog.yelp();
13、下面这个ul,如何点击每一列的时候alert其index?(闭包)
祝君好运!
a-zA-Z_ ↩︎
a-ZA-Z ↩︎