html
什么是语义化的HTML?
- 选择合适的标签。搜索引擎的爬虫也依赖于标记来确定上下文和各个关键字的权重。这对搜索引擎的抓取有好处。
- 符合内容的结构化:在没有CSS的情况下,让页面展现出清晰地结构。
- 有利于开发和维护:能够使阅读源代码的人更容易明白网页的结构。
说下行内元素和块级元素的区别?行内块元素的兼容性使用?(IE8 以下)
行内元素特性:
- 和相邻的内联元素在同一行
- 宽度、高度,padding-top/bottom、margin-top/bottom都不可设置
块级元素特性:
- 总是独占一行
- 宽度,高度,内边距,外边距都可以设置
div { display: inline-block;//先用display:inline-block属性触发块元素 *zoom: 1;//通过zoom:1触发块元素的layout *display: inline;//让块元素呈x现为内联对象 }
XHTML和HTML有什么区别
XHTML是更严格的HTML标准,主要表现在:XHTML元素必须正确的嵌套和关闭,标签名必须用小写字母,文档必须要有根元素
前端页面有哪三层构成,分别是什么?作用是什么?
- 结构层:主要指DOM节点,html
- 表现层:主要指页面渲染,css
- 行为层:主要指页面的动画效果,js
Doctype作用?标准模式与兼容模式各有什么区别?
- Doctype在文档的第一行,处于html标签之前。告诉我们的浏览器用什么文档标准来解析文档。Doctype不存在或格式不正确会导致文档以兼容模式呈现。
- 标准模式:标准模式下的排版和js的运作模式都是按照该浏览器支持的最高标准来执行的。
- 兼容模式下,页面以宽松的,向后兼容的方式显示,模拟老式浏览器的行为以防站点无法工作。
你知道多少种Doctype文档类型?
对于标准模式,有严格型。对于准标准模式,有过渡型,框架集型。这两种模式的差异几乎可以忽略不计。
HTML5 为什么只需要写 <!DOCTYPE HTML>?
HTML5不基于SGML(标准通用标记语言)的子集,因此不需要对DTD(文档类型定义规则)进行引用。但是需要Doctype来规范浏览器的行为。
html5有哪些新特性、移除了那些元素?如何处理HTML5新标签的浏览器兼容问题?如何区分 HTML 和
HTML5?
新特性:
- 语义化更好的标签:header,footer,nav,aside,article,section
- 对本地离线存储更好的支持:localStorage长期存储数据,浏览器关闭后数据不丢失。sessionStorage浏览器关闭后自动删除。
- 画布canvas,音频audio,视频video,地理Geolocation
- 新的表单控件:calendar,date,time,email,URL,search
- 新的表单元素:atalist 元素规定输入域的选项列表。 keygen 元素的作用是提供一种验证用户的可靠方法。 output 元素用于不同类型的输出
- webworker:当前javascript的主线程中,使用Worker类加载一个javascript文件来开辟一个新的线程,起到互不阻塞执行的效果,并且提供主线程和新线程之间数据交换的接口:postMessage,onmessage。
- JavaScript是单线程的,在执行过程中会阻塞页面的渲染和其他脚本的执行。因此webworker可以在主线程当中开启一个新的线程,起到互不阻塞执行的效果。通过 worker = new Worker( url ) 加载一个JS文件来创建一个worker,同时返回一个worker实例。通过worker.postMessage( data ) 方法来向worker发送数据。绑定worker.onmessage方法来接收worker发送过来的数据。
- websocket:webscoket是HTML5提供的传输协议。它可以将服务器的更新及时主动的发给客户端
移除了纯表现的元素:big,center,font,strike等等。对可用性产生负面影响的元素:frame,frameset,noframes;
浏览器兼容问题:IE8/IE7/IE6支持通过document.createElement方法产生的标签,可以利用这一特性让这些浏览器支持HTML5新标签。当然最好的方式是直接使用成熟的框架、使用最多的是html5shim框架
如何区分:DOCTYPE声明\新增的结构元素\功能元素
iframe的优缺点?
优点:
- 解决加载缓慢的第三方内容如图标和广告等的加载问题
- Security sandbox
- 并行加载脚本
缺点:
- iframe会阻塞主页面的Onload事件;
- 即时内容为空,加载也需要时间
- 没有语意
div+css的布局较table布局有什么优点?
- 改版的时候更方便 只要改css文件。
- 页面加载速度更快、结构化清晰、页面显示简洁。
- 表现与结构相分离。
- 易于优化(seo)搜索引擎更友好,排名更容易靠前。
<meta>文档编码格式
http-equivcontent-type值可以设计文档的编码格式。把 content 属性关联到 HTTP 头部。
<meta http-equiv='Content-Type' content='text/html; charset=gbk'>
CSS
页面导入样式时,使用link和@import有什么区别?
- 就标签的分类来说,link属于HTML标签,而@import是CSS提供的。而且link的权重大于@import。
- 加载顺序来说,link引用的css文件,页面载入的时候同时加载。而@import是等到页面加载完成后再加载。
- 兼容性来说,link没有兼容性问题,@import在IE5以上才可识别
- 使用DOM控制样式时,link支持js操作DOM改变样式。@import不行。
CSS放在顶部/底部有什么区别
- CSS放在顶部时,页面会逐步呈现出来。因为浏览器在页面载入的时候同时加载css。浏览器会根据html生成DOM树,根据css生成渲染树。
- 但是放在底部页面会出现白屏或者闪跳的情况。因为放在底部时,css是等页面下载完后再被下载。浏览器为了弥补样式比较靠后的加载,为了逐步呈现从而延迟呈现,因此出现白屏的情况。
什么是 FOUC(无样式内容闪烁)?你如何来避免 FOUC?
就是@import引起的。@import是等到页面加载完成后再加载。因此会出现闪烁的感觉。解决办法是link引用css文件
简要说一下CSS的元素分类
块级元素:div p ul ol li form
行内元素:span a input img strong em label
CSS 选择符有哪些?哪些属性可以继承?优先级算法如何计算? CSS3新增伪类有那些?以及这些选择器的使用场景?
选择器:(按优先级)
- 通配符* (*, > ,+ 选择器的权重都是0)
- id选择器 #myid (权重100)
- class选择器 .class (10)
- 属性选择器 input[type="button"](10)
- 伪类选择器 a:link a:visited a:hover a:visited(10)
- 标签选择器 p div (1)
- 伪元素选择器 a:before a:after :first-child(1)
- 相邻+,子>,后代选择器
优先级算法:同权重下以最近者为准
!important>行内样式(权重1000)>id选择器(权重100)>id选择器 |属性选择器|伪类选择器 (权重10)>标签选择器|伪元素选择器(权重1)
可继承的样式:font的样式,color,visiblity
不可继承的:关于盒模型的:width height margin padding border
新增伪类:first-child last-child nth-child(n)
CSS选择器,nth-chlid(n)和nth-of-type(n)区别
ele:nth-of-type(n)是指父元素下第n个ele元素, 而ele:nth-child(n)是指父元素下第n个元素且这个元素为ele,若不是,则选择失败
介绍一下CSS的盒子模型?
W3C标准盒模型:content,padding,border,margin。其中width指的是内容content的宽度
IE盒模型:content,padding,border,margin。其中width指的是content的宽度+padding+border的宽度
box-sizing常用的属性有哪些?分别有什么作用?
是CSS3中提供的属性。主要控制盒模型的解析方式。每种盒模型计算元素宽高的方式不同:
- 它的默认值是content-box,也就是width的宽度指的是内容content的宽度。是W3C标准盒模型。
- border-box的width是content+padding+border。也就是IE盒模型
- 还有padding-box:width指的是content+padding的宽度。
display的值:
规定元素生成框的类型:
- block:块类型元素
- inline:行内元素
- inline-block:行内块级元素
- list-item:块类型元素,并添加样式列表标记
- none:元素脱离文档流,不会显示
display:none与visibility:hidden的区别是什么?
他们都可以隐藏对应的元素。
- display:none:使元素脱离文档流,不占用空间。其他元素会靠拢,就当他不存在一样。
- visibility:hidden:不会脱离文档流。
position的值, relative和absolute分别是相对于谁进行定位的?
- relative:相对于其在普通流中的位置定位
- absolute:相对于离其最近的已定位的父元素定位,如果没有就相对于窗口。
- fixed:相对于浏览器窗口定位。
- static:元素在正常流当中,并且忽略其top,bottom,left,right值
- inherit:从父元素继承position的值
为什么要初始化CSS样式?
因为浏览器的兼容问题,不同浏览器对某些标签的默认值不同。如果没有初始化,会导致页面在不同浏览器中存在差异。
垂直居中设置(已知大小和未知大小,图片)多行文本居中
已知大小:
块元素:绝对定位后margin左上都设置为负的1/2宽高。
.center{ position: absolute; width: 200px; height: 200px; left:50%; top:50; margin-top:-100px; margin-left: -100px; }
文本:将文本text-align:center;line-height设置为父容器的高;
.text{ height:100px; text-align: center; line-height: 100px; }
多行文本居中:width,height必须使用px单位,再配合vertial-align:middle和display:table-cell属性,且div不能浮动,如果浮动就在里面再添加一个div
.parent{ display: table-cell; vertical-align: middle; }
未知大小元素居中:
方法一:使用CSS3的flex-box
.wrap { display: flex; align-items: center; justify-content: center; }
方法2:父元素相对定位,子元素绝对定位,左右为50%,再使用transform:translate上下移动自身的-50%;
.parent{ position: relative; } .child{ position: absolute; left: 50%; top: 50%; -webkit-transform: translate(-50%,-50%); }
方法4:给子元素加上table标签,让table的margin:0 auto;height:100%;
<table style="margin: 0 auto;height: 100%;"> <tbody> <tr> <td> <ul ><!-- ul居中--> <li>8888888888</li> <li>8888888888</li> <li>8888888888</li> <li>8888888888</li> <li>8888888888</li> </ul> </td> </tr> </tbody> </table>
居中图片:
.parent{ display:table-cell; vertical-align:middle; text-align:center; }
浮动原理,浮动产生的问题,CSS清除浮动的几种方法(至少两种)
浮动的元素脱离文档流,不占用空间。可以向左和向右浮动,直到它的外边缘碰到包含框或者另外一个浮动框的边缘为止。
浮动产生的问题:
- 因为浮动的元素脱离文档流,同级非浮动的元素会表现的他不存在一样。
- 如果父元素没有设置宽高,其子元素都浮动的话,会导致父元素的高度无法撑开。影响与父元素同级的元素。
解决办法:
- 同级的元素被覆盖,可以浮动同级元素,但是不推荐这种做法,因为后面的布局会受到影响。也可以给非浮动元素添加clear:both;
- 可以在浮动元素的后面加上空标签清除浮动
- 可以给父元素添加一个after伪元素。也可以让父元素overflow:hidden/auto;*zoom:1;
CSS隐藏元素的几种方法(至少说出三种)
- display:none;不占用空间
- height:0;overflow:hidden
- visibility:hidden;占用空间,不影响点击事件
- opacity:0;
<strong>,<em>和<b>,<i>标签
- strong:逻辑标记,粗体强调标签表示内容的重要性
- em:斜体强调标签,更强烈强调,表示内容的强调点
- b:物理标记,只是单纯的加粗
- i:物理标记,单纯的斜体
img的alt与title有何异同?
- alt:用于图片的替代文字,当不能显示图片时显示。
- title:用于提供元素的信息,鼠标悬停时显示(在IE浏览器下会在没有title时显示alt)
px,em的区别
它们都是长度单位,px的值是固定的,指定多少就是多少,em的值是不固定的,他会继承父级元素的大小。浏览器默认字体高都是16排序,所以未经调整的话1em=16px;
怎么实现三角形?
宽高设为0,border设置很大的宽度,再根据所需要的三角形方向设置border-left/right等。
#triangle-left { width: 0px; height: 0px; border: 100px solid transparent; border-right: 100px solid red; }
怎么实现一个圆形可点区域?
1.border-radius设置成50%;
.circle { width: 100px; height: 100px; border-radius: 50%; cursor: pointer; }
2.map+area
<img src="t.jpg" width="1366" height="768" border="0" usemap="#Map" /> <map name="Map" id="Map"> <area shape="circle" coords="821,289,68" href="www.baidu.com" target="_blank" /> </map>
<area shape="circle" coords="x1, y1,r" href=url>表示设定热点的形状为圆形,圆心坐标为(X1,y1),半径为r。
3.JS实现,获取鼠标点击位置坐标,判断其到圆点的距离是否不大于圆的半径,来判断点击位置是否在圆内
document.onclick = function(e) { var r = 50; var x1 = 100; var y1 = 100; var x2= e.clientX; var y2= e.clientY; var distance = Math.abs(Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2))); if (distance <= 50) alert("Yes!"); }
css一个冒号和两个冒号区别?
一个冒号用于CSS伪类,两个冒号用于CSS伪元素。它是CSS3中引入的,为了区分伪类和伪元素。为了兼容IE,还是用一个比较好。
两栏分布,左边定宽右边自适应。
左侧固定宽度,让他绝对定位。右侧margin-left设为左侧宽度
.left{ width:200px; height: 800px; position: absolute; left:0; top:0; } .right{ height: 800px; margin-left: 200px; background-color: green; }
三栏分布
左侧右侧固定宽度并且绝对定位。中间设置marginleft和right。
.left{ width: 200px; position: absolute; left: 0; top: 0; height: 800px; } .right{ width: 300px; position: absolute; right: 0; top: 0; height: 800px; } .main{ /* position: absolute; left: 200px; right: 300px; */ margin-left: 200px; margin-right: 300px; }
css hack原理和分类,利弊
原理:由于不同的浏览器和浏览器各版本对CSS的支持及解析结果不一样,以及CSS优先级对浏览器展现效果的影响,我们可以据此针对不同的浏览器情景来应用不同的CSS。
分类:
- CSS属性前缀法 :IE6能识别下划线"_"和星号" * ",IE7能识别星号" * ",IE6~IE10都认识"\9",但firefox前述三个都不能认识
- 选择器前缀法:IE6能识别*html .class{},IE7能识别*+html .class{}或者*:first-child+html .class{}
- IE条件注释法(即HTML头部引用if IE)针对所有IE(注:IE10+已经不再支持条件注释): <!--[if IE]>IE浏览器显示的内容 <![endif]-->,针对IE6及以下版本: <!--[if lt IE 6]>只在IE6-显示的内容 <![endif]-->。这类Hack不仅对CSS生效,对写在判断语句里面的所有代码都会生效。
利弊:使用hack虽然对页面表现的一致性有好处,但过多的滥用会造成html文档混乱不堪,增加管理和维护的负担。
浏览器前缀
现在写css3代码的时候,为了实现兼容性,需要在前面加前缀以便兼容对应的浏览器。
-webkit //Webkit 谷歌和Safari浏览器 -moz //Gecko内核,火狐浏览器 -o //Presto内核,Opera浏览器 -ms //Trident内核,IE浏览器
什么是Css Hack?ie6,7,8的hack分别是什么?
对不同的浏览器写不同的CSS的过程,就是CSS hack
background-color:red\9; /*all ie*/ background-color:yellow\0; /*ie8*/ +background-color:pink; /*ie7*/ _background-color:orange; /*ie6*/
解释下 CSS sprites,以及你要如何在页面或网站中使用它。
把网页中一些背景图片整合到一张图片文件中。利用CSS的background-image,background-position组合进行定位。减少HTTP请求次数。
对BFC规范的理解?
块级格式化上下文,是CSS2.1提出的一个概念:它决定了元素如何对其内容进行布局,以及和其他元素的关系和相互作用。一个创建了BFC的盒子是独立布局的,盒子里面的元素的样式不会影响到外面的元素。
Css渲染机制
在网页中的应该使用奇数还是偶数的字体?为什么呢?
- 偶数字号相对更容易和 web 设计的其他部分构成比例关系
- 为了迁就ie6,ie6会把定义为13px的字渲染成14px
- 偶数宽的汉字显得均衡
iconfont矢量图标优点和缺点
Iconfont 就是指用字体文件取代图片文件,来展示图标、特殊字体等元素的一种方法。
优点:
- 加载文件体积小。
- 可以直接通过css的font-size,color修改它的大小和颜色,对于需要缩放多个尺寸的图标,是个很好的解决方案。
- 支持一些css3对文字的效果,例如:阴影、旋转、透明度。
- 兼容低版本浏览器。
缺点:
- 矢量图只能是纯色的。
- 制作门槛高,耗时长,维护成本也很高。
知道的网页制作会用到的图片格式有哪些?
- png-8,png-24,jpeg,gif,svg,Webp,Apng
- Webp:谷歌开发的为了加快图片下载速度的图片格式。它的图片大小只有JPEG的2/3.
- Apng:可以实现png格式的动态图片效果
canvas为什么会出现,用来做什么的;
canvas 元素使用 JavaScript 在网页上绘制图像,适合像素处理,动态渲染和大数据量绘制
简述一下src与href的区别。
- src用于替换当前元素,指向外部资源的位置,指向的内容会嵌入到文档当中,它会阻塞其他资源的下载。直到该资源下载执行完毕。比如js脚本,image图片等
- href指向网络资源所在的位置,它会并行下载资源并且不会停止对当前文档的处理,比如link方式引入css文件。
什么是外边距重叠?重叠的结果是什么?
CSS中相邻两个盒子的外边距会结合成一个单独的外边距,这种合并的方式称为折叠。两个浮动的块元素不存在margin折叠的情况
折叠结果遵循以下原则:
- 两个相邻的外边距都是正数时,折叠结果是它们两者之间较大的值
- 两个相邻的外边距都是负数时,折叠结果是两者绝对值的较大值
- 两个外边距一正一负时,折叠结果是两者的相加的和
两个块状元素上下的margin-top和margin-bottom会重叠。啥原因?怎么解决?
CSS中相邻两个盒子的外边距会结合成一个单独的外边距,这种合并的方式称为折叠。
而对于标准浏览器来说:两个浮动的块元素不存在margin折叠的情况,但是此时加浮动后会造成IE6的双边距bug,可以让其设置为_diplay:inline;
rgba()和opacity的透明效果有什么不同?
都能实现透明效果。opacity会作用于元素的背景和内容,rgba只会作用于背景。
关于letter-spacing的妙用知道有哪些么?
以用于消除inline-block元素间的换行符空格间隙问题。
Sass、LESS是什么?大家为什么要使用他们?
他们是CSS预处理器,他们是一种特殊的语法/语言编译成CSS。例如LESS是一种动态样式语言. 将CSS赋予了动态语言的特性,如变量,继承,运算, 函数. LESS 既可以在客户端上运行 (支持IE 6+, Webkit, Firefox),也可一在服务端运行 (借助 Node.js)
为什么要使用它们?
- 结构清晰,便于扩展。
- 可以方便地屏蔽浏览器私有语法差异。
- 可以轻松实现多重继承。
- 完全兼容 CSS 代码,可以方便地应用到老项目中。
知道css有个content属性吗?有什么作用?有什么应用?
用在before和after伪元素上,用来插入生成内容。
最常见的应用就是清除浮动:
.parent:after{ content:'.'; height:0; visiblity:hidden; display:block; clear:both; *zoom:1; // for IE6 }
去除inline-block间隙的方法
- 去除标签内的空格和换行符(代码可读性变差,中间可以加注释分开)
- inline-clock的元素设一个负的margin值:3px;margin负值的大小与上下文的字体和文字大小相关
- 父元素设置font-size:0;-webkit-text-size-adjust:none;
- 使用letter-spacing字符间距:父元素letter-spacing: -3px;inline-clock的元素设letter-spacing: 0px;
- 使用word-spacing单词间距:父元素word-spacing: -6px;inline-clock的元素设letter-spacing: 0px;word-spacing的负值只要大到一定程度,其兼容性上的差异就可以被忽略
媒体查询
使用@media可以针对不同的媒体类型或者不同屏幕大小来定义不同的样式
@media screen and/not/only (min-width:365px,max-width:667px;)//iphone6 @media screen and/not/only (min-width:768px,max-width:1024px;)//ipad @media screen and/not/only (min-width:1024px)//sm-screen
Css实现动画效果Animation还有哪些其他属性。
CSS3动画的属性主要分为三类:
transform
- 元素顺时针旋转的角度rotate
- 设置元素放大或缩小的倍数scale
- 设置元素的位移translate
- 设置元素倾斜的角度skew
transition过渡:可以在不使用 Flash 动画或 JavaScript 的情况下,当元素从一种样式变换为另一种样式时为元素添加效果。
animation:@keyframes 规则用于创建动画。在 @keyframes 中规定某项 CSS 样式,就能创建由当前样式逐渐改为新样式的动画效果
怎么在页面里放置一个很简单的图标,不能用img和background-img
canvas,icon库
谈一谈flexbox,讲一讲哪些浏览器已经支持。
弹性布局。把复杂的网站布局变得简易和快速。
如果我们把Flexbox新语法、旧语法混合在一起使用,在现代浏览器(Chrome、Firefox、Safari、Opera Presto 12.1+,IE10+,IOS和Android)可以得到很好的支持。在这里新旧语法的顺序显得非常重要。需要确保老语法不要覆盖新语法。写的时候对于不同的浏览器加上不同的前缀。
任何一个容器都可以指定为Flex布局,它有如下属性(主轴排列方向flex-direction,是否换行flex-wrap,主轴对齐方式justify-content,与主轴垂直的对其方式align-content):
.flex-container { display: -ms-flexbox; display: -webkit-flex; display: flex; /*主轴方向:项目排列方向水平*/ -webkit-flex-direction: row; -ms-flex-direction: row; flex-direction: row; /*超出容器后是否换行:换行*/ -webkit-flex-wrap: wrap; -ms-flex-wrap: wrap; flex-wrap: wrap; /*主轴对齐方向:水平居中*/ -webkit-justify-content: center; -ms-flex-pack: center; justify-content: center; /*垂直方向的对齐方式:垂直居中*/ -webkit-align-content: center; -ms-flex-line-pack: center; align-content: center; -webkit-align-items: center; -ms-flex-align: center; align-items: center; }
你了解哪些布局?你平时有使用过什么布局实现?
- 浮动布局
- 弹性盒模型布局:主要解决移动端屏幕宽度不定的问题。
- 定位布局
DOM
DOM操作——怎样添加、移除、移动、复制、创建和查找节点。
- createAttribute() 创建属性节点。
- createElement() 创建元素节点。
- createTextNode() 创建文本节点。
- parent.removeChild(child);
- parent.replaceChild(new,old);
- parent.appendChild(child)
- parent.insertBefore(before,old)
- getElementById("id")
- getElementsByClassName("class")
- getElementsByTagName("p")
NodeList和Array的区别
NodeList是DOM操取出来的集合,是集合而不是普通的数组,因此不能使用数组元素的方法来操作nodelist
NodeList具有length,下标索引这些数组的属性特征
NodeList最大的特点就是时效性(live),这个集合是“动态的”:每当文档结构发生变化时,它会得到更新,因此在迭代nodelist的时候,应该将其length缓存到变量值,否则有可能会造成无限循环的问题,而且应该尽量减少访问nodelist的次数,因为每次访问nodelist都会进行一次基于文档的查询,我们应该将nodelist中取得的值缓存起来。
另外,我们可以把NodeList转化为数组,方便操作
在IE8+和其他浏览器当中可以使用
Array.prototype.slice.call(nodelist,0)
在IE中必须手动枚举成员
使用try-catch
另外ES6当中提供了Array.from()将类数组对象转化为数组var brr=Array.from(nodelist);
function converToArray(nodelist) { var arr = []; var len = nodelist.length; try { arr = Array.prototype.slice.call(nodelist, 0)); //针对非IE浏览器 } catch (error) { for (var i = 0; i < len; i++) { arr.push(nodelist[i]) } } return arr; }
事件委托是什么?事件委托的缺点
事件委托:是 JavaScript 中绑定事件的常用技巧,利用事件模型中的冒泡原理,将事件绑定在更上层的父元素时,通过检查事件的目标对象来判断并获取事件源。使用事件代理的好处是可以提高性能。
使用场景:
- 给许多子元素绑定相同的事件,比如ul的li元素,或者table的td元素。可以大量节省内存,减少事件注册。
- 可以实现当新增子对象时无需再次绑定事件,对于动态内容及其合适
缺点:事件代理的常用应用应该仅限于上述需求,如果把所有事件都用事件代理,可能会出现本不该被触发的事件被绑定上了事件的情况。
DOM0和DOM2的区别
- DOM0中事件一旦发生就直接调用事件句柄,无传播过程。在DOM2中有一个事件的传播过程。包括事件捕获,目标元素的事件处理程序运行,事件冒泡。
- 一个DOM对象注册多个类型相同的事件时,DOM0级中会发生事件的覆盖,而DOM2级中则会依次执行各个事件函数。
- DOM0级事件的注册是直接将事件处理程序作为js对象的属性,或者是将js代码作为HTML元素的性质值。在DOM2中,事件的注册可以使用addEventListener("click",fn,false)的方法。事件删除用removeEventListener()
冒泡和捕捉
- 事件捕捉:事件由document对象一直向下传播到目标元素
- 事件冒泡:事件从目标元素上升一直打到document
如何阻止事件冒泡和默认事件
- IE:window.event.cancelBuble=true;
- DOM2:ev.stopPropogation();
- 阻止默认行为:return false;
事件模型
在各种浏览器中存在3种事件模型:
1.DOM0(所有浏览器都支持):
- DOM0中事件一旦发生就直接调用事件句柄,无传播过程
- 一个DOM对象注册多个类型相同的事件时,DOM0级中会发生事件的覆盖
- DOM0级事件的注册是直接将事件处理程序作为js对象的属性,或者是将js代码作为HTML元素的性质值。
2.DOM2(除了IE意外都支持)
- 在DOM2中有一个事件的传播过程。包括事件捕获,目标元素的事件处理程序运行,事件冒泡。
- DOM2级中一个DOM对象注册多个类型相同的事件时,则会依次执行各个事件函数。
- 在DOM2中,事件的注册可以使用addEventListener("click",fn,false)的方法。事件删除用removeEventListener()
- event对象是事件处理函数的参数,事件源是e.target
3.IE事件模型:
- IE的事件传播过程只有DOM0级和DOM2级中第二第三阶段,也就是只冒泡,不捕捉。
- ie中也可以在一个对象上添加多个事件处理函数
- 事件的注册用attachEvent("onclik",fn);事件删除用detachEvent();
- IE中的event对象不是事件处理函数的参数,而是window,并且事件源是srcElement
document.write()用法,和innerHTML区别?
document.write()方法可以用在两个方面:
- 页面载入过程中用实时脚本创建页面内容
- 用延时脚本创建本窗口或新窗口的内容。
document.write只能重绘整个页面。innerHTML可以重绘页面的一部分
window.onload和$(document).ready区别?用原生实现
window.onload()方法是必须等到页面内包括图片的所有元素加载完毕后才能执行。
$(document).ready()是DOM结构绘制完毕后就执行,不必等到加载完毕。
function ready(fn){ if(document.addEventListener) { //标准浏览器 document.addEventListener('DOMContentLoaded', function() { //注销事件, 避免反复触发 document.removeEventListener('DOMContentLoaded',arguments.callee, false); fn(); //执行函数 }, false); }else if(document.attachEvent) { //IE document.attachEvent('onreadystatechange', function() { if(document.readyState == 'complete') { document.detachEvent('onreadystatechange', arguments.callee); fn(); //函数执行 } }); } };
attribute和property的区别是什么?
- attribute是dom元素在文档中作为html标签拥有的属性;
- property就是dom元素在js中作为对象拥有的属性。
所以:
- 对于html的标准属性来说,attribute和property是同步的,是会自动更新的,
- 但是对于自定义的属性来说,他们是不同步的,
dom3新增加了哪些特性,哪些已经被完全接受了
事件循环
如何在页面中插入一些数据
原生js添加class怎么添加,如果本身已经有class了,会不会覆盖,怎么保留?
document.getElementById("flag").className = "mycalss"
JavaScript
eval是做什么的?
- 作用:把对应的字符串解析成js代码并运行,返回执行的结果。
- 缺点:应该避免使用eval,因为不安全,非常耗性能(两次,一次解析成js语句,一次执行)
- 应用场景:把json字符串转化为json对象。
js有哪些内置对象?
- Object,Array
- Boolean,Number,String
- Math,Date,Function,RegExp,Error,Argument,Global
js延迟加载的方式有哪些?
延迟javascript代码的加载是为了加快网页的访问速度
1.把延迟脚本放在页面底部(body标签里):如果把script标签放在head中,那么js加载完后才会加载页面,因为js会阻塞后面的代码的运行。这时候可以放在页面的底部,文档会按照从上到下的顺序加载。
2.动态创建DOM的方式:在文档都加载完后,创建script标签,插入到DOM中
//这些代码应被放置在</body>标签前(接近HTML文件底部) <script type="text/javascript"> function downloadJSAtOnload() { var element = document.createElement("script"); element.src = "defer.js"; document.body.appendChild(element); } if (window.addEventListener) window.addEventListener("load", downloadJSAtOnload, false); else if (window.attachEvent) window.attachEvent("onload", downloadJSAtOnload); else window.onload = downloadJSAtOnload; </script>
3.defer:在script标签里设置这个属性,脚本会被延迟到整个页面都解析完毕后再运行,就是相当于告诉浏览器立即下载但延迟执行。
4.async:它的作用和defer类似,但是不能控制加载的顺序。
<script src="" async="true"/>
5.使用在文档加载完后使用setTimeout()方法延迟加载js:
window.οnlοad=function(){ setTimeout(function(){ var head=document.getElementsByTagName("head")[0]; var script=document.createElement("script"); script.src="defer.js"; head.appendChild("script") },1000) }
6、使用jQuery的$.getScript( "src",callback )方法
$.getScript("defer.js",function(){
console.log("回调函数执行");
})
什么是 “use strict”; ? 使用它的好处和坏处分别是什么?
它是JavaScript另外的一种运行模式,在这种模式下,JavaScript在更严格的条件下执行。
好处:
- 消除JavaScript一些不合理不严谨之处,消除一些怪异行为。
- 保证代码安全运行
- 提高编译器效率,增加运行速度。
- 为未来版本的JavaScript做好铺垫。
坏处:
现在网站的js都会进行压缩,一些文件用了严格模式,一些文件没有,压缩后本来是严格模式的文件,不仅没有指示严格模式,反而在压缩后浪费了字节。(可以写在立即执行函数当中)
说说严格模式的限制
- 变量必须先声明后使用
- 函数的参数不能有同名属性,否则报错
- 对象不能有同名的属性
- 不能对只读属性赋值
- 不能删除不可删除的属性
- eval和arguments不能被重新赋值
- arguments不会自动追踪函数参数的变化,传进来是几就是几
- 不能使用arguments.callee和arguments.caller
- 禁止设置原始类型的属性
- 禁止八进制表示法
- 新增保留字,不能讲保留字作为变量名 let const static private public yield package
JavaScript 运行机制详解
写一个链式调用;
链式调用就是一行代码就实现了对一个或多个节点的两个或两个以上的操作。比如jquery里面就实现了链式操作:对一个节点进行多次的操作
实现链式操作的核心思想是在每个对象的方法里面都返回这个对象:
/*创建对象的方式:组合使用构造函数模式和原型模式:构造函数模式定义属性, 原型模式定义对象的方法,用原型模式可以实现所有对象的实例共享它的方法, 这样可以最大限度的节省内存*/ function Base(){ // 把返回的节点保存在一个数组里头 this.elements=[]; /*获取id*/ this.getId=function(id){ //获取到对象后放在数组里面 this.elements.push(document.getElementById(id)); //在对象的方法中返回这个对象 return this; }; this.getClass=function(className){ this.elements.push(document.getElementsByClassName(className)); return this; }; this.getTag=function(tag){ this.elements.push(document.getElementsByTagName(tag)); return this; }; this.getName=function(name){ this.elements.push(document.getElementsByName(name)); return this; }; } //给原型对象添加方法,所有实例共享这些方法 Base.prototype.css=function(attr,value){ for (var i = 0; i < this.elements.length; i++) { this.elements[i].style[attr]=value; } return this; } Base.prototype.html=function(str){ for (var i = 0; i < this.elements.length; i++) { this.elements[i].innerHTML=str; } return this; } Base.prototype.click=function(fn){ for (var i = 0; i < this.elements.length; i++) { this.elements[i].οnclick=fn; } return this; } //避免在前台new一个对象 var $=function(){ return new Base(); }
//在前台就可以使用库当中的代码了 window.οnlοad=function(){ console.log($().getId("id").css("color","red").html("hello world")); }
了解设计模式吗(我说了单例和观察者模式,并写了下代码,介绍有啥作用)
js异步的方法(promise,generator,async)
在浏览器端,异步编程非常重要,耗时很长的操作都应该异步执行,避免浏览器失去响应。
在ES6之前,异步编程的方法大概有以下几种
回调函数:将回调函数作为异步函数的参数传入,相当于先执行程序的主要逻辑,将耗时的操作推迟执行,这种方法不利于代码的维护,代码高度耦合
发布订阅模式:假设存在一个信号中心,某个任务执行完成后向信号中心发布一个信号,其他任务可以向信号中心订阅这个信号,从而知道自己什么时候可以执行,这样去除了代码之间的耦合,而且我们可以通过查看消息中心可以知道有多少个信号,每个信号有多少个订阅者
这个模式有多种实现,我们可以用jquery的插件
Promises对象是CommonJS工作组提出的一种规范,目的是为异步编程提供统一接口,使得控制异步操作更加的容易。promise优点在于避免层层嵌套的回调函数,回调函数变成了链式写法,程序的流程可以看得很清楚。而且如果一个任务已经完成,再添加回调函数,该回调函数会立即执行。所以,你不用担心是否错过了某个事件或信号。
generator函数:多个线程相互合作,完成异步任务
async函数:generator函数的改进
类型,值和变量
判断类型的方法
- 原始类型使用typeof操作符(string,number,undefined,object,boolean,function,symbol)
- 引用类型使用 x instanceof class(Array,Object)
- 还有所以类型通用的Object.prototypr.toString.call(o) //String,Number,Boolean,Object,Array,Null,Undefined,Function
javascript的typeof返回哪些数据类型?
返回字符串:string,number,undefined,object,boolean,function,symbol
例举3种强制类型转换和2种隐式类型转换?
强制:有三个函数可以将非数值转化为数值:parseInt,parseFloat,(将字符串转化为数值)number(适用于任何数据类型)
隐式:==
null和undefined的区别?
null是一个表示"无"的对象,转为数值时为0;undefined是一个表示"无"的原始值,转为数值时为NaN。
当声明的变量还未被初始化时,变量的默认值为undefined。null用来表示尚未存在的对象,常用来表示函数企图返回一个不存在的对象。
undefined表示"缺少值",就是此处应该有一个值,但是还没有定义。典型用法是:
- 变量被声明了,但没有赋值时,就等于undefined。
- 调用函数时,应该提供的参数没有提供,该参数等于undefined。
- 对象没有赋值的属性,该属性的值为undefined。
- 函数没有返回值时,默认返回undefined。
null表示"没有对象",即该处不应该有值。典型用法是:
- 作为函数的参数,表示该函数的参数不是对象。
- 作为对象原型链的终点。
JavaScript中的变量声明提升?
在一个函数体内,无论在哪声明的变量,都会被提升到函数的顶部,再依次从上到下执行和赋值。
数组
数组方法有哪些?
能改变原数组的:
-
- pop() 返回被删除的最后一个元素
- push(item1,item2) 在后面添加元素,返回新的长度
- shift() 返回被删除的第一个元素
- unshift(item1,item2) 在前面添加元素,返回新的长度
- sort(function(a,b){return b-a(倒序)|a-b(升序)})排序,字母按照开头字母顺序,如果排列数字大写必须写比较函数否则有bug
- reverse() 颠倒顺序
- splice(index,howmany,newitem1,newitem2(加到被删除的位置))返回被删除元素组成的数组
不能改变原数组的
-
- slice(start,end)返回数组中的成员数组,包括end
- concat(newarr)返回连接后的新数组
- join(str)把数组值用指定字符串连起来,如果没有就默认是逗号
- toString()把数组中的每一项用逗号连接起来转化为字符串(和没参数的join一样)
ES5中的数组方法:
-
- arr.forEach(function(e,index,arr){}):给每个元素调用指定的函数,不能中止遍历
- arr.map(function(e,index,arr){return e*e}):每个元素调用函数,有返回值,返回新的数组,不改变原数组,会处理稀疏数组,返回稀疏
- arr.filter(function(e){return e<3})返回满足条件的子数组,不会处理稀疏数组
- arr.every(function(e){return e<3}),看数组所有元素是否满足某条件,返回T/F
- arr.some(function(e){return e<3}),判断数组的某些元素是否满足某条件,返回T/F
- arr.reduce(function(x,y){return x+y},0(初始值)):用指定的函数组合数组元素,返回单个值,初始值不提供的话将数组第一个和第二个作为函数的参数
数组遍历:
- 常规for循环(按照顺序,会处理稀疏数组不存在的元素,也会处理null和undefined)
- for-in语句(不一定按顺序,不会处理稀疏数组不存在的元素,保证兼容性使用前判断null或者undefined)
- forEach()
写出2个以上数组去重的方法:
1.创建一个新的数组存放结果,遍历数组元素,判断新数组在是否存在该元素,不存在就存入
function delSame(arr) { var result = []; var len = arr.length; for (var i = 0; i < len; i++) { if (result.indexOf(arr[i]) == -1) { result.push(arr[i]) }; }; return result; }
2.先将原数组排序,创建新数组并将第一个元素存入新数组,从第二项遍历数组元素,判断每一项和新数组最后一项是否相同,不相同存入该数组
function delSame2(arr) { var arr=arr.sort(); var result=[arr[0]]; var len = arr.length; for (var i = 1; i < len; i++) { if (arr[i]!==result[result.length-1]) { result.push(arr[i]) }; }; return result; }
3,创建一个新的结果数组和空对象,遍历数组元素,判断对象中属性为数组元素的值是否为空,如果为空,将元素存入结果数组,并将对象的属性赋值为1
function delSame3(arr) { var result=[]; var obj={}; var len=arr.length; for (var i = 0; i < len; i++) { var key=arr[i]; if (!obj[key]) { result.push(arr[i]); obj[key]=1; }; }; return result; }
快速排序的思想并实现一个快排?
function quickSort(arr){ if(arr.length<=1){ return arr;//如果数组只有一个数,就直接返回; } var num = Math.floor(arr.length/2);//找到中间数的索引值,如果是浮点数,则向下取整 var numValue = arr.splice(num,1);//找到中间数的值,并从原数组删除 var left = []; var right = []; for(var i=0;i<arr.length;i++){ if(arr[i]<numValue){ left.push(arr[i]);//基准点的左边的数传到左边数组 } else{ right.push(arr[i]);//基准点的右边的数传到右边数组 } } return arguments.callee(left).concat(numValue,arguments.callee(right));//递归不断重复比较 } alert(quickSort([32,45,37,16,2,87]));//弹出“2,16,32,37,45,87”
判断数组的方法:
- Array.isArray([]) //true
- [] instanceof Array //ture(但这个方法在多个窗口中有可能会造成混淆,因为一个窗口中的对象有可能不是另一个窗体中的构造函数的实例)
- Object.prototype.toString.call(arr)=='[object Array]' //检查对象的类属性(最通用的)
函数
Javascript垃圾回收方法?
- 标记清除:这是所有浏览器最常用的一种垃圾回收方式,当变量进入环境(在函数在声明一个变量)时,将其标记为“进入环境”,当变量离开环境(函数执行结束)时,将其标记为离开环境。垃圾收集器会按照固定的时间间隔周期性的释放内存。
- 引用计数:当声明了一个变量并将一个引用类型的值赋给该变量时这个值得引用次数+1,当去掉这个引用时,引用次数-1,当引用次数为0时表明可将其内存回收
内存泄漏是什么?
- 内存泄漏指任何对象在您不再拥有或需要它之后仍然存在。
- 在低版本的IE中经常会出现内存泄漏,是因为IE中DOM/BOM对象都是通过引用计数回收的,因为存在循环引用的问题,所以他们的引用次数永远不会为0,假如这个函数被重复多次调用,就会导致内存泄漏(大量内存得不到回收)
- 解决办法:要想破坏循环引用,引用
DOM元素的对象或DOM对象的引用需要被赋值为null。
哪些操作会造成内存泄漏?
- 闭包:闭包中的变量不会被垃圾回收机制回收。
- setTimeout 的第一个参数使用字符串而非函数的话,会引发内存泄漏。
- 循环引用:循环(在IE中两个DOM/BOM对象彼此引用时,就会产生一个循环)
谈谈This对象的理解。
this总是指函数运行时所在的对象。在不同的场景中,this的身份不同:
-
- DOM的事件处理函数中,this指触发这个事件的DOM对象;
- 全局函数调用中,this指window;
- 作为对象的方法调用时,this指调用这个函数的那个对象;
- 用new实例化对象,作为构造函数调用时,this指新创建的那个对象
ES6中,箭头函数当中的this指的的是定义时所在的对象而不是使用时所在的对象。这样我们在使用的时候就不会产生很多歧义了。
JavaScript有块作用域吗?
没有。在JavaScript中,if/for语句中初始化变量的表达式中所定义的变量,在循环结束后也依旧会存在于循环外部的执行环境当中。
JavaScript的作用域和作用域链?
- 作用域:只有函数才会产生作用域的概念,它指变量的作用范围,内部作用域由局部变量,函数,形参,实参组成
- 作用域链:保证执行环境中有权访问的变量和函数是有序的,作用域链的变量只能向上访问,变量访问到window对象终止,变量作用域链向下访问变量时不允许的。
说说函数表达式和函数声明的区别
- 执行代码时,JavaScript引擎在第一遍会声明函数并将它们提升到顶部。所以函数声明语句可以它定义之前出现的代码所调用。
- 函数表达式定义的函数,是将其赋值给一个变量,虽然变量的声明提前了,但给变量赋值是不会提前的,因此调用这个函数之前必须先定义才行。
函数声明提升:
执行代码时,JavaScript引擎在第一遍会声明函数并将它们提升到顶部。函数声明语句可以它定义之前出现的代码所调用。
js中上下文是什么,js有哪些函数能改变上下文
- 上下文就是this关键字的值,比如当函数作为对象的方法来调用时,该对象就是此次调用的上下文,也就是该函数的this值;当函数作为全局函数调用时,上下文指的时window。
- 作用域和上下文之间最大的区别是: 上下文在运行时确定,随时可能改变;作用域在定义时确定,永远不会改变。
- JavaScript中call和apply可以改变上下文
call和apply的区别和作用?
区别:
- call()的第一个参数是上下文,第二个参数是参数序列
- apply()的第一个参数是上下文,第二个参数是参数组成的数组
作用:改变函数的上下文,它是以某个对象的方法来调用函数,函数的this指的是第一个参数。如果没有传递参数是null/undefined,this指window
f.call(o) //以对象o的方法来调用函数f 代码的功能: o.m=f; //将f存储为o的临时方法 o.m(); //调用它,没有参数 delete o.m //将临时方法删除
谈谈你对闭包的理解,为什么使用闭包,使用场景,它会有什么影响?
- 闭包:就是访问函数内部变量的函数,创建闭包的方式就是函数嵌套函数
- 作用:当在函数内部嵌套一个函数时,就创建了闭包,闭包可以访问它被定义时所处的作用域中的任何变量,并且参数和变量不会被垃圾回收机制回收。闭包还可以避免全局变量的污染。
- 使用场景:在大型项目当中,为了防止命名冲突,一般会把相应的代码用闭包的形式包裹起来,避免暴露在全局作用域下
- 缺点:如果闭包引用外部变量,变量会常驻内存,这样会增大内存使用量,从而降低性能,使用不当很容易造成内存泄露。
手写一个闭包
function fn(){
var n=0;
function fn1(){
n++;
console.log(n);
}
return fn1;
}
var foo=fn(); foo(); //1 foo(); //2 foo(); //3
new操作符具体做了什么?
- 创建了一个空对象,并且this变量引用该对象,同时继承了该函数的原型
- 属性和方法加入到this引用的对象
- 新创建的对象由this引用,并且最后隐式的返回this
var o={};
o.__proto__=Base.prototype;
Base.call(o);
给你一个空函数,加new和不加new的区别
- 加new时,会把这个函数当作是一个构造函数,返回一个对象。
- 不加new时,就是调用一个普通的函数,结果视函数返回值而定。
for函数里面setTimeout异步问题
setTimeout()是将一段代码延迟一定时间并异步执行。比如想要在for循环里面使变量i每隔1秒输出,如果这样写:
for (var i = 1; i <= 2; i++) { setTimeout(function() { alert(i) }, 1000); }
结果是两次都弹出了3。因为setTimeout是异步的,那么在调用它之前,其实3次循环都已经结束了。每个定时器处理函数就会共享同一作用域里的同一变量"i"。怎么样才能达到预期效果?你要为每个定时器处理函数创建不同的“i”变量副本。
在函数内创建一个立即执行函数,函数引用了变量i,作为实参将其传递给形参,从而创建了变量的值的副本。由于setTimeout()是在该副本的上下文中调用的,所以它每次都有自己的私有的"i"以供使用。
for (var i = 1; i <= 2; i++) { (function(i) { setTimeout(function() { alert(i) }, 1000); })(i); }
对象
定义不可修改属性?
Object.defineProperty(obj,propertyName,{ writable:false, //表示能否修改属性的值,默认是true configurable:false, //表示不能从对象中删除属性,默认是true value:"valueOfProperty", //属性的值,默认是undefined Enumerable:"true" //能够通过for-in循环 ,默认是true })
对象属性的遍历
1.for-in循环可以遍历对象所有 可枚举的(对象继承的方法不可枚举) ,包括自有的和继承的属性。
var o = { name: "lifurong", age: 24 } for (var key in o) { console.log(o[key]) };
//lifurong
//24
2、Object.keys()方法
返回一个由对象中可枚举的自有的属性组成的数组。
3、Object.getOwnPropertyNames()
返回一个由对象中所有的(包括不可枚举的)自有属性组成的数组。
Javascript中,有一个函数,执行时对象查找时,永远不会去查找原型,这个函数是?
obj.hasOwnProperty(propertyName);这个方法返回一个布尔值。用来检测一个属性是存在于实例中还是存在于原型中。
object和array的区别
数组表示带有编号的有序数据的集合,而对象表示无序数据的集合。如果数据的顺序很重要,就用数组,否则就用对象。
如何判断对象的类型
- 用instanceof操作符来测试实例与原型链中出现的构造函数:b1 instanceof Box //true
- 使用原型的isPrototypeOf()方法:Box.prototype.isPrototypeOf(b1) //true
instanceof原理
instanceof操作符是来测试实例与原型链中出现的构造函数。如果实例的原型链中有这个构造函数,返回true.
对象中key-value的value怎么再放一个对象。
通过对象字面量的方法
var book={ edition:2, author:{ firstname:"David", lastname:"li" } }
静态属性怎么继承?
静态属性:无需实例化就可以调用的方法就叫静态方法
静态属性不能被继承
function Father() { //公有属性 this.lastname = "li"; //私有属性 var mood="good"; } //静态属性 Father.staticPro="staticPro"; function Child() { this.age = 20; } Child.prototype = new Father();
正则:
匹配模式:i (忽略大小写),g(全局:匹配所有字符串,而不是发现第一个就停止),m(多行模式:忽略文本的末尾)
regexp的方法:
- test() : pattern.test(str) 返回T/F
- exec(): pattern.exec(str) 返回数组,第一个是匹配的字符串,后面都是括号里的子表达式的字符串
字符串方法:
- search(pattern):返回第一个匹配字符串的起始位置
- replace(pattern,str/fn):先找,然后替换,如果有g替换所以匹配字符串,没有就替换第一个匹配的,函数可以动态改变字符串(不改变原字符串)
- match(pattern):返回数组,如果有g返回所有匹配结果,如果没有数组第一个是字符串,剩下都是括号里的子表达式
常用的正则:
- \s空格,\d数字,\w(字母和数字),[^..]不在里面的任意字符,+ 一个或多个,* 0个或多个, ?0或1个,{n}n个,{n,m} n<=x个<m
- 字符类:中括号匹配一个所包含的任意字符 比如[ab]就是a或b,比如[3457]匹配3或者4或者5或者7,而(3457)只匹配3457
检验网址的正则:
var str="visit my personal information at http://www.t1amo.com/about.html"
var pattern=/(\w+):\/\/([\w.]+)\/(\S*)/
var result=str.match(pattern);
result[0] // http://www.t1amo.com/about.html
result[1] //http 协议
result[2] //www.t1amo.com域名
result[3] //about.html路径
怎么去除字符串前后的空格:
var str=" hello world ";
- str.replace(/^\s+|\s+$/,'') //"hello world"
- str.trim()
手机号码正则:手机号1开头,第二位是[3,4,5,7,8],再后面9位(总共11位)
function checkPhone(){ var phone = document.getElementById('phone').value; if(!(/^1[34578]\d{9}$/.test(phone))){ alert("手机号码有误,请重填"); return false; } }
客户端存储
浏览器本地存储?
- 在较高版本的浏览器中,js提供了sessionstorage和globalstorage
- 在HTML5中,提供了localstorage来取代globalstorage
sessionStorage:用于存储一个会话中的数据,这些数据只有在同一个标签页或窗口中才可以访问,并且浏览器关闭后数据自动删除。
localStorage:用于持久化的本地存储数据。浏览器关闭后数据不丢失除非主动删除数据;
区别:
- 两者都有同源限制:不同站点无法读取对方存储的数据
- localstorage同一站点的不同页面可以共享数据,而sessionStorage不可以。
web storage和cookie的区别?Cookie、sessionStorage 和 localStrorage?
它们都是为了实现本地存储而设计的。
- 存储空间:cookie数据大小不能超过4K,webstorage虽然也有存储大小的限制,但是比cookie大得多,有5M
- 数据是否传递:cookie是每请求一个页面都会发送到服务器,webstorage仅用于本地存储数据,不会与服务器进行交互。
- 数据有效时间:cookie在过期时间一直有效,即使窗口和浏览器关闭。localstorage存储持久数据,浏览器关闭后数据不丢失除非主动删除数据;sessionstorage数据在当前浏览器窗口关闭后自动删除。
- Web Storage拥有setItem,getItem,removeItem,clear等方法,不像cookie需要前端开发者自己封装setCookie,getCookie
为什么选择Web Storage而不是Cookie?
Web Storage拥有setItem,getItem,removeItem,clear等方法,不像cookie需要前端开发者自己封装setCookie,getCookie,在不支持web存储的浏览器中,可以使用cookie和IE userData来解决兼容性
/*识别出是哪类存储机制*/ var memory=window.localStorage|| (window.UserDataStorage&& new UserDataStorage())|| new cookieStorage(); /*然后在对应的机制中查询数据*/ var value=memory.getItem("name");
cookie 和session 的区别?
- cookie的数据存放在浏览器上,session的数据存放在服务器上
- cookie不是很安全,别人会分析本地cookie而进行cookie欺骗,因此考虑到安全性应该使用session。
- session的数据在一定时间内会存放在服务器上,当访问增多,会影响服务器性能,因此考虑到服务器性能应该使用cookie。
- 单个cookie保存的数据不能超过4k,很多浏览器都限制一个站点最多保存20个cookie。
所以一般来说,将重要信息存放在session,不重要的需要保存的数据存放在cookie。
请你谈谈Cookie的弊端?
cookie虽然在持久保存客户端数据提供了方便,减轻了服务器的负担,但是还有很多局限性:
缺点:
- 数量和长度的限制:单个cookie保存的数据不能超过4k(1024*4=4096字节,为了兼容性一般不能超过4095kb),很多浏览器都限制一个站点最多保存20个cookie。
- 安全性问题:如果cookie被人拦截了,那么他将获得所有的session信息
- 有些状态不能保存在客户端。比如为了防止重复提交表单,需要在服务器端保存一个计数器。如果放在客户端不会起作用。
优点:极高的扩展性和可用性
使用cookie需要注意的问题:
- 可以通过良好的编程来控制保存在cookie中的session对象的大小
- 通过加密和安全传输技术减小cookie被破解的可能性
- 不在cookie中存放重要信息。
- 控制cookie的有效期,偷盗者可能拿到一个过期的cookie
cookie的读取,set,以及删除?
- cookie有名值对组成,以分号和空格隔开。document.cookie="name=value; max-age=xx; path=xx; "
- cookie的名值对不允许包含分号,逗号和空白符,要采用全局函数encodeURIComponent()对值进行编码,读取的时候用dncodeURIComponent()解码
cookie属性:有效期和作用域
- 有效期:cookie的默认有效期很短,一旦浏览器关闭,数据丢失,如果想延长cookie的有效期,可以通过设置cookie的max-age属性(单位是s)
- 作用域:cookie的作用域是通过文档源和文档路径确定的,可以通过path和domain属性来配置。cookie是对创建cookie的那个web页面和该web页面同目录或者同目录的子目录是可见的。对其他目录的页面是不可见的。
1、cookie设置
function setCookie(name,value,daystoLive,path,domain,secure){ var cookie=name+"="+encodeURIComponent(value); if (typeof daystoLive === "number") cookie+="; max-age="+(daystoLive*24*60*60); if (path) cookie+="; ="+path; if (domain) cookie+="; domain="+domain; document.cookie=cookie; }
2、cookie的获取:
function getCookie(){ var cookie={}; var all=document.cookie; if (all===null) return cookie; var list=all.split("; "); for (var i = 0; i < list.length; i++) { var p=list[i].indexOf("="); var name=list[i].substring(0,p); var value=list[i].substring(p+1); value=decodeURIComponent(value); cookie[name]=value; } return cookie;//返回的是对象的方式 }
3、cookie删除:
function delCookie(name,path,domain,secure){ //必须要设置成相同的域和路径才可以 var cval=getCookie().name; if (cval!=null) { document.cookie=name+"="+cval+ "; max-age=0"; }; }
如何实现浏览器内多个标签页之间的通信?
调用localStorage,cookie等本地存储方式
localstorage怎么使用
localStorage仅仅支持存储字符串类型的数据,它和JavaScript对象的使用没什么区别。需要注意的是,当存储一个数字时,会把它自动转化成字符串。当获取该值时应该使用parseInt()转换成数字类型
localStorage.x=10;
var x=parseInt(localStorage.x);
localStorage具有setItem("name","value")方法和getItem("name")方法。分别实现数据存储和获取数据,调用removeItem("name")方法可以删除数据。
localStorage.setItem("x",10);
localStorage.getItem("x"); //"10"
localStorage.removeItem("x")
调用clear()方法可以删除所有存储的数据。
使用length属性和key()方法,枚举存入数据的名字;
for (var i = 1; i < localStorage.length; i++) { var name=localStorage.key(i); console.log(name); var value=localStorage.getItem(name); console.log(value); };
如何保持登录状态?
- 把登录信息如账号、密码等保存在Cookie中,并控制Cookie的有效期,下次访问时再验证Cookie中的登录信息即可。
- 保存登录信息有多种方案。最直接的是把用户名与密码都保持到Cookie中,下次访问时检查Cookie中的用户名与密码,与数据库比较。这是一种比较危险的选择,一般不把密码等重要信息保存到Cookie中。
- 还有一种方案是把密码加密后保存到Cookie中,下次访问时解密并与数据库比较。这种方案略微安全一些。如果不希望保存密码,还可以把登录的时间戳保存到Cookie与数据库中,到时只验证用户名与登录时间戳就可以了。
如果页面初始载入的时候把ajax请求返回的数据存在localStorage里面,然后每次调用的时候去localStorage里面取数,是否可行。
- 不能保证数据的实时性,请求和实时性必然会有一方有所牺牲
前端路由的实现原理
大型框架例如Angular的路由就是通过hash实现的。一个url里的#号叫hash,也就是所谓的锚点。当我们点击一个a标签时,将href属性设置为相应的path,就可以在不用更新网页情况下局部的刷新页面。
hash的运行机制是:
- 将路由更新时需要执行的回调函数存储在对象中。
- 点击a标签触发hash改变
- 监听浏览器的hashchange事件,执行当前url对应的回调函数,利用DOM操作更新页面。
具体的代码如下:
<ul>
<li><a href="#/">首页</a></li>
<li><a href="#/product">产品页</a></li>
<li><a href="#/service">服务页</a></li>
</ul>
<div id="refreshBox"></div>
<script type="text/javascript">
function Route() {
/*存储hash更新时的回调函数到routes里*/
this.routes = {};
this.curUrl = "";
/*存储路由更新时的回调到routes中*/
this.route = function(path, callback) {
this.routes[path] = callback;
}
/*执行当前的回调函数更新页面*/
this.refresh = function() {
this.curUrl = location.hash.slice(1) || '/'; //获取当前hash
this.routes[this.curUrl](); //根据对应的hash执行回调函数
}
//监听浏览器 url hash 更新事件。
this.init = function() {
window.addEventListener("load", this.refresh.bind(this), false);
window.addEventListener("hashchange", this.refresh.bind(this), false);
}
}
var box = document.getElementById('refreshBox');
var R = new Route();
R.init();
R.route('/', function() {
box.style.background = "blue";
box.innerHTML = "这是首页";
});
R.route('/product', function() {
box.style.background = "red";
box.innerHTML = "这是产品页";
});
R.route('/service', function() {
box.style.background = "yellow";
box.innerHTML = "这是服务页";
});
</script>
如何实现跨浏览存储
跨域
说一下什么是javascript的同源策略?
它是一种安全协议。指一段脚本只能读取来自同一来源的窗口和文档的属性,同一来源指的是端口,域名,协议相同。
为什么要有同源限制?
比如一个黑客将真正的银行登录的页面嵌入到他的页面,当用户登录时它就可以通过js读取到你表单的内容。
如何解决跨域问题
1、JSONP/ Jsonp的原理。怎么去读取一个script里面的数据。
由于同源策略的限制,在js中不可以使用AJAX跨域请求,但可以在页面上引入不同域的脚本。jsonp正是利用这个特性来实现的。
JSONP又叫填充式json,它由回调函数和传入回调函数的json数据组成。
原理是动态插入script标签,通过script标签引入一个js文件,这个文件载入成功后会执行我们在url中指定的函数,并且会把服务器端输出的json数据作为参数传入。
<script type="text/javascript">
function jsonpCallback(result) {
alert(result.msg);
}
</script>
<script type="text/javascript" src="http://crossdomain.com/jsonServerResponse?jsonp=jsonpCallback"></script>
其中jsonCallback是客户端注册的,获取跨域服务器上的JSON数据后,回调的函数。http://crossdomain.com/jsonServerResponse?jsonp=jsonpCallback 这个url是跨域服务器取JSON数据的接口,参数为回调函数的名字,返回的格式为:jsonpCallback({msg:'this is json data'}) 。如此就生成了一段js语法的文档, 传回客户端就可以调用jsonpCallBack函数了.
优点:简单易用,兼容性好
缺点:
- 只支持get请求,不支持POST请求。
- 不容易调试:如果回调函数没有调入成功无法检测出具体原因
- 有可能会出现安全问题:远程服务器可能注入任何内容,所以必须确保对方安全
2、CORS(跨域资源共享)
它定义了浏览器和服务器是如何通过可控的方式来进行跨域通信的,CORS通过一些列特殊的HTTP头还实现的,通过HTTP头信息可以允许双方判断请求应该是成功还是失败。
3、通过修改document.domain来跨子域
将主域和子域的document.domain设置成同一个主域。前提条件:这两个域名必须属于同一个基础域名,而且所用的协议,端口都要一致,否则无法利用document.domain进行跨域
4、使用window.name跨域
一个窗口内所有的页面共享一个window.name属性,可以读写。
5、使用HTML5提供的window.postMessage()来跨域传递数据。IE8+都支持
个人认为window.name方法既不复杂也能兼容几乎所有浏览器,所以比较好用。
iframe实现跨越的具体方法?
应用页面创建iframe,src指向数据页面;数据页面把数据附加到window.name上;应用界面监听iframe的onload事件,在此事件中设置这个iframe的src指向本地域的代理文件;获取数据后销毁iframe
AJAX
ajax的内部原理
其核心有JavaScript、XMLHTTPRequest、DOM对象组成,通过XmlHttpRequest对象来向服务器发异步请求,从服务器获得数据,然后用JavaScript来操作DOM而更新页面。
创建ajax过程
- 创建一个新的xhr对象
- 使用open方法创建一个新的HTTP请求,包含了请求的方法(GET/POST),URL,是否异步
- 创建一个响应http请求变化的函数onreadystatechange函数,每当 readyState 属性改变时,就会调用该函数。当 readyState 等于 4 且http状态status为 200 时,表示响应已就绪
- 使用send方法发送http请求。
- 获取异步调用返回的数据, 它是xhr对象的 responseText 或 responseXML 属性
- 使用JavaScript和DOM局部刷新页面
readyState几个状态的含义
存有 XMLHttpRequest 的状态。从 0 到 4 发生变化。
- 0:请求未初始化
- 1:服务器连接已建立
- 2:请求已接收
- 3:请求处理中
- 4:请求已完成,且响应已就绪
原生jquery的ajax实现,具体思路
原生:
//首先检查浏览器是否支持XMLHttpRequest对象。 var xhr; if (window.XMLHttpRequest) { xhr = new XMLHttpRequest(); } else { xhr = new ActiveXObject("Microsoft.XMLHTTP") }; var xhr = new XMLHttpRequest(); //可以向URL添加需要发送的数据 //为了避免得到缓存的结果可以向URL添加一个唯一的id //xhr.open("GET","demo_get.asp?t=" + Math.random(),true); xhr.open("GET", "test.php?key1=value1&key2=value2", true); xhr.onreadystatechange = function() { if (xhr.readyState === 4 && xhr.status === 200) { var result = xhr.responseText; }; } xhr.send();
jquery:
$.ajax()是最底层的AJAX实现。它包含一个对象参数,以键值对的方式提供该方法的请求设置和回调函数。
$.ajax({ /*发送请求的地址*/ url: "url", /*请求的方式*/ type: "POST/GET", /*是否异步*/ async: true, 发送到服务器的数据 data: { name: "furong", age: 20 }, /*服务器返回数据类型*/ dataType: "json/html/xml/text/jsonp/script", /*请求成功后的回调函数*/ success: function(data, status, xhr) { //..callback }, /*请求失败时的回调函数*/ error: function() { //error } });
同步和异步的区别
同步:js代码加载到当前AJAX的时候,页面里所有的代码都会停止加载,当AJAX执行完毕后才会执行ajax后面的代码,页面会出现假死状态。
异步:当ajax发送请求,等待服务器端返回数据的这个过程当中,前台会继续执行ajax后面的代码,也就是说这时候是两个线程(ajax发送的线程和ajax块后的线程)
ie各版本和chrome可以并行下载多少个资源
IE6 两个并发,iE7升级之后的6个并发,之后版本也是6个 Firefox,chrome也是6个
ajax的优缺点和在IE下的问题?
优点:
- 不需要插件支持,可以被大多数浏览器支持
- 能在不刷新整个页面的前提下更新数据,提升用户体验
- A减轻服务器和带宽的负担
缺点:
- 不支持后退按钮
- 对搜索引擎不友好
- 开发和调试工具匮乏
- 安全问题,AJAX暴露了与服务器交互的细节。
IE缓存问题:在IE下,如果是GET请求,并且URL不变,这个结果会被缓存
解决办法:可以向URL添加一个唯一的id
xhr.open("GET","demo_get.asp?t=" + Math.random(),true);
ajax请求的时候get 和post方式的区别?
- GET从服务器获取数据,POST向服务器发送数据
- GET使用url传递参数,对传递数据的类型(ASCII编码)和长度(2kb)有限制,POST没有限制。
- GET安全性较差,因为发送的数据在url中,是可见的。POST更加安全,因为它是通过http post机制传值,是不可见的。
什么情况下分别使用GET和POST?
POST:
- 无法使用缓存文件(更新服务器上的文件或数据库)
- 向服务器发送大量数据(POST 没有数据量限制)
- 发送包含未知字符的用户输入时,POST 比 GET 更稳定也更可靠
GET:
- 请求是为了查找资源,HTML表单数据仅用来帮助搜索。
- 请求的数据不超过2kb
Post一个file的时候file放在哪的?
请求实体
ajax请求时,如何解释json数据
原生js的AJAX:
- eval( '('+jsonstr+')' ) :这种方法不推荐,这种方法解析的时候不会去判断字符串是否合法,而且json对象中的js方法也会被执行,这是非常危险的。
- JSON.parse(jsonstr):解析JSON格式的字符串,返回一个js值,如果字符串不合法会报错。
Jquery的AJAX:
jquery异步请求将type设为“json”,如果不添加该条属性,则返回来的为字符串。或者利用$.getJSON()方法获得服务器返回json数据,这时候返回的就是json对象了
$.each()是用来在回调函数中解析JSON数据的方法
$.each( collection, callback(indexInArray, valueOfElement) )
success : function(data) { $.each(data.list,function(index,item){ alert(item.id); }) }
多个ajax怎么处理
Ajax 同时处理多个异步请求,可能出现这样的错误:只有最后一个异步请求有效,其他的都没效果。所以当我们执行完一次异步请求就应该把这次创建出来的 XMLHttpRequest 对象删除,然后再执行下一次异步请求。删除使用 delete 即可:delete xhr;
<body>
<p>Input1:<input type="text" id="first" /> <span id="firstSpan"></span></p>
<p>Input2:<input type="text" id="second" /> <span id="secondSpan"></span></p>
<p>Input3:<input type="text" id="three" /> <span id="threeSpan"></span></p>
<p><input type="button" value="发送" οnclick="test();" /></p>
</body>
</html>
<script language="javascript">
function getData(url, input, label) {
var xhr;
if (window.ActiveXObject) {
xhr = new ActiveXObject('Microsoft.XMLHTTP');
} else if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
}
var val = document.getElementById(input).value;
var realUrl = url + "?time=" + new Date().getTime() + "&text=" + val;
//GET请求查询字符串必须进行编码。而且所有的键值对必须&分割
realUrl = encodeURI(encodeURI(realUrl));
xhr.onreadystatechange = function() {
if (xhr.readyState==4 && xmlHttp.status==200) {
var labelSpan = document.getElementById(label);
labelSpan.innerHTML = decodeURI(xhr.responseText);
delete xhr; // 手动删除
xhr = null
}
}
xmlHttp.open('GET', realUrl);
xmlHttp.send(null);
}
function test() {
getData('index.php', 'first', 'firstSpan');
getData('index.php', 'second', 'secondSpan');
getData('index.php', 'three', 'threeSpan');
}
</script>
<?php header('Content-Type:text/html;Charset=utf-8'); echo $_GET['text']; ?>
JSON
JSON 的了解?
- JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。
- 它是基于JavaScript的一个子集。数据格式简单, 易于读写, 占用带宽小,是前后台数据交互最常见的一种形式。
- 格式采用键值对的方式,{'age':'12', 'name':'back'}
XML和JSON的区别?
- 数据体积方面:json比xml数据体积小
- 数据交互方面:json与JavaScript的交互更加方便,更容易解析处理
- 数据描述方面:json比xml要差
- 传输速度方面:json比xml快的多
JSON字符串转换为JSON对象(互转)
- eval( '('+jsonstr+')' ) :这种方法不推荐,该方法解析的时候不会去判断字符串是否合法。eval会执行json串中的表达式, 这种方式不安全
- JSON.parse(jsonstr):解析JSON格式的字符串,返回一个js值,如果字符串不合法会报错。
- jQuery支持的转换方式:$.parseJSON( jsonstr );
- JSON.stringify(jsonobj); //可以将json对象转换成json字符串
浏览器、http
一个页面从输入 URL 到页面加载显示完成,这个过程中都发生了什么?(流程说的越详细越好)
- 用户发送一个url请求
- 浏览器通过DNS获取网站的IP地址:客户端先检查本地是否有对应的IP地址,若找到则返回,若没有则请求上级DNS服务器,直到找到或找到根节点。
- 浏览器和服务器通过TCP三次握手来建立TCP连接。
- 一旦连接建立,浏览器会通过该连接向服务器端发送HTTP请求
- 远程服务器找到资源并返回响应报文,响应报文中包含状态码。(200表示请求成功)
- 请求成功后服务器返回相应的资源,客户端下载资源
- 释放TCP连接。
- 接下来就是页面渲染阶段了。首先解析HTML生成DOM树,再解析CSS文件生产渲染树。 javascript又可以根据 DOM API 操作 DOM
说说TCP传输的三次握手四次挥手策略
1、三次握手:为了将数据准确无误的送达目标处,TCP协议采用三次握手策略。
三次握手的过程是:
- 发送端先发送一个带有SYN标志的数据包给接收端
- 接收端收到数据包后,传回一个带有SYN/ACK标志的数据包以示传达确认信息
- 发送端再发送一个带有ACK表示的数据包以示握手成功。
在这个过程当中,如果发送方在规定的延迟时间内没有收到回复则默认接收方没有收到请求,TCP协议会再次发送数据包。直到收到回复为止。
2、断开一个TCP连接需要四次握手:
- 主动关闭方发送一个FIN,用来关闭主动方到被动方的数据传送。(但是在fin包之前发送出去的数据,如果没有收到ack确认报文,主动关闭方还是会再次发送这些数据。此时主动关闭方还可以接受数据)
- 被动关闭方收到fin包后,发送一个ack给对方。确认序号为收到序号+1。
- 被动关闭方发送一个fin,用来关闭被动关闭方到主动关闭方的数据传送。
- 主动关闭方收到fin后,发送一个ack给对方,确认序号为收到序号+1,至此,完成四次握手。
其他 HTTP 请求方法
在请求头的第一行包含了请求的方法,它包括OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE
- GET:从指定资源请求数据
- POST:向指定的资源发送数据
- HEAD:和GET相同,但是只返回HTTP报头,不返回文档主体
- DELETE:删除指定资源
- OPTIONS:返回服务器支持的HTTP方法
- CONNECT:把请求的连接转换到透明的TCP/IP通信
- PUT:上传指定的URL表示
TCP和UDP的区别
- TCP(Transmission Control Protocol,传输控制协议):是基于连接的协议。也就是说在发送数据前,必须和对方建立可靠的连接。一个TCP连接必须通过三次握手才能建立起来。
- UDP(User Data Protocol,用户数据报协议):是于TCP相对应的协议。它是面向非连接的协议。也就是说他不与对方建立连接,而是直接把数据包发送过去。UDP适用于一次只传少量的数据、并且对可靠性要求不高的应用环境
HTTP状态码
- 200 OK 请求成功
- 201 Created 请求成功并且服务器创建了新的资源
- 202 Accepted 请求接受但尚未处理
- 301 Move Permanently 永久性重定向,请求的网页已被永久性的移到了新的位置。请求的报文中会附带重定向的URL。
- 302 Found 临时性重定向
- 304 Not Modified 自从上次请求后,请求的网页未修改过。可直接使用缓存
- 400 Bad Request 服务器无法理解请求的格式
- 401 Unauthorized 请求未授权。
- 402 Forbidden 禁止访问。
- 404 Not Found 找不到如何与 URI 相匹配的资源。
- 500 Internal Server Error 最常见的服务器端错误。
- 503 Service Unavailable 服务器端暂时无法处理请求(可能是过载或维护)。
HTTP最常见的响应头
- Allow 服务器支持哪些请求方法(如GET、POST等);
- Content-Encoding 数据的压缩格式
- Content-Length 表示内容长度
- Content-Type 数据的类型.
- Cache-controll 它是一个相对时间,表示从请求时间到过期时间的秒数。
- Date:当前的GMT时间。
- ETag:Last-Modified类似, 不过他发送的是一个字符串来标识url的版本
- Expires 它是一个绝对时间,表示在指定时间后缓存失效。-1或0则是不缓存.
- Last-Modified 当前资源的最后修改时间,客户可以通过If-Modified-Since请求头提供一个日期,只有改动时间迟于指定时间的文档才会返回,否则返回一个304状态
- Location 配合302状态码(临时性重定向)使用, 用于告诉客户找谁
- Server 服务器的类型
http请求头有哪些字段
- 请求行:请求的方法,url,http协议版本( url在请求行, cookie在请求头)
- Accept-Encoding 客户端支持的数据压缩格式
- Accept-Language 客户端的语言环境
- Connection:处理完这次请求后是否断开连接还是继续保持连接
- Cache-Control 指定请求和响应遵循的缓存机制
- pragma:no-cache表示禁用缓存,必须返回一个刷新后的文档
HTTP和HTTPS
- HTTP协议通常在TCP协议之上
- 在HTTP和TCP之间添加一个安全协议层,这个时候就成了HTTPS
- http端口号80,https是443。http更加安全
http的端口号,ftp的端口号
- HTTP默认的端口号为80
- FTP默认的端口号为21
- HTTPS默认的端口号为443
为什么HTTPS安全
- 因为网络请求需要中间有很多的服务器路由器的转发。中间的节点都可能篡改信息
- 而使用HTTPS,密钥只有在你和终点站才有。
- 之所以比较安全是因为它利用SSL/TSL协议传输,保证了数据传输过程的安全。
关于Http 2.0 你知道多少?、http1和http2的区别
- http2采用二进制格式而非文本格式
- http2使用爆头压缩,降低了开销
- 让服务器可以将响应主动推送到客户端的缓存中
- http2是完全的多路复用,非有序并阻塞的。只需要一个连接即可实现并行。
什么是Etag?应用
- 服务器使用它来判断页面是否被修改过。
- 当浏览器请求一个页面,服务器返回页面并且给页面加上一个Etag,浏览器缓存页面和Etag,再次请求该页面时将Etag发送给服务器,服务器检查Etag判断未修改,返回304和空的响应体。浏览器收到304的状态码后使用缓存文件。
web缓存,浏览器怎么知道要从缓存获取;
- 当浏览器请求一个页面,服务器返回页面并且给页面加上一个Etag,浏览器缓存页面和Etag,再次请求该页面时将Etag发送给服务器,服务器检查Etag判断未修改,返回304和空的响应体。浏览器收到304的状态码后使用缓存文件。
有没有方法不请求不经过服务器直接使用缓存。(强缓存和协商缓存的命中和管理)、浏览器缓存的区别
- 浏览器在加载资源时,首先浏览器会根据第一次请求资源时缓存的响应头里的Expires和Cache-Control信息来判断是否命中强缓存,如果命中,浏览器直接从缓存中读取资源,不会发送请求到服务器。
- 当强缓存没有命中的时候,浏览器发送一个请求到服务器。服务器根据响应头的Last-Modified和Etag信息来判断是否命中协商缓存,如果命中,服务器返回一个304的状态码和空的响应体,浏览器收到304的状态码后使用缓存文件。
- 当协商缓存没有命中的时候,浏览器直接从服务器加载资源。
Expires和Cache-Control
Expires和Cache-Control是http响应头信息,都用来表示资源在客户端缓存的有效期。浏览器强缓存就是利用它们来实现的。
Expires是较老的强缓存管理header,它是服务器返回的一个绝对时间。用GMT格式的字符串表示。它的缓存原理是:
- 当浏览器第一次请求一个资源时,服务器返回资源的同时,会在响应头里加上Expires的header。
- 浏览器收到这个资源后,会把资源和响应头都缓存下来。
- 当浏览器再次请求这个资源时,先在自己的缓存里寻找,找到后判断当前请求时间是否在Expires之前。如果是就命中强缓存,浏览器直接从缓存中读取资源,不会发送请求到服务器。
- 如果缓存都没有命中,浏览器直接从服务器加载资源时,Expires会被更新。
Cache-Control是比较新的缓存管理header,它是一个相对时间,单位是秒,它的缓存原理是:
- 当浏览器第一次请求一个资源时,服务器返回资源的同时,会在响应头里加上Cache-Control的header。
- 浏览器收到这个资源后,会把资源和响应头都缓存下来。
- 当浏览器再次请求这个资源时,先在自己的缓存里寻找,找到后根据第一次请求时间和Cache-Control设定的有效期,计算出一个资源过期时间。如果当前请求事情在过期时间之前。如果是就命中强缓存,浏览器直接从缓存中读取资源,不会发送请求到服务器。
- 如果缓存都没有命中,浏览器直接从服务器加载资源时,Cache-Contro会被更新。
304与200读取缓存的区别?讲讲304缓存的原理
- 当浏览器对某个资源的请求命中了强缓存时,返回的http状态为200
- 当浏览器对某个资源的请求没有命中强缓存,就会发一个请求到服务器,验证协商缓存是否命中,如果协商缓存命中,请求响应返回的http状态为304,浏览器收到304的状态码后使用缓存文件。
禁止缓存,期限,修改/请列举三种禁止浏览器缓存的头字段, 并写出相应的设置值
1.加载文件的时候在文件末尾给一个时间戳作为版本参数以强制刷新
<script>
var js = document.createElement("script");
js.src = "test.js?random" + Math.random();
document.body.appendChild(js);
</script>
2.meta方法:在meta标签里设置http-equiv属性,它是用来在HTML文档中模拟HTTP响应头报文的东西。
- expires: 告诉浏览器把回送的资源缓存多长时间 -1或0则是不缓存
- Cache-Control: no-cache 描述的是相对时间。
- Pragma: no-cache 设定禁止浏览器从本地获取缓存。
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Cache-Control" content="no-cache">
<meta http-equiv="Expires" content="0">
在css/js代码上线之后开发人员经常会优化性能,从用户刷新网页开始,一次js请求一般情况下有哪些地方会有缓存处理?
webscoket会用吗?webSocket如何兼容低浏览器,websocket原理,应用场景
1、webscoket是HTML5提供的传输协议。websocket是应用层第七层上的一个应用层协议,它必须依赖 HTTP 协议进行一次握手 ,握手成功后,数据就直接从 TCP 通道传输,与 HTTP 无关了。它可以将服务器的更新及时主动的发给客户端,而不需要客户端以一定时间间隔去轮询。
2、目前主流的浏览器都支持这个协议,IE还不支持。如何兼容呢?
Adobe Flash Socket 、 ActiveX HTMLFile (IE) 、 基于 multipart 编码发送 XHR 、 基于长轮询的 XHR
3、原理:Websocket的数据传输是frame形式传输的,比如会将一条消息分为几个frame,按照先后顺序传输出去。这样做会有几个好处:
- 大数据的传输可以分片传输,不用考虑到数据大小导致的长度标志位不足够的情况。
- 和http的chunk一样,可以边生成数据边传递消息,即提高传输效率。
4、应用场景:社交聊天、弹幕、多玩家游戏、协同编辑、基于位置的应用、体育实况更新、视频会议/聊天等需要高实时的场景
说说网络分层里七层模型是哪七层(从上到下)
- 应用层:允许访问OSI环境的手段
- 表示层:对数据进行翻译、加密和压缩
- 会话层:建立、管理和终止会话
- 传输层(TCP和UDP):提供端到端的可靠报文传递和错误恢复
- 网络层(IP):负责数据包从源到宿的传递和网际互连
- 数据链路层:将比特组装成帧和点到点的传递
- 物理层:通过媒介传输比特,确定机械及电气规范
各种协议
- ICMP协议: 因特网控制报文协议。它是TCP/IP协议族的一个子协议,用于在IP主机、路由器之间传递控制消息。
- TFTP协议: 是TCP/IP协议族中的一个用来在客户机与服务器之间进行简单文件传输的协议,提供不复杂、开销不大的文件传输服务。
- HTTP协议: 超文本传输协议,是一个属于应用层的面向对象的协议,由于其简捷、快速的方式,适用于分布式超媒体信息系统。
- DHCP协议: 动态主机配置协议,是一种让系统得以连接到网络上,并获取所需要的配置参数手段。
介绍一下你对浏览器内核的理解?
主要分为渲染引擎和JS引擎,浏览器内核不同导致渲染的效果不同。
- 渲染引擎:负责取得网页的内容(HTML、图片,css等),以及计算网页的显示方式,再输出到显示器或打印机
- JS引擎:解析和执行JavaScript来实现网页的动态效果。
介绍常用的几种浏览器和内核
- IE:Trident
- Firefox:Gecko
- Opera:以前是presto内核,Opera现已改用Google Chrome的Blink内核
- chrome:Blink(基于webkit,Google与Opera Software共同开发)
- safari:WebKit
WEB应用从服务器主动推送Data到客户端有那些方式?
- 基于 AJAX 的长轮询(long-polling)方式,服务器Hold一段时间后再返回信息;
- HTTP Streaming,通过iframe和<script>标签完成数据的传输;
- TCP 长连接
- HTML5新引入的WebSocket,可以实现服务器主动发送数据至网页端
上述的1和2统称为comet技术
线程与进程的区别
- 一个程序至少有一个进程,一个进程至少有一个线程
- 线程的划分尺度小于进程,使得多线程程序的并发性高
- 另外,进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率
- 线程在执行过程中与进程还是有区别的。每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制
- 从逻辑角度来看,多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。但操作系统并没有将多个线程看做多个独立的应用,来实现进程的调度和管理以及资源分配。这就是进程和线程的重要区别
性能优化
渐进增强和优雅降级
- 渐进增强:先针对低版本的浏览器构建页面,保证最基本的功能后咋针对高版本的浏览器进行效果、交互等方面的改进,以提升用户体验。
- 优雅降级:一开始就构建完整的功能,然后在针对低版本的浏览器进行兼容。
网站打开比较卡,你怎么优化;
优化网站代码,对网站进行重构。
你有哪些性能优化的方法?
- 代码层面:避免使用css表达式,避免使用高级选择器,通配选择器,避免写行内样式。少用全局变量,用innerHTML代替DOM操作,减少DOM操作次数,缓存DOM节点查找的结果,避免全局查询,多个变量声明合并,避免图片和iFrame等的空Src。空Src会重新加载当前页面,影响速度和效率,
- 缓存利用:缓存Ajax,多个域名缓存,使用CDN,使用外部js和css文件以便缓存,添加Expires头,服务端配置Etag等等
- 减小请求数量:合并样式和脚本,使用css sprite,图片按需加载,静态资源延迟加载。
- 减少带宽:压缩文件,开启GZIP
为什么利用多个域名来存储网站资源会更有效?
网站资源指网站的图片、视频、js、css。服务器直接把相应文件发送到客户端的文件都是静态资源。(动态资源一般指数据库资源)。
- 使CDN缓存更方便:静态资源和动态资源分服务器存放,使用不同的服务器处理请求。
- 突破浏览器的并发限制。比较老的浏览器(IE6)只有两个并发,现代浏览器是6个并发。并发请求只针对同一个域名的,即同一时间针对同一域名下的请求数量有限制,超过限制的资源会阻塞。
- 节省cookie带宽:每请求一个页面都会发送一次主域名下的cookie,请求头的cookie不能压缩,如果cookie较多时,会造成发送的数据过大,导致速度变慢。使用其他域名来保存cookie
- 节约主域名的连接数,优化页面响应速度
- 防止不必要的安全问题。(上传js窃取主站cookie)
关于多域名,也不是越多越好,浏览器做dns解释也是耗时间的,所以控制在2~4个之间。
移动端性能优化
- 尽量使用css3动画,开启硬件加速。
- 适当使用touch事件代替click事件。
- 避免使用css3渐变阴影效果。
- 可以用transform: translateZ(0)来开启硬件加速。
- 不滥用Float。Float在渲染时计算量比较大,尽量减少使用
- 不滥用Web字体。Web字体需要下载,解析,重绘当前页面,尽量减少使用。
- 合理使用requestAnimationFrame动画代替setTimeout
- CSS中的属性(CSS3 transitions、CSS3 3D transforms、Opacity、Canvas、WebGL、Video)会触发GPU渲染,请合理使用。过渡使用会引发手机过耗电增加
- PC端的在移动端同样适用
谈谈你对重构的理解
网站重构也就是说是在不改变UI的情况下,对网站进行优化,简化结构、添加可读性。
对于传统的网站来说重构通常是:
- 表格(table)布局改为DIV+CSS
- 使网站前端兼容于现代浏览器
- 对于移动平台的优化
- 针对于SEO进行优化
深层次的网站重构应该考虑的方面:
- 减少代码间的耦合
- 让代码保持弹性
- 严格按规范编写代码
- 设计可扩展的API
- 代替旧有的框架、语言(如VB)
- 增强用户体验
通常来说对于速度的优化也包含在重构中:
- 压缩JS、CSS、image等前端资源
- 程序的性能优化(如数据读写)
- 采用CDN来加速资源加载
- 对于JS DOM的优化
- HTTP服务器的文件缓存
什么样的前端代码是好的
高复用低耦合,这样文件小,好维护,而且好扩展。
CDN,为什么cdn比较快;
CDN:内容分发网络,因为他让用户就近取得所需内容,可以使内容传输的更快,提高用户访问网站的速度。
怎样减少http请求次数
- CSS Sprites
- 合并js,css文件
- js,css,images等资源的压缩
- CDN托管
- 缓存的使用
上线后,如何监控网站
可以使用一些监控工具,比如监控宝等等,如果访问不了,监控工具就会按照你设置的方式给你提醒。这个时候你就可以马上知道问题并想办法解决。不用自己经常去手动访问尝试了。
打不开网站,什么原因造成的,解决办法
- 服务器/空间不稳定:找个稳定的服务器很重要
- IP被限制了:换个ip访问;或者使用代理服务器伪装访问
- 通信异常:重启电脑,或者路由设备
- 本地DNS缓存:更新DNS。可以选择电脑自动更新,也可以手动清空缓存:ipconfig /displaydns ,ipconfig /flushdns,清空DNS缓存
- 网站的域名或者空间到期:及时续费
你如何对网站的文件和资源进行优化?
- 文件合并
- 文件压缩
- 使用CDN托管
- 使用多个域名来缓存资源
你都使用哪些工具来测试代码的性能?
- Profiler
- JSPerf
- Dromaeo
一个页面上有大量的图片(大型电商网站),加载很慢,你有哪些方法优化这些图片的加载,给用户更好的体验。
- 图片懒加载,在页面的未可视区域添加一个滚动条事件,判断图片位置和浏览器顶端的距离与页面的距离,如果前者小于后者,优先加载。
- 如果为幻灯片,相册等,可以使用图片预加载技术,将当前展示图片的前一张和后一张优先下载
- 如果图片为css图片,可以使用css sprite ,iconfont等技术
- 如果图片过大,可以使用特殊编码的图片,加载时会先加载一张压缩的特别厉害的缩略图,以提高用户体验。
- 如果图片展示区域小于图片的真实大小,则因在服务器端先进行图片压缩,图片压缩后大小与展示一致。
谈谈以前端角度出发做好SEO需要考虑什么?
- 了解搜索引擎如何抓取网页和如何索引网页:需要知道一些搜索引擎的基本工作原理,各个搜索引擎之间的区别,搜索机器人如何进行工作,搜索引擎如何对搜索结果进行排序等等
- Meta标签优化:主要包括主题,网站描述,和关键词。还有一些其它的隐藏文字比如Author(作者),Category(目录),Language(编码语种)等
- 如何选取关键词并在网页中放置关键词:首先要给网站确定主关键词(一般在5个上下),然后针对这些关键词进行优化,包括关键词密度,相关度,突出性等等
- 了解主要的搜索引擎:虽然搜索引擎有很多,但是对网站流量起决定作用的就那么几个。比如英文的主要有Google,Yahoo,Bing等;中文的有百度,搜狗,有道等。不同的搜索引擎对页面的抓取和索引、排序的规则都不一样。还要了解各搜索门户和搜索引擎之间的关系
- 主要的互联网目录:网站目录和搜索引擎的主要区别是网站内容的收集方式不同。目录是人工编辑的,主要收录网站主页;搜索引擎是自动收集的,除了主页外还抓取大量的内容页面。
- 按点击付费的搜索引擎:可以通过搜索引擎的点击广告来定位商业网站,这里面也大有优化和排名的学问,学会用最少的广告投入获得最多的点击。
- 搜索引擎登录:网站做完了以后,要让别人找到你,最简单的办法就是将网站提交到搜索引擎。
- 链接交换和链接广泛度:其它网站到你的网站的链接越多,你也就会获得更多的访问量。更重要的是,你的网站的外部链接数越多,会被搜索引擎认为它的重要性越大,从而给你更高的排名。
- 合理的标签使用
你平常写CSS的时候有考虑过CSS的性能么
- 避免使用css表达式,表达式会进行繁琐的求值,当改变页面(滚动,改变窗口大小)都会进行求值,影响浏览器的性能。
- 避免使用统配选择器*,因为它将所有的标签都初始化了,很占用资源。
- 尽量不要使用过小的图片做背景的平铺,假如需要1*1px平铺100*100px需要10000次,也很占用资源。
- 尽量合写css,可以减少css的字节
- 避免使用高级选择器,使用单一的或者尽量少的class来解决。
- 学会利用继承,在css里很多属性可以继承,比如visibility,font-family等等
reflow和repaint(重排和重绘)
1.repaint(重绘):改变DOM元素的视觉效果时会触发,使浏览器变慢,因为改变某个元素的视觉效果会check这个DOM元素内的所有节点,会重新对DOM渲染。
比如:opacity、background-color、visibility、outline
2.reflow(回流):改变DOM元素的位置时会触发,比repaint开销更大,因为他会重新计算所有元素的位置和占用的面积,这样会引起整个页面的重新渲染,他也会触发repaint。(display:none的元素不会引发重排和重绘)
比如:js添加删除元素,用js改变DOM的可见性(display:none-block),添加删除或改变CSS样式,增加或移除样式表,css3的动画和过渡,使用offsetwidth和offsetheight。还有用户的一些操作:拖动窗口大小,表单输入值 ,改变字体大小,更换样式表等等
常见web安全及防护原理
1.CSRF(Cross-site request forgery):跨站请求伪造:攻击者盗用了你的身份,以你的名义发送恶意请求。
CSRF能够做的事情包括:以你名义发送邮件,发消息,盗取你的账号,甚至于购买商品,虚拟货币转账......造成的问题包括:个人隐私泄露以及财产安全。
- 检查报头中的Referer参数确保请求发自正确的网站(但XHR请求可调用setRequestHeader方法来修改Referer报头);
- 对于任何重要的请求都需要重新验证用户的身份;
- 创建一个唯一的令牌(Token),将其存在服务端的session中及客户端的cookie中,对任何请求,都检查二者是否一致。
2.xss (Cross Site Scripting):跨站脚本攻击:通过插入恶意脚本,实现对用户游览器的控制
- 浏览器自身可以识别简单的XSS攻击字符串,从而阻止简单的XSS攻击;
- 从根本上说,解决办法是消除网站的XSS漏洞,这就需要网站开发者运用转义安全字符等手段,始终把安全放在心上;
- 对于普通网民,需要注意尽量抵挡诱惑,别去点击非知名网站的链接。
3.sql注入:以SQL语句作为用户输入,从而达到查询/修改/删除数据的目的
- 永远不要信任用户的输入,要对用户的输入进行校验,可以通过正则表达式,或限制长度,对单引号和双"-"进行转换等。
- 永远不要使用动态拼装SQL,可以使用参数化的SQL或者直接使用存储过程进行数据查询存取。
- 永远不要使用管理员权限的数据库连接,为每个应用使用单独的权限有限的数据库连接。
- 不要把机密信息明文存放,请加密或者hash掉密码和敏感的信息。
哪些地方会出现css阻塞,哪些地方会出现js阻塞?
CSS 本来是可以并行下载的,当 CSS 后面跟着嵌入的 JS 的时候,该 CSS 就会出现阻塞后面资源下载的情况。因为浏览器会维持 html 中 css 和 js 的顺序,样式表必须在嵌入的 JS 执行前先加载、解析完。而嵌入的 JS 会阻塞后面的资源加载,所以就会出现上面 CSS 阻塞下载的情况。
所有浏览器在下载 JS 的时候,会阻止一切其他活动,比如其他资源的下载,内容的呈现等等。直到 JS 下载、解析、执行完毕后才开始继续并行下载其他资源并呈现内容。
Javascript无阻塞加载具体方式
- 把延迟脚本放在页面底部(body标签里)
- defer:在script标签里设置这个属性,具有这个属性的脚本会被延迟到整个页面都解析完毕后再运行,就是相当于告诉浏览器立即下载但延迟执行。
- async:它的作用和defer类似,但是脚本不一定会按照先后顺序执行。
- 动态创建DOM的方式:创建script标签,插入到DOM中,加载完毕后callBack
- 使用jQuery的getScript()方法
兼容性
写出几种IE6 BUG的解决方法
常见兼容性问题?
列举IE 与其他浏览器不一样的特性?
超链接访问过后hover样式就不出现的问题是什么?如何解决?
Node.JS
了解Node么?Node的使用场景都有哪些?
对Node的优点和缺点提出了自己的看法?
.如何判断当前脚本运行在浏览器还是node环境中?
框架/项目
你都用过哪些前端框架?为什么选择这个框架?
博客主要通过Angular这个框架搭建的。
Angualr是一款基于MVC的框架,MVC是模型,视图,控制器的缩写。模型负责数据保存,视图负责用户界面,控制器负责业务逻辑。
主要应用于单页面的WEB应用。提供了许多功能,例如双向数据绑定,AJAX服务,路由,模块化等。
博客大致过程就是通过视图,路由等功能搭建了页面,在控制器里通过点击不同的链接向AJAX请求服务器端的数据。通过php操作数据库进行数据库的查询,再将返回的数据显示在视图上。
在这个过程当中也出现了许多问题,例如:在数据传递过程当中会出现各种各样的错误,这时候就要调试清楚到底是哪个环节出了问题。
AngularJS:
它拓展了HTML,提供了丰富的指令。例如
- ng-repeat用于每遍历数组中的一项,就会克隆一次HTML
- ng-model把元素值绑定到应用程序
- ng-app初始化一个应用程序。
每一个ng-controller都有一个作用域,$scope对象拥有属性和方法,当把scope对象加到控制器时,视图就可以获取这些属性。
每一个应用都有一个rootscope根作用域,也就是说它的属性和方法可以作用在app的所有元素当中
Angular还具有http服务,用于读取远程服务器上的数据
$http.get("data/clickRate.php").success(function(response) {
$scope.clickRate = response;
});
Angular还提供路由。它主要通过#号来实现,因为url中#号后面的内容会被忽略掉,点击链接时向服务器请求的地址是相同的。每当点击连接时就会显示不同的内容。
Angular优点缺点
Angular JS (Angular.JS) 是一组用来开发Web页面的框架
优点:
是一个比较完善的MVC框架,包含了模板,双向数据绑定,路由功能。双向数据绑定可能是AngularJS最酷最实用的特性,将MVC的原理展现地淋漓尽致.
自带丰富的angular指令,无需进行手工DOM操作。
AngularJS很小,只有60K,兼容主流浏览器,与 jQuery 配合良好
缺点:
- ng-view只能有一个,不能嵌套多个视图。
- 对于特别复杂的应用场景,性能可能会出现问题。
angular的双向绑定原理
Angular实现了双向绑定机制。所谓的双向绑定,无非是从界面的操作能实时反映到数据,数据的变更能实时展现到界面。
Bootstrap了解程度
对于SASS或是Less的了解程度?喜欢那个?
你觉得jQuery或zepto源码有哪些写的好的地方
react native是怎么做到用js调用原生API的?怎么把js代码和java或者OC连接起来的?介绍底层的实现
如何评价AngularJS和BackboneJS
jquery绑定click的方法有几种
vue.js双向绑定的原理,讲一讲MVVM
jQuery源码有看过吗?请说出你印象最深刻部分的原理。
请说出jQuery内部判断数据类型的巧妙方式。
针对 jQuery 的优化方法?
你从jQuery学到了什么?
Jquery与jQuery UI 有啥区别?在jquery方法和原型上面添加方法的区别和实现($.extend,$.fn.extend),以及jquery对象的实现(return new jQuery.fn.init)
jquery 中如何将数组转化为json字符串,然后再转化回来?
react虚拟DOM为什么有优势,我用原生的为啥就慢,是什么原因;
工具
对于前端自动化构建工具有了解吗?简单介绍一下
你常用的开发工具是什么,为什么?
用过哪些自动化构建工具,怎么用的
谈谈你对webpack的看法,webpack底层实现原理,webpack是用来干嘛的
平时如何管理你的项目?
新技术
说说最近最流行的一些东西吧?常去哪些网站?
对前端模块化的认识
ES6的了解,es6哪些特性比较吸引你,ES6里头的箭头函数的this对象与其他的有啥区别
requireJS的原理是什么? requirejs怎么防止重复加载
说说你对Promise的理解,构造一个 Promise,用promise手写ajax
babel是如何将es6代码编译成es5的
说说你对AMD和Commonjs的理解
说说你对MVC和MVVM的理解
AMD和CMD 规范的区别
模块化怎么做?
如何将项目里面的所有的require的模块语法换成import的ES6的语法?
看过那些书(高级程序设计看了几遍,有啥收获)
对数据库的了解,mysql与 MongoDB的区别
分别说说同步和异步模块化的应用场景,说下AMD异步模块化实现的原理?
一个静态资源要上线,里面有各种资源依赖,你如何平稳上线
如果要你去实现一个前端模板引擎,你会怎么做
手指点击可以触控的屏幕时,是什么事件?
编程
编写一个b继承a的方法;
function A(name){ this.name = name; this.sayHello = function(){alert(this.name+" say Hello!");}; } function B(name,id){ A.call(this,name); //在子类型的构造函数内部调用父类型的构造函数 this.id = id; } var b=new B("furong",1) b;//B {name: "furong", id: 1, sayHello: function}
实现一个函数clone,可以对JavaScript中的5种主要的数据类型(包括Number、String、Object、Array、Boolean)进行值复制
原始类型和引用类型克隆的时候有很大区别,因为原始类型存储的是简单的数据段,引用类型存储的是对象在内存当中的地址。
浅克隆:原始类型值传递,引用类型引用传递。
深克隆:对新对象的修改不会影响到原来的对象。
tips:我们直接通过普通赋值的方式,就实现了函数的克隆,因为函数的克隆会在内存单独开辟一块空间,互不影响。
function isClass(obj){ return Object.prototype.toString.call(obj).slice(8,-1); } function deepClone(obj){ var type=isClass(obj); var result; if (type==="Array") { result=[]; }else if(type==="Object"){ result={}; }else{ //除了数组和对象,其他类型的数据都可以通过简单赋值进行克隆。 return obj; }; //对象属性的遍历 for (var key in obj) { //继续判断属性的数据类型 if (isClass(obj[key])=="Object" || isClass(obj[key])=="Array") { //如果属性值的对象,递归调用 result[key]=deepClone(obj[key]); } else{ //如果属性都是简单的数据段,直接赋值 result[key]=obj[key]; } } return result; }
编写一个方法 求一个字符串的字节长度
英文字母字节数=length,一个中文占两个字节,所以我们需要把中文的个数计算出来
ASCII 字符集的码值从 0 到 255,代表了字母、数字、标点符号和其他字符
可以通过charCodeAt(i)获取每个位置的Unicode编码判断是否为中文字符
function getBytes(str){ var len=str.length; var result=len; for (var i = 0; i < len; i++) { if (str.charCodeAt(i)>255) { result++; }; }; return result; }
获取url后面的参数并变为对象
function getSearchObj(){ var qs=location.search.length>0?location.search.subString(1):'', obj={}, items=qs.length>0?qs.split('&') : [], item=null; name='', value='', i=0; len=items.length; for (var i = 0; i < len; i++) { item=items[i].split('='); name=decodeURIComponent(item[0]); value=decodeURIComponent(item[1]); obj[key]=value? value : undefined; } return obj; }
三级菜单的实现,简单描述下你的实现过程;不用框架
- 第一级菜单的ul li标签
- 一级li标签里包含文字和第二级ul li标签
- 二级li标签里包含文字和第三级ul li标签
<ul class="menu"> <li class="level1">一级菜单 <ul class="level2"> <li class="level2-2">二级菜单1 <ul class="level3"> <li>1-2-3</li> <li>1-2-3</li> <li>1-2-3</li> </ul> </li> <li class="level2-2">二级菜单1 <ul class="level3"> <li>2-2-3</li> <li>2-2-3</li> <li>2-2-3</li> </ul> </li> <li class="level2-2">二级菜单1 <ul class="level3"> <li>3-2-3</li> <li>3-2-3</li> <li>3-2-3</li> </ul> </li> </ul> </li> <li class="level1">一级菜单 <ul class="level2"> <li>二级菜单2</li> <li>二级菜单2</li> <li>二级菜单2</li> </ul> </li> <li class="level1">一级菜单 <ul class="level2"> <li>二级菜单3</li> <li>二级菜单3</li> <li>二级菜单3</li> </ul> </li> </ul>
使二级菜单level2和三级菜单level3的display设置为none;绝对定位,left设置为宽度的值;高度为32px;
在js里,
- 获取一级菜单的nodelist,二级菜单的nodelist,二级菜单li标签的list
- 给每一个一级菜单的li绑定mouseover和out事件,使用闭包,获取每次的下表,over时对应下标的level2[i]显示,并且top设置为i*32px;
- 给每个二级菜单中的li绑定事件,over时对应的level3[i]显示
window.onload = function() { var level1 = document.getElementsByClassName("level1"); var level2 = document.getElementsByClassName("level2"); var level20Li = document.getElementsByClassName("level2-2"); var level30 = document.getElementsByClassName("level3"); for (var i = 0; i < level1.length; i++) { level1[i].onmouseover = (function(i) { return function() { level2[i].style.display = "block"; level2[i].style.top = (i * 32 + "px"); } })(i); level1[i].onmouseout = (function(i) { return function() { level2[i].style.display = "none"; } })(i); } for (var i = 0; i < level20Li.length; i++) { level20Li[i].onmouseover = (function(i) { return function() { console.log(i); level30[i].style.display = "block"; level30[i].style.top = (i * 32 + "px"); } })(i); level20Li[i].onmouseout = (function(i) { return function() { level30[i].style.display = "none"; } })(i); } }
(function() { var menu = document.getElementById("menu"); var level1 = menu.getElementsByClassName("level1"); var level2 = menu.getElementsByClassName("level2"); addEvent(level1); addEvent(level2); function addEvent(objects) { var len=objects.length; for (var i = 0; i < len; i++) { objects[i].onmouseover = function() { var children = this.childNodes; for (var j = 0; j < children.length; j++) { if (children[j].nodeName == "UL") { children[j].style.display = "block"; } } } objects[i].onmouseout = function() { var children = this.childNodes; for (var j = 0; j < children.length; j++) { if (children[j].nodeName == "UL") { children[j].style.display = "none"; } } } } } })();
一个table,点击按钮,实现某一列的刷新,不能采用框架,简单描述下实现过程
<body>
<table id="tb" border="1" style="border-collapse: collapse;">
<thead>
<tr>
<th>name</th>
<th οnclick="update(this)">age</th>
</tr>
</thead>
<tbody>
<tr>
<td>A</td>
<td>12</td>
</tr>
<tr>
<td>b</td>
<td>18</td>
</tr>
<tr>
<td>c</td>
<td>30</td>
</tr>
</tbody>
</table>
<script type="text/javascript">
function update(btn) {
var table = document.getElementById("tb");
var tbody=table.tBodies[0];
var getObj = function(table) {
var arr = [],
rows = table.tBodies[0].rows,
len = rows.length;
for (var i = 0; i < len; i++) {
var key = rows[i].cells[0].innerHTML;
var value=rows[i].cells[1].innerHTML;
arr[i]={
name:key,
age:value
}
}
return arr;
}
var arr=getObj(table);
arr.sort(function(a,b){
return b.age-a.age;
})
tbody.innerHTML="";
for (var i = 0,len=arr.length; i < len; i++) {
tbody.insertRow(i);
tbody.rows[i].innerHTML="<td>"+arr[i].name+"</td><td>"+arr[i].age+"</td>";
}
}
</script>
</body>
点击按钮后把数据存在数组里,数组元素是对象存放name和age,然后按照age排序,清空tbody后把内容逐次加到列表当中
window.onload = function() { var btn = document.getElementById('age');//获取要刷新那一行的按钮 var tbody = document.getElementsByTagName('tbody')[0]; var tr = tbody.getElementsByTagName('tr'); var age = [],//保存哪一行的数据 result = [];//保存刷新后的值 for (var i = 0; i < tr.length; i++) { var msg = parseInt(tr[i].getElementsByTagName('td')[2].innerHTML); var brr = [msg, i] age.push(brr);//将每一行的数据和对应的行数保存在二维数组中 }; flag = true;//只能点击一次 btn.onclick = function() { if (flag) { age = age.sort();//从小到大排序 for (var i = 0; i < age.length; i++) { var key = age[i][1]; result.push(tr[key]);//将排序后的tr保存起来 }; tbody.innerHTML = ""; for (var i = 0; i < result.length; i++) { tbody.appendChild(result[i]);//更新整个table }; flag = false; }; } }
实现一个可拖动的div(要考虑到浏览器兼容性)
/*盒子设置宽高,并且相对定位*/ #box { width: 100px; height: 100px; background-color: red; position: relative; }
//确定窗口大小 var screenheight=document.body.clientHeight /*混杂模式*/ ||document.documentElement.clientHeight /*标准模式*/ ||window.innerHeight; /*移动设备*/ var screenwidth= document.body.clientWidth /*混杂模式*/ ||document.documentElement.clientWidth /*标准模式*/ ||window.innerWidth;
/* a) 给需要拖拽的节点绑定mousedown, mousemove, mouseup事件 b) mousedown事件触发后, 开始拖拽 c) mousemove时, 需要通过event.clientX和clientY获取拖拽位置, 并实时更新位置 d) mouseup时, 拖拽结束 e) 需要注意浏览器边界的情况*/
<body>
<div id="div" style="width: 100px;height: 100px;background: red;position: absolute;">
</div>
<script>
var div = document.getElementById("div");
var pageWidth = document.documentElement.clientWidth || document.body.clientWidth || window.innerWidth;
var pageHeight = document.documentElement.clientHeight || document.body.clientHeight || window.innerHeight;
div.onmousedown = function(e) {
var e = e || window.event;
var a = e.clientX - div.offsetLeft;
var b = e.clientY - div.offsetTop;
div.onmousemove = function(e) {
console.log(this.offsetHeight)
var c = e.clientX - a;
var d = e.clientY - b;
if (c < 0) c = 0;
if (d < 0) d = 0;
if (c > pageWidth - this.offsetWidth) c = pageWidth - this.offsetWidth;
if (d > pageHeight - this.offsetHeight) d = pageHeight - this.offsetHeight;
this.style.left = c + 'px';
this.style.top = d + 'px';
}
this.onmouseup = function() {
div.onmousemove = null;
}
}
让写个从几个li中取下标的闭包代码
<body>
<ul>
<li>0</li>
<li>1</li>
<li>2</li>
</ul>
<script type="text/javascript">
window.onload=function(){
/*方法一:循环:闭包*/
/*var li=document.getElementsByTagName("li");
for (var i = 0; i < li.length; i++) {
li[i].οnclick=(function(i){
return function(){
alert(i);
}
})(i)
};*/
//方法二:事件代理
var ul=document.getElementsByTagName("ul")[0];
ul.onclick=function(e){
console.log(e.target.innerHTML)
}
}
</script>
</body>
手写闭包,继承,
//闭包内的变量不会被垃圾回收机制回收 function fn(){ var n=0; return function(){ n++; console.log(n); } } var foo=fn(); foo();//1 foo();//2 foo();//3
手写事件绑定
var EventUtil={ addEvent:function(item,type,fn){ if (item.addEventListener) { item.addEventListener(type,fn,false); }else if (item.attachEvent) { item.attachEvent('on'+type,fn) //IE }else{ item['on'+type]=fn; } }, removeEvent:function(item,type,fn){ if (item.removeEventListener) { item.removeEventListener(type,fn,false); }else if (item.detachEvent) { item.detachEvent('ob'+type,fn) //IE }else{ item['on'+type]=null; } }, getEvent:function(e){ return e || window.event; }, getTarget: function(e) { var e = this.getEvent(e); var target = e.target || e.srcElement; if (target.nodeType === 3) {//空白节点 target = target.parentNode; } return target; } }
手写一个原生ajax
<body>
<button id="btn" type="button">AJAX局部刷新</button>
<div id="result"></div>
<script type="text/javascript">
var btn=document.getElementById("btn");
var result=document.getElementById("result");
btn.onclick=function(){
var xhr=null;
if (window.XMLHttpRequest) {
xhr=new XMLHttpRequest();
}else{
xhr=new ActiveXObject("Microsoft.XMLHTTP")
}
xhr.open("GET","url",true);
xhr.onreadystatechange=function(){//创建一个响应HTTP请求变化的函数
if (xhr.readyState===4 && xhr.status===200) {
//使用JavaScript和DOM局部刷新页面
result.innerHTML=xhr.responseText;
}
}
xhr.send(null);
}
</script>
手写实现jquery里面的insertAfter(结合nextSibling和insertBefore来实现)
<script type="text/javascript"> window.onload = function() { var one = document.getElementById("one"); var two = document.createElement("div"); two.innerHTML = "2"; function insertAfter(two, one) { var parent = one.parentNode; // 看子元素里有几个属性节点 var child = parent.childNodes; var count = 0; for (var i = 0; i < child.length; i++) { if (child[i].nodeType === 1) { count++; }; }; /*如果只有一个*/ if (count == 1) { parent.appendChild(two); } else { //判断下一个节点是元素节点,nodeType=1 var three = one.nextSibling; while (three.nodeType != 1) { three = three.nextSibling; }; parent.insertBefore(two, three); } } insertAfter(two, one); }
toggleClass实现
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>toggle</title>
<style>
#test {
width: 400px;
height: 300px;
margin: 50px auto;
}
.red {
border: 5px solid red;
}
.opacity {
opacity: 0.2;
}
.yellow {
background-color: yellow;
}
</style>
</head>
<body>
<div id="test" class="yellow"></div>
<br/>
<div style="text-align:center;margin:0 auto">
<button type="button" οnclick="toggleClass('red')">红色边框</button>
<button type="button" οnclick="toggleClass('opacity')">内填充</button>
</div>
<script type="text/javascript">
var ele = document.getElementById('test'); //得到元素
function toggleClass(newClass) {
var currentClass = ele.className;//获取当前样式
var arr = [];
var exist = false;//用变量来标识类是否存在
if (!currentClass) {//如果当前样式不存在,直接添加
ele.className = newClass;
} else {//如果存在
arr = currentClass.split(' ');//将样式存放在数组里方便判断里面是否存在新的样式
for (var i = 0; i < arr.length; i++) {
if (arr[i] == newClass) {//如果发现存在
exist = true;//标记为当前样式中存在新的样式
ele.className = currentClass.replace(newClass, '').trim();//通过字符串的replace方法去除样式,在赋值给元素的className
break;//退出循环
}
}
if (!exist) {//如果当前样式中都不存在新的样式
ele.className=currentClass+' '+newClass;//将样式添加到当前样式当中
};
}
}
</script>
</body>
</html>
写一个通用的事件侦听器函数?
window.onload = function() { var Event = { /*视能力分别使用dom2||IE||dom0方式 来绑定事件*/ addEvent: function(ele, type, fn) { if (ele.addEventListener) { ele.addEventListener(type, fn, false); } else if (ele.attachEvent) { ele.attachEvent('on' + type, function() { fn.call(ele); }); } else { ele['on' + type] = fn; } }, removeEvent: function(ele, type, fn) { if (ele.removeEventListener) { ele.removeEventListener(type, fn, false); } else if (ele.detachEvent) { ele.detachEvent('on' + type, fn); } else { ele['on' + type] = null; } }, stopProrpgation: function(e) { e = this.getEvent(e); console.log(e); if (e.stopProrpgation) { e.stopProrpgation(); } else { e.cancleBubble = true; } }, preventDefault: function(e) { e = this.getEvent(e); if (e.preventDefault) { e.preventDefault(); } else { e.returnValue = false; } }, getEvent: function(e) { return e || window.event; }, getTarget: function(e) { var e = this.getEvent(e); var target = e.target || e.srcElement; if (target.nodeTypr === 3) { target = target.parentNode; } return target; } } var btn = document.getElementById('btn'); function handler() { /*alert(this.id);*/ Event.getEvent(); Event.stopProrpgation(); Event.preventDefault(); } Event.addEvent(btn, 'click', handler); /* Event.removeEvent(btn, 'click', handler);*/ }
如何获取UA
用来表明用户的浏览器名称和版本,操作系统等信息。在每一次HTTP请求中,响应头部都会包含UA字符串,用于浏览器识别和数据统计。在js中可以用navigator.userAgent属性来获取本浏览器的UA字符串。UA可以让网页开发者能够根据不同的浏览器发送不同的显示内容,为了避免浏览器不支持的功能,以获得更好的用户体验。例如“Mozilla/1.0 (Windows NT 6.1; rv:2.0.1) Gecko/20100101Firefox/4.0.1”,此字符串表明这是一个 Windows 版的使用 Gecko 引擎(火狐浏览器内核)的火狐浏览器。
<form name="Browser"> 浏览器名称:<input type="text" name="appCodeName" ><br> 完整的浏览器名称:<input type="text" name="appName" ><br> 浏览器版本:<input type="text" name="appVersion" ><br> 浏览器的用户代理字符串:<input type="text" name="userAgent" ><br> <button type="button" οnclick="getUA()">点击获取浏览器信息</button> </form> <script> function getUA(){ document["Browser"][0].value=navigator.appCodeName; document["Browser"][1].value=navigator.appName; document["Browser"][2].value=navigator.appVersion; document["Browser"][3].value=navigator.userAgent; } </script>
字符串匹配,一个字符串子在另一个字符串中出现的次数
function getStrNum(subStr,str){ //RegExp构造函数动态创建正则表达式,RegExp构造函数第一个参数是正则表达式主题部分, //第二个参数可选,是正则的修饰符,g表示全局搜索 var pattern=new RegExp(subStr,'g');//全局匹配的正则对象 // return str.match(pattern).length; }
将一篇文章的每个单词首字母大写;不改变原有的格式
function tooUpperLetter(str) { return str.replace(/\b\w+\b/g, function(word) { return word.substring(0, 1).toUpperCase() + word.substring(1); }) }
快排实现的原理
function quickSort(arr){ if (arr.length<=1) return arr; var left=[],right=[]; var num=Math.floor(arr.length/2);//取得中间的数值,将它从数组中删除 var value=arr.splice(num,1); for (var i = 0; i < arr.length; i++) { if (arr[i]<value) { left.push(arr[i]); }else{ right.push(arr[i]); } } return arguments.callee(left).concat(numValue,arguments.callee(right)); }
请用Css写一个简单的幻灯片效果页面
百度搜索框
手机某一行均分为四个,不知道尺寸的情况下
如何自己实现一个alert
三个tab页面,实现代码
有没有写过插件,用js写过什么(然后就是具体描述怎么实现的)
给你一个url,判断是否是同一个域名(qq.com)下的
图片预加载
.js:写一个递归。就是每隔5秒调用一个自身,一共100次。
js轮播实现思路
使用js画一个抛物线,抛物线上有个小球随着抛物线运动,有两个按钮能使小球继续运动停止运动
实现两个大整数的相加,怎么实现两个大整数的相乘说下思路
说下选择排序,冒泡排序的实现思路
url去参数的题
手写一个盒子模型中,获取盒子内子节点的class样式
深度遍历DOM节点
复杂的酒店预订table
手写jsonp的实现
手写链表倒数第K个查找
手写一个jQuery插件
手写一个简单遍历算法
手写归并排
实现两个数组的排序合并,我一开始先合并再排序,他不乐意,然后我用了类似插入排序的方法
手写实现一个promise(不会)
手写实现requireJS模块实现(想了半天才想到createElement("script"),配合异步来加载,闭包导出)
JS配合DOM实现EChart柱状图
移动端
有移动端的经验么?
移动端适配问题
1) <meta name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1.0; user-scalable=0;" />
//width=device-width :强制让文档的宽度与设备的宽度保持1:1
// initial-scale=1.0:文档初始化缩放比例是1:
//user-scalable=0:不允许用户点击屏幕放大浏览,
//maximum-scale=1.0:允许用户缩放到的最大比例,
注意:content里多个属性的设置一定要用逗号+空格来隔开,如果不规范将不会起作用。
其他属性有:width;height; initial-scale; minimum-scale; maximum-scale; user-scalable;
2) <meta name="apple-mobile-web-app-capable" content="yes" />
//iPhone私有标签,它表示:允许全屏模式浏览
3) <meta name="apple-mobile-web-app-status-bar-style" content="black" />
//iPhone私有标签,它指定的iPhone中safari顶端的状态条的样式
4) <meta name="format-detection" content="telephone=no; email=no" /> //不识别邮件和不把数字识别为电话号码
你用了移动端的什么库类和框架?
移动端要注意哪些
适配有去考虑么,retina屏幕啊?
关于前端
你觉得哪些站点前端技术比较好的?或者说你平时怎么学前端的?看过哪些前端的书
你有什么规划?
你所了解的前端技术栈有哪些
你有什么问题要问的么?前端妹子的发展路线都有哪些?前端技术多而杂,好的学习方法?
移动端和pc差别
自学经历
数据结构
解释平衡二叉树,以及在数据结构中的应用
平衡二叉树相关知识
图论最短路径算法
数组和链表的区别,空间和时间上的优劣,查找和删除的选择
快排的时间复杂度和空间复杂度。
常见排序算法的时间复杂度
数据集A、数据集B大小500GB,电脑内存很小,如何求得AB的差集。
数组和链表的区别
后序遍历的实现代码
排序算法总结
栈和队列
冒泡快排算法思路,复杂度
整型数组全排列问题
virtual dom的实现,diff算法
对模块化了解吗?说说有哪些模块化的库,有了解过模块化的发展的历史吗?(commonJS,RequireJS,SeaJS)
分别说说同步和异步模块化的应用场景,说下AMD异步模块化实现的原理?(看JS设计模式的时候看过同步模块模式,所以我只答了同步模块化的实现,但是AMD异步的不会)
如何将项目里面的所有的require的模块语法换成import的ES6的语法?
复习数据结构 排序算法重新写一遍,二分,链表的算法,BFS,DFS,图论最短路径等算法,以前基础不错写了大量博客, 所以看看自己的博客,复习起来很快
刷前端面经 bind,debounce,once,深浅拷贝等的ployfill
事件委托,JQ链式调用实现,原生ajax,函数式,柯里化
常见的跨域方式和原理(主要是jsonp和CORS,记得CORS一定要动手自己写后端才能理解深刻)
前端安全之XSS和CSRF,以及如何防御
ES6部分,let暂时性死区,箭头函数(this指针,arguments的坑),generator/iterator,promise,阮一峰老师的那本电子书
模块化历史以及同步异步原理
webpack 2.0 慕课网上看一个大神的视频,讲的很好
360奇舞团瓜瓜老师的性能优化的视频,关键渲染路径,网页渲染过程,资源对渲染的阻塞
根据前几轮面试暴露的缺点,做了下面的实践
80行代码的类工厂,原型链继承面向对象的一个实践
100行简单实现AMD异步模块加载器(JS设计模式这本书上有样例代码)
看Vue文档练手,然后阅读Vue.js早期源码,简单实现MVVM双向绑定,数组监听,简单指令实现
看gayhub上的仓库的代码,模仿virtual-dom的实现,diff算法
- padding百分比是相对于父级宽度还是自身的宽度




