码云笔记前端博客
Home > 免费资源 > web前端开发经典面试题整理

web前端开发经典面试题整理

2019-02-27 分类:免费资源 作者:管理员 阅读(6445)

本文共计45892个字,阅读时间预计115分钟,干货满满,记得点赞加收藏哦

  每到年底,想起来金三银四跳槽季,心里就痒痒:那么多高薪机会,我要不要看看?听了太多“别人公司的福利”、“别人公司的薪资”、“别人公司的发展机会”,于是,很多人摩拳擦掌准备拿了年终奖就另择高枝换个更好的工作。可是,你真的准备好了吗?然而对于前端开发的小伙伴来说,在面试之前刷一下前端面试题还是有必要的,所以忙里偷闲为大家整理一下有关前端面试题,希望对小伙伴们有帮助。

web前端开发经典面试题整理

1.CSS的盒子模型

  包含元素内容content、内边距padding、边框border、外边距margin

  box-sizing:border-box;content-box;inherit;

  1)content-box:总宽度=margin+border+padding+width,即为标准模型;

  2)border-box:总宽度=margin+width,即为IE模型;

  3)inherit:继承父元素的border-sizing属性。

2.AJAX的readyState几种状态

  0——初始化

  1——载入

  2——载入完成

  3——解析

  4——完成

3.常见的post提交数据方式对应的content-type取值

  4种

  1)application/x-www-form-urlencoded:数据被编码为名称/值对,这是标准的编码格式。

  2)multipart/form-data:数据被编码为一条消息,页上的每个控件对应消息中的一个部分。

  3)application/json:告诉服务端消息主体是序列化后的JSON字符串.

  4)text/xml

4.清除浮动的几种方法

  1)父级div定义伪类:after和zoom

1
.clearfloat::after {display:block; clear:both; content:" "; visibility:hidden; height:0;} .clearfloat {zoom:1}

  2)在结尾处添加空div标签clear:both

  3)父级div定义height

  4)父级div定义display:table

  5)父级div也一起浮动

  6)父级div定义overflow:auto/hidden(必须定义width或zoom:1,同时不能定义height,浏览器会自动检查浮动区域的高度)

5.Webpack解析ES6用的插件

babel-loader

6.移动端上click事件在某些浏览器有没有遇到延迟的问题

1)静止缩放

1
<meta name="viewport" content="width=device-width user-scalable='no' ">

1
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1">

2)引入fastclick.js

1
2
3
window.addEventListener(function(){
FastClick.attach(document.body);
1},false);

7.HTTP的缓存机制

  1)强制缓存:当所请求的数据在缓存数据库中尚未过期时,不与服务器进行交互,直接使用缓存数据库中的数据。

  Expire/Cache-Control

  2)协商缓存:从缓存数据库中取出缓存的标识,然后向浏览器发送请求验证请求的数据是否已经更新,如果已更新则返回新的数据,若未更新则使用缓存数据库中的缓存数据。

  etag/last-modifield

8.实现三栏布局(左右两边固定宽度,中间自适应)

  1)浮动布局

  左右两边固定宽度,并分别设置float:left和float:right。(但这会带来高度塌陷的问题,所以要清除浮动。清除浮动的方式有:

  a.给父级盒子设置height;

  b.给父级盒子设置overflow:hidden;

  c.在父级盒子结束前的盒子添加clear:both;

  d.父级盒子也设置浮动;

  e.父级div定义伪类:after和zoom,

1
2
.clear::after{display:block;clear:both;content:"";visibility:hidden;height:0;}
.clear{zoom:1;}

  2)绝对定位布局

  左中右三个盒子都设置position:absolute;然后分别设置定位

  3)flex布局

  父盒子设置display:flex;位于中间的子盒子设置flex:1

  4)表格布局

  父盒子设置display:table;左中右三个盒子设置display:table-cell;左右两个盒子分别设置宽度;

  5)网格布局

  父盒子设置display:grid;grid-template-columns:300pxauto300px;

9.== 和 === 的区别

  ===为恒等符:当等号两边的值为相同类型的时候,直接比较等号两边的值,值相同则返回true,若等号两边的值类型不同时直接返回false。

  ==为等值符:当等号两边的值为相同类型时比较值是否相同,类型不同时会发生类型的自动转换,转换为相同的类型后再作比较。

  a、如果一个是null、一个是undefined,那么相等。

  b、如果一个是字符串,一个是数值,把字符串转换成数值再进行比较。

  c、如果任一值是true,把它转换成1再比较;如果任一值是false,把它转换成0再比较。

  d、如果一个是对象,另一个是数值或字符串,把对象转换成基础类型的值再比较。对象转换成基础类型,利用它的toString或者valueOf方法。js核心内置类,会尝试valueOf先于toString;例外的是Date,Date利用的是toString转换。那些不是JavaScript语言核心中的对象则通过各自的实现中定义的方法转换为原始值。

  e、任何其他组合,都不相等。

web前端开发经典面试题整理

10.transition和animation比较

transition

  1)语法

  transition是一个复合属性,可设置四个过渡属性,简写方式如下:

1
transition{ transition-property transition-duration transition-timing-function transition-delay}

  transition-property:是用来指定当元素其中一个属性改变时执行transition效果,值有none(没有属性改变)、all(默认值,所有属性改变),indent(某个属性名,一条transition规则,只能定义一个属性的变化,不能涉及多个属性,如果要设置多个属性时,需分别设置,中间以逗号隔开)【当其值为none时,transition马上停止执行,当指定为all时,则元素产生任何属性值变化时都将执行transition效果】;

  transition-duration:过度时间,是用来指定元素转换过程的持续时间,单位为s(秒)或ms(毫秒);

  transition-timing-function:时间函数,根据时间的推进去改变属性值的变换速率,值ease(逐渐变慢)、linear(匀速)、ease-in(加速)、ease-out(减速)、ease-in-out(加速然后减速)、cubic-bezier:(自定义一个时间曲线);

  transition-delay:延迟,指定一个动画开始执行的时间,也就是当改变元素属性值后多长时间开始执行transition效果,单位为s(秒)或ms(毫秒);

  2)触发方式

  伪类触发::hover,:focus,:checked,:active

  js触发:toggleClass

  3)以下情况下,属性值改变不能产生过渡效果

  a.background-image,如url(a.jpg)到url(b.jpg)(与浏览器支持相关,有的浏览器不支持)等

  b.float浮动元素

  c.height或width使用auto值

  d.display属性在none和其他值(block、inline-block、inline)之间变换

  e.position在static和absolute之间变换

  transition示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<head>
   <style>    
   #box2{
            height: 100px;
            width: 100px;
            background: blue;
        }
        #box2:hover{
            transform: rotate(180deg) scale(.5, .5);
            background: red;
            transition: background 2s ease, transform 2s ease-in 1s;}
    </style>
</head>
<body>
 <div id="box1">BOX1</div>
 <div id="box2">BOX2</div>
</body>

animation

1)语法

1
animation{ animation-name animation-duration animatino-timing-function animation-delay animation-iteration-count animation-direction animtion-play-state animation-fill-mode}

  animation-name:用来调用@keyframes定义好的动画,与@keyframes定义的动画名称一致;

  animation-duration:指定元素播放动画所持续的时间;

  animation-timing-function:和transition中的transition-timing-function中的值一样。根据上面的@keyframes中分析的animation中可能存在多个小动画,因此这里的值设置是针对每一个小动画所在所在时间范围内的属性变换速率;

  animation-delay:定义在浏览器开始执行动画之前的等待的时间、这里是指整个animation执行之前的等待时间,而不是上面所说的多个小动画;

  animation-iteration-count:定义动画的播放次数,通常是整数,默认是1,若为infinity,动画将无限多次的播放;

  animation-direction:主要用来设置动画播放次数,其主要有两个值:normal:默认值,动画每次训话都是按顺序播放;alternate:动画播放在第偶数次向前播放,第奇数次想反方向播放(animation-iteration-count取值大于1时设置有效)

  animation-play-state:属性用来控制元素动画的播放状态。主要有两个值:running:可以通过该值将暂停的动画重新播放,这里的重新播放不是从元素动画的开始播放,而是从暂停的那个位置开始播放;paused:暂停播放。

  animation-fill-mod:默认情况下,动画结束后,元素的样式将回到起始状态,animation-fill-mode属性可以控制动画结束后元素的样式。主要具有四个属性值:none(默认,回到动画没开始时的状态。),forwards(动画结束后动画停留在结束状态),backwords(动画回到第一帧的状态),both(根据animation-direction轮流应用forwards和backwards规则)。

  animation示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<style>
        .box{height:100px;width:100px;border:15px solid black;
            animation: changebox 10s ease-in-out   3 alternate paused;
            }
        .box:hover{
            animation-play-state: running;
        }
        @keyframes changebox {
            10% {  background:red;  }
            50% {  width:80px;  }
            70% {  border:15px solid yellow;  }
            100% {  width:180px;  height:180px;  }
        }
</style>
<body>
 <div class="box"></div>
</body>

11.事件冒泡的事件捕获

  事件冒泡,事件会从最内层的元素开始发生,一直向上传播,直到document对象;

  事件捕获则跟事件冒泡相反,事件会从document对象开始发生,直到最具体的元素;

12.GET和POST的区别

  1.发送方式:GET请求数据放在url上,即HTTP的协议头中;而POST把数据放在HTTP的包体中。

  2.大小的限制:GET传的参数有长度的限制,因为浏览器对url的长度有限制;而POST理论上是没有限制的。

  3.安全性:GET请求可被缓存,请求保存在浏览器的历史记录中;POST则不能被缓存。与POST相比,GET的安全性较差,因为发送的数据是URL的一部分。

13.var的变量提升的底层原理是什么?

  JS引擎的工作方式是

  1)先解析代码,获取所有被声明的变量;

  2)然后再执行。

  也就是分为预处理和执行这两个阶段。

  变量提升:所有用var声明变量的语句都会被提升到代码头部。另外function也可看作变量声明,也存在变量提升的情况。

14.垂直水平居中的方式?

  1)定位

  父元素设置为:position:relative;

  子元素设置为:position:absolute;

  距上50%,据左50%,然后减去元素自身宽度的距离就可以实现

1
2
3
4
5
6
width: 100px;
height: 100px;
position: absolute;
left: 50%;
top: 50%;
margin: -50px 0 0 -50px;

2)flex布局

1
2
3
display: flex; //flex布局
justify-content: center; //使子项目水平居中
align-items: center; //使子项目垂直居中

3)tabel-cell

1
2
3
display: table-cell;
vertical-align: middle;//使子元素垂直居中
text-align: center;//使子元素水平居中

15.如何判断一个对象是否为数组

  1)Array.prototype.isPrototypeOf(obj)方法,判定Array是不是在obj的原型链中,如果是,则返回true,否则false;

  2)objinstanceofArray;

  3)Object.prototype.toString.call(obj);(==="[objectArray]")

  4)Array.isArray(obj);

16.行内元素和块级元素有哪些?img属于什么元素?

1)块元素(block element)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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 - 非排序列表

2)内联元素(inline element)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
a - 锚点
abbr - 缩写
acronym - 首字
b - 粗体(不推荐)
bdo - bidi override
big - 大字体
br - 换行
cite - 引用
code - 计算机代码(在引用源码的时候需要)
dfn - 定义字段
em - 强调
font - 字体设定(不推荐)
i - 斜体
img - 图片
input - 输入框
kbd - 定义键盘文本
label - 表格标签
q - 短引用
s - 中划线(不推荐)
samp - 定义范例计算机代码
select - 项目选择
small - 小字体文本
span - 常用内联容器,定义文本内区块
strike - 中划线
strong - 粗体强调
sub - 下标
sup - 上标
textarea - 多行文本输入框
tt - 电传文本
u - 下划线
var - 定义变量

3)可变元素

1
2
3
4
5
6
7
8
9
可变元素为根据上下文语境决定该元素为块元素或者内联元素。
applet - java applet
button - 按钮
del - 删除文本
iframe - inline frame
ins - 插入的文本
map - 图片区块(map)
object - object对象
script - 客户端脚本

  img、input属于行内替换元素。height/width/padding/margin均可用。效果等于块元素。

17.margin塌陷?

  当两个盒子在垂直方向上设置margin值时,会出现塌陷现象

  解决方法:

  1.给父盒子添加border

  2.给父盒子添加padding-top

  3.给父盒子添加overflow:hidden

  4.父盒子:position:fixed

  5.父盒子:display:table

  6.给子元素的前面添加一个兄弟元素 属性为:content:""; overflow:hidden;

  解决方法的主要原理就是设置盒子为BFC

  BFC为页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。

18.伪类与伪元素的区别

  1)伪类

  伪类用于选择DOM树之外的信息,或是不能用简单选择器进行表示的信息。前者包含那些匹配指定状态的元素,比如:link,:visited,:hover,:active;后者包含那些满足一定逻辑条件的DOM树中的元素,比如:first-child,:first-of-type,:target。

  2)伪元素

  伪元素为DOM树没有定义的虚拟元素。不同于其他选择器,它不以元素元素为最小选择单元,它选择的是元素制定单元。比如::before表示选择元素内容的之前内容;::selection表示选择元素被选中的内容。

  3)伪类/伪元素一览表

  <伪类如下>

1
2
3
4
5
6
7
8
9
10
11
:active      选择正在被激活的元素
:hover         选择被鼠标悬浮着元素
:link        选择未被访问的元素
:visited     选择已被访问的元素
:first-child 选择满足是其父元素的第一个子元素的元素    
:lang         选择带有指定 lang 属性的元素
:focus       选择拥有键盘输入焦点的元素
:enable      选择每个已启动的元素
:disable     选择每个已禁止的元素
:checked     选择每个被选中的元素    
:target      选择当前的锚点元素

<伪元素如下>

1
2
3
4
5
::first-letter    选择指定元素的第一个单词
::first-line      选择指定元素的第一行
::after           在指定元素的内容后面插入内容
::before          在指定元素的内容前面插入内容
::selection       选择指定元素中被用户选中的内容

19.介绍一下JS的基本数据类型

1
Undefined,Null,Boolean,Number,String

20.JavaScript的typeof返回那些数据类型

1
undefined,string,boolean,number,symbol(ES6)object,function

21.介绍一下JS有哪些内置对象?

  数据封装类对象:Object、Array、Boolean、Number、String

  其他对象:Function、Argument、Math、Date、RegExp、Error

22。null和undefined的区别

  1)null表示一个对象被定义了,值为“空值”;undefined表示不存在这个值。

  2)变量被定义了,但是没有赋值时,就等于undefined。

  3)注意:在验证null时,要用===,因为==无法区分null和undefined。

  typeofnull//"object"说明:null是一个没有任何属性和方法的对象

23.对JSON的了解

  1)JSON(JavaScriptObjectNotation)是一种轻量级的数据交换格式。

  2)它是基于JavaScript的一个子集。数据格式简单,易于读写,占用带宽小。如:{"age":"12","name":"back"}

24.列举3种强制类型转换和2种隐式类型转换

  强制:parseInt(),parseFloat(),Number(),(Boolean(),String())

  隐式:==,!

25.input的type属性有哪些?

  text:文本框

  password:密码

  radio:单选按钮

  checkbox:复选框

  file:文件选择域

  hidden:隐藏域

  button:按钮

  reset:重置按钮

  submit:表单提交按钮

  image:图片按钮

26.IE和标准下有哪些兼容性的写法

1
2
3
var ev = ev || window.event
document.documentElement.clientWidth || document.body.clientWidth
var target = ev.srcElement||ev.target

27.如何阻止事件冒泡

  ie:阻止冒泡ev.cancelBubble=true;

  非IEev.stopPropagation();

28.如何阻止默认事件

1)return false;

2) ev.preventDefault();

29.说说前端中的事件流

  事件流描述的是从页面接收事件的顺序,DOM2级事件流包括下面几个阶段。

  事件捕获阶段

  处理事件阶段

  事件冒泡阶段

  (addEventListener:addEventListener是DOM2级事件新增的指定事件处理程序的操作,这个方法接收3个参数:要处理的事件名,作为事件处理程序的函数和一个布尔值。最后的布尔值如果为true,表示在捕获阶段调用事件处理程序;如果为false,表示在冒泡阶段调用事件处理程序,默认为false)

30.如何实现一个自适应的正方形

  1)CSS3vw单位

  CSS3中新增了一组相对于可视区域百分比的长度单位vw、vh、vmin、vmax。其中vw是相对于视口宽度百分比的单位,1vw=1%viewportwidth,vh是相对于视口高度百分比的单位,1vh=1%viewportheight;vmin是相对于当前视口宽高中较小的一个的百分比单位,同理vmax是相对当前视口宽高中较大的一个百分比单位。之前也写过相关文章,大家可以查看《视口百分比长度vh、vw、vi、vb、vmin、vmax单位的了解

  代码实现:

1
2
3
4
.placeholder{
  width: 50vw;
  height: 50vw;
}

  优点:简洁方便

  缺点:浏览器兼容不好

  2)设置垂直方向的padding撑开容器

  margin、padding的百分比数值是相对于父元素宽度计算的。由此可以发现只需要将元素垂直方向的padding值设定为与width相同的百分比就可以制作出自适应正方形了:

  代码实现:

1
2
3
4
.placeholder{
  width: 100%;
  padding-bottom:100%;
}

如果正方形中没有内容(相当于只是一个几何里面的正方形,并没有展示其他任何内容),一切看起来都很正常;但是,如果正方形中有其他内容(这种情况会更常见一些,比如说有一些文本和图片),此时容器的高度就会被拉伸,因为盒子模型中的padding是不包含在content中的,所以我们可以通过height:0解决这个问题;这种方案简洁明了,且兼容性好;但是除了填充内容后会出现问题以外,还有可能碰上max-height不收缩,于是第三种方案来了:

3)利用伪元素的margin(padding)-top撑开容器

在方案二中,我们利用百分比数值的padding-bottom属性撑开容器内部空间,但是这样做会导致在元素上设置的max-height属性失效;而失效的原因是max-height属性只限制于height,也就是只会对元素的contentheight起作用。那么我们是不是能用一个子元素撑开content部分的高度,从而使max-height属性生效呢?我们来试试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
.placeholder {
    width: 20%;
    background-color: #000;
    /* overflow: hidden; */
    /* display: inline-block; */
    float: left;
    /*设置成BFC才能使margin-top撑起高度*/
}
.placeholder:after {
    content: '';
    display: block;
    margin-top: 100%;
    /* margin 百分比相对父元素宽度计算 */
}

31.js中的位置关系

js中的位置关系

  offsetParent:该属性返回一个对象的引用,这个对象是距离调用offsetParent的元素最近的(在包含层次中最靠近的),已进行过CSS定位的容器元素。如果这个容器元素未进行CSS定位,则offsetParent属性的取值为body元素的引用。当容器元素的style.display被设置为"none"时(译注:IE和Opera除外),offsetParent属性返回null。

  top:该属性一般对用过css定位的元素有效(position为“static”时为auto,不产生效果),定义了一个top属性有效的元素(即定位元素)的上外边距边界与其包含块上边界之间的偏移。

  clientTop:元素上边框的厚度,当没有指定边框厚底时,一般为0。

  scrollTop:位于对象最顶端和窗口中可见内容的最顶端之间的距离,简单地说就是滚动后被隐藏的高度。

  offsetTop:获取对象相对于由offsetParent属性指定的父坐标(css定位的元素或body元素)距离顶端的高度。

  clientHeight:内容可视区域的高度,也就是说页面浏览器中可以看到内容的这个区域的高度,一般是最后一个工具条以下到状态栏以上的这个区域,与页面内容无关。

  scrollHeight:IE、Opera认为scrollHeight是网页内容实际高度,可以小于clientHeight。FF认为scrollHeight是网页内容高度,不过最小值是clientHeight。

  offsetHeight:获取对象相对于由offsetParent属性指定的父坐标(css定位的元素或body元素)的高度。IE、Opera认为offsetHeight=clientHeight+滚动条+边框。FF认为offsetHeight是网页内容实际高度,可以小于clientHeight。offsetHeight在新版本的FF和IE中是一样的,表示网页的高度,与滚动条无关,chrome中不包括滚动条。

*诸如left、clientLeft、offsetLeft、clientWidth、scrollWidth等,和top、height类似,不再赘述。

  clientX、clientY:相对于浏览器窗口可视区域的X,Y坐标(窗口坐标),可视区域不包括工具栏和滚动条。IE事件和标准事件都定义了这2个属性。

  pageX、pageY:类似于event.clientX、event.clientY,但它们使用的是文档坐标而非窗口坐标。这2个属性不是标准属性,但得到了广泛支持。IE事件中没有这2个属性。

  offsetX、offsetY:相对于事件源元素(target或srcElement)的X,Y坐标,只有IE事件有这2个属性,标准事件没有对应的属性。

  screenX、screenY:相对于用户显示器屏幕左上角的X,Y坐标。标准事件和IE事件都定义了这2个属性

32.Doctype作用? 严格模式与混杂模式如何区分?它们有何意义?

Doctype声明于文档最前面,告诉浏览器以何种方式来渲染页面,这里有两种模式,严格模式和混杂模式。

严格模式的排版和JS运作模式是以该浏览器支持的最高标准运行。

混杂模式,向后兼容,模拟老式浏览器,防止浏览器无法兼容页面。

33.link标签和import标签的区别?

  link属于html标签,而@import是css提供的

  页面被加载时,link会同时被加载,而@import引用的css会等到页面加载结束后加载。

  link是html标签,因此没有兼容性,而@import只有IE5以上才能识别。

  link方式样式的权重高于@import的。

34.元素的文本省略号?

单行:

1
2
3
overflow:hidden;
text-overflow:ellipsis;
white-space:nowrap

  多行:

  1)直接用css属性设置(只有-webkit内核才有作用)

1
2
3
4
display: -webkit-box
-webkit-box-orient:vertical
-webkit-line-clamp:3
overflow:hidden

  移动端浏览器绝大部分是WebKit内核的,所以该方法适用于移动端;

  -webkit-line-clamp用来限制在一个块元素显示的文本的行数,这是一个不规范的属性(unsupportedWebKitproperty),它没有出现在CSS规范草案中。

  display:-webkit-box将对象作为弹性伸缩盒子模型显示。

  -webkit-box-orient设置或检索伸缩盒对象的子元素的排列方式。

  text-overflow:ellipsis以用来多行文本的情况下,用省略号“…”隐藏超出范围的文本。

2)利用伪类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<style>
#txt{
  display: inline-block;
  height: 40px;
  width: 250px;
  line-height: 20px;
  overflow: hidden;
  font-size: 16px;
}
.t:after{
  display: inline;
  content: "...";
  font-size: 16px;
   
}
</style>
<div id="con">
  <span id="txt">文本溢出显示省略号,文本溢出显示省略号,文本溢出显示省略号,文本溢出显示省略</span>
  <span class="t"></span>
</div>

这种方法的缺点就是内容不足以超过位置的时候,还是会有…

35.XML和JSON的区别?

  1)数据体积方面

  JSON相对于XML来讲,数据的体积小,传递的速度更快些

  2)数据描述方面

  JSON和JavaScript交互更加方便,更容易解析处理,更容易交互

  3)数据描述方面

  JSON对数据的描述性比XML差

  4)传输速度方面

  JSON的速度要远远快于XML

36.前端需要注意哪些SEO?

  合理的title、description、keywords:搜索对着三项的权重逐个减少,title值强调重点即可,重要关键词不要超过两次,而且要靠前,不同页面的title要有所不同;

  description把页面的内容高度概括,长度合适,不可过分分堆砌关键词,不同页面的description有所不同;

  keywords列举重要关键词即可;

1
2
3
4
5
6
// title标题
<title>标题</title>
// keywords 关键词
<meta name="description" content="关键词1,关键词2,关键词3">
// description 内容摘要
<meta name="description" content="网页的简述">

  语义化的HTML代码,符合W3C规范:语义化代码让搜索引擎容易理解网页;

  重要内容的HTML代码放在最前:搜索引擎抓取HTML顺序是从上到下,有的搜索引擎对抓取长度有限制,所以要保证重要内容一定会被抓取;

  重要内容不要用JS输出:爬虫不会执行JS获取内容;

  少用iframe:搜索引擎不会抓取iframe中的内容;

  非装饰性图片必须加alt;

  提高网站速度:网站速度是搜素引擎排序的一个重要指标;

37.HTTP的几种请求方法用途?

  1)GET方法

  发送一个请求来取得服务器上的某一资源

  2)POST方法

  向URL指定的资源提交数据或附加新的数据

  3)PUT方法

  跟POST方法很像,也是想服务器提交数据。但是,它们之间有不同。PUT指定了资源在服务器上的位置,而POST没有

  4)HEAD方法

  只请求页面的首部

  5)DELETE方法

  删除服务器上的某资源

  6)OPTIONS方法

  它用于获取当前URL所支持的方法。如果请求成功,会有一个Allow的头包含类似“GET,POST”这样的信息

  7)TRACE方法

  TRACE方法被用于激发一个远程的,应用层的请求消息回路

  8)CONNECT方法

  把请求连接转换到透明的TCP/IP通道

38.如何进行网页性能优化?

  1)content方面

  减少HTTP请求:合并文件、CSS精灵图

  减少DNS查询:DNS缓存、将资源分布到恰当数量的主机名

  减少DOM元素数量

  2)Server方面

  使用CDN

  配置ETag

  对组件使用Gzip压缩

  3)Cookie方面

  减少cookie大小

  4)CSS方面

  将样式表放到页面顶部

  不使用CSS表达式

  使用不使用@import

  5)JavaScript方面

  将脚本放到页面底部

  将JavaScript和CSS从外部引入

  压缩JavaScript和CSS

  删除不需要的脚本

  减少DOM访问

  6)图片方面

  优化CSS精灵

  不要再HTML中拉伸图片

39.语义化的理解

  HTML语义化就是让页面的内容结构化,便于对浏览器、搜索引擎解析;

  在没有CSS样式情况下也以一种文档格式显示,并且是容易阅读的;

  搜索引擎的爬虫依赖于标记来确定上下文的各个关键字的权重,利于SEO;

  使阅读源代码的人更容易将网站分块,便于阅读维护理解;

40.WEB标准以及W3C标准是什么

  标签闭合、标签小写、不乱嵌套、使用外链CSS和JS、结构行为表现的分离

41.说说对作用域链的理解

  作用域链的作用是保证执行环境里有权访问的变量和函数是有序的,作用域链的变量只能向上访问,变量访问到window对象即被终止,作用域链向下访问变量是不被允许的;

  即作用域就是变量与函数的可访问范围,即作用域控制这变量与函数的可见性和生命周期;

42.如何实现瀑布流

  1)瀑布流布局的要求要进行布置的元素等宽;

  然后计算元素的宽度,

  与浏览器宽度之比,得到需要布置的列数;

  2)创建一个数组,长度为列数,

  里面的值为以已布置元素的总高度(最开始为0);

  3)然后将未布置的元素的依次布置到高度最小的那一列,

  就得到了瀑布流布局;

  4)滚动加载,scroll事件得到scrollTop,

  与最后盒子的offsetTop对比,

  符合条件就不断滚动加载。

  瀑布流布局核心代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
/**
 * 实现瀑布流的布局
 * @param {string}parentBox
 * @param {string}childBox
 */
function waterFull(parentBox, childBox) {
    // 1. 求出父盒子的宽度
    //  1.1 获取所有的子盒子
    var allBox = $(parentBox).
         getElementsByClassName(childBox);
    // console.log(allBox);

    // 1.2 求出子盒子的宽度
    var boxWidth = allBox[0].offsetWidth;
    // console.log(boxWidth);

    // 1.3 获取窗口的宽度
    var clientW = document.
        documentElement.clientWidth;
    // console.log(clientW);

    // 1.4 求出总列数
    var cols = Math.floor(clientW / boxWidth);
    // console.log(cols);

    // 1.5 父盒子居中
    $(parentBox).style.width = cols * boxWidth + 'px';
    $(parentBox).style.margin = '0 auto';

    // 2. 子盒子定位
    //  2.1 定义变量
    var heightArr = [], boxHeight = 0,
        minBoxHeight = 0, minBoxIndex = 0;

    // 2.2 遍历所有的子盒子
    for (var i = 0; i < allBox.length; i++) {
        // 2.2.1 求出每一个子盒子的高度
        boxHeight = allBox[i].offsetHeight;
        // console.log(boxHeight);
        // 2.2.2 取出第一行盒子的高度放入高度数组中
        if (i < cols) { // 第一行
            heightArr.push(boxHeight);
        } else { // 剩余行的盒子
            // 2.2.3 取出数组中最矮的高度
            minBoxHeight = _.min(heightArr);
            // 2.2.4 求出最矮高度对应的索引
            minBoxIndex = getMinBoxIndex(heightArr, minBoxHeight);
            // 2.2.5 盒子定位
            allBox[i].style.position = 'absolute';
            allBox[i].style.left = minBoxIndex * boxWidth + 'px';
            allBox[i].style.top = minBoxHeight + 'px';
            // 2.2.6 更新最矮的高度
            heightArr[minBoxIndex] += boxHeight;

        }
    }
}

/**
 * 根据内容取出在数组中对应的索引
 * @param {object}arr
 * @param {number}val
 * @returns {boolean}
 */

function getMinBoxIndex(arr, val) {
    for (var i = 0; i < arr.length; i++) {
        if (arr[i] === val) return i;
    }
}

/**
 * 判断是否具备加载子盒子的条件
 * @returns {boolean}
 */
function checkWillLoadImage() {
    // 1. 获取最后一个盒子
    var allBox = $('main').getElementsByClassName('box');
    var lastBox = allBox[allBox.length - 1];

    // 2. 求出高度
    var lastBoxDis = lastBox.offsetHeight * 0.5 + lastBox.offsetTop;

    // 3. 求出窗口的高度
    var clientH = document.documentElement.clientHeight;

    // 4. 求出页面滚动产生的高度
    var scrollTopH = scroll().top;

    // 5. 对比
    return lastBoxDis <= clientH + scrollTopH;
}

43.原生JS都有哪些方式可以实现两个页面间的通信?

  1)通过url地址栏传递参数;

  例如:点击列表中的每一条数据,跳转到一个详情页面,在URL中传递不同的参数区分不同的页面;

  2)通过本地存储cookie、localStorage、sessionStorage;

  例如京东的登陆,把登陆后获得的页面信息存储到本地,其他页面需要用户信息的话就从本地的存储数据中获取;

  3)使用iframe

  例如在A页面中嵌入B页面,在A中可以通过一些属性和实现方法和B页面的通信;

  4)利用postMessage实现页面间的通信

  例如父窗口往子窗口传递信息,子窗口往父窗口传递信息

44.ES6中的let,const,var的区别是什么?

  var:声明全局变量;

  let:声明块级变量,即局部变量,定以后可以修改;

  const:用于声明常量,定义后不能再修改值或者引用值的常量,也具有块级作用域;

45.对数组进行去重,es5或者es6方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
//es5四种方式:

//方式一:
Array.prototype.unique1 = function() {
    // 1. 定义数组
    var temp = [];
    // 2. 遍历当前数组
    for(var i = 0; i < this.length; i++) {
        // 3.如果当前数组的第i已经保存进了临时数组,
        // 那么跳过,否则把当前项push到临时数组里面
        if (-1 === temp.indexOf(this[i])) {
            temp.push(this[i]);
        }
    }
    return temp;
};

//方式二:
Array.prototype.unique2 = function() {
    //1. hash为hash表,r为临时数组
    var hash = {}, temp=[];
    // 2.遍历当前数组
    for(var i = 0; i < this.length; i++)
    {
        // 3. 如果hash表中没有当前项
        if (!hash[this[i]])
        {
            // 4.存入hash表
            hash[this[i]] = true;
            // 5.把当前数组的当前项
            // push到临时数组里面
            temp.push(this[i]);
        }
    }
    return temp;
};

//方式三:
Array.prototype.unique3 = function() {
    var n = [this[0]];
    for(var i = 1; i < this.length; i++){
        if (this.indexOf(this[i]) === i) {
            n.push(this[i]);
        }
    }
    return n;
};

//方式四:
Array.prototype.unique4 = function() {
    this.sort();
    var re=[this[0]];
    for(var i = 1; i < this.length; i++)
    {
        if( this[i] !== re[re.length-1])
        {
            re.push(this[i]);
        }
    }
    return re;
};

//es6实现方式:

Array.prototype.unique =
Array.prototype.unique
|| function () {
    return [...new Set(this)];
};

46.页面加载过程中可能触发哪些事件?它们的顺序是?

  页面加载时,大致可以分为以下几个步骤:

  1)开始解析HTML文档结构

  2)加载外部样式表及JavaScript脚本

  3)解析执行JavaScript脚本

  4)DOM树渲染完成

  5)加载未完成的外部资源(如图片)

  6)页面加载成功

  执行顺序:

  1)documentreadystatechange事件

  2)documentDOMContentLoaded事件

  3)windowload事件

47.什么是CDN,CDN对于网络有什么意义,它有什么的缺点?

  CDN又称为内容分发网络;本意在于尽可能避开互联网上有可能影响数据传输速度和稳定性的瓶颈和环节,使内容传输的更快、更稳定。

  主要目的:解决因分布、带宽、服务器性能带来的访问延迟问题,适用于站点的加速、点播、直播等场景。使用户就近取得所需内容,解决Internet网络拥挤的状况,提高用户访问网站的响应速度和成功率。

  缺点:

  1)实施复杂,投资大

  2)目前大部分的CDN还只是对静态的内容加速,对动态加速效果不好;而双线对动态加速的效果跟静态是一样的。

48.vue-router中$route和$router的区别?

  1)$route为当前router跳转对象里面可以获取name、path、query、params等

  2)$router为VueRouter实例,想要导航到不同URL,则使用$router.push方法

  返回上一个history也是使用$router.go方法

49.vue路由传参query与params两种方式的区别

query要用path来引入,例如ths.$router.push({ path:"detail",query:{id:"00"}}),接收参数为this.$route.query.id,params要用name来引入,例如ths.$router.push({ name:"detail",params:{id:"00"}}),接收参数为this.$route.params.id。以query传输的参数会在类似于get传参,在浏览器地址栏中显示参数。

50.描述一下渐进增强和优雅降级

  优雅降级(gracefuldegradation):一开始就构建站点的完整功能,然后针对浏览器测试和修复。

  渐进增强(progressiveenhancement):一开始只构建站点的最少特性,然后不断针对各浏览器追加功能。

51.为什么利用多个域名来请求网络资源会更有效?

  动静分离请求,使用不同的服务器处理请求,提高效率;

  突破浏览器的并发限制,同一时间针对同一域名下的请求有一定的数量限制。

  节约主域名的连接数,从而提高客户端网络带宽的利用率,优化页面响应。

52.HTML5有哪些新特性、移除了哪些元素?

  1)绘画标签canvas;

  2)用于媒介回放的video和audio元素;

  3)本地离线存储localStorage长期存储数据,浏览器关闭后数据不丢失;

  4)sessionStorage的数据在浏览器关闭后自动删除;

  5)语义化更好的内容元素,比如article、footer、header、nav、section;

  6)表单控件,calendar、data、time、email、url、search;

  7)webworker、websocket、Geolocation;

  移除的元素:

  1)纯表现的元素:basefont、big、center、font、s、strike、tt

  2)对可用性产生负面影响的元素:frame、frameset、noframes

53.display:none;与visibility:hidden;的区别?

  相同点:它们都能让元素不可见‘

  不同点:

  display:none;会让元素完全从渲染树中消失,渲染的时候不占据任何空间;

  visibility:hidden;不会让元素从渲染树消失,渲染元素继续占据空间,只是内容不可见;

  display:none;是非继承属性,子孙节点的消失由于元素从渲染树消失造成,通过修改子孙节点属性无法显示;

  visibility:hodden;是继承属性,子孙节点的消失由于继承了hidden,通过设置visibility:visible;可以让子孙节点显示;

  修改常规流中元素的display通常会造成文档重排。修改visibility属性只会造成本元素的重绘;

  读屏器不会读取display:none;元素内容;会读取visibility:hidden;元素内容;

54.CSS去掉inline-block元素间隙的几种方法?

  间隙是怎么来的:间隙是由换行或者回车导致的;只要把标签写成一行或者标签没有空格,就不会出现间隙;

  去除方法:

  方法一:

  元素间的间隙出现的原因,是元素标签之间的空格,把空格去掉间隙就会消失

1
2
3
<div class="itlike">
  <span>lhh</span><span>lhh</span>
</div>

  方法二:

  利用HTML注释标签

1
2
3
4
<div class="demo">
    <span>lhh</span><!--
    --><span>lhh</span>
</div>

  方法三:

  取消标签闭合

1
2
3
4
5
6
<div class="demo">
    <span>lhh
    <span>lhh
    <span>lhh
    <span>lhh
</div>

  方法四:

  在父容器上使用font-size:0;可以消除间隙

1
2
3
4
5
6
7
<div class="demo">
    <span>lhh</span>
    <span>lhh</span>
    <span>lhh</span>
    <span>lhh</span>
</div>
.demo {font-size: 0;}

55.input标签的type种类

button、checkbox、file、hidden、image、password、radio、reset、submit、text

56.apply,call,bind有什么区别?

  三者都可以把一个函数应用到其他对象上,apply,call是直接执行函数调用,bind是绑定,执行需要再次调用。

  apply和call的区别是apply接受数组作为参数,而call是接受逗号分隔的无限多个参数列表。

  代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function Person() {
    }
    Person.prototype.sayName() { alert(this.name); }

    var obj = {name: 'michaelqin'}; // 注意这是一个普通对象,它不是Person的实例
    // 1) apply
    Person.prototype.sayName.apply(obj, [param1, param2, param3]);

    // 2) call
    Person.prototype.sayName.call(obj, param1, param2, param3);

    // 3) bind
    var liaoke = Person.prototype.sayName.bind(obj);    
    liaoke ([param1, param2, param3]); // bind需要先绑定,再执行
    liaoke (param1, param2, param3); // bind需要先绑定,再执行

57.介绍一下defineProperty,hasOwnProperty, propertyIsEnumerable

  Object.defineProperty(obj,prop,descriptor)用来给对象定义属性,有value,writeable,enumerable,set/get,configurable,

  hasOwnProperty用于检查某一属性是不是存在于对象本身,

  propertyIsEnumerable用来检测某一属性是否可遍历,也就是能不能用for…in循环来取到。

58.JS常用设计模式的实现思路(单例、工厂、代理、装饰、观察者模式等)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
// 1) 单例: 任意对象都是单例,无须特别处理
    var obj = {name: 'michaelqin', age: 30};

 // 2) 工厂: 就是同样形式参数返回不同的实例
    function Person() { this.name = 'Person1'; }
    function Animal() { this.name = 'Animal1'; }

    function Factory() {}
    Factory.prototype.getInstance = function(className) {
        return eval('new ' + className + '()');
    }

    var factory = new Factory();
    var obj1 = factory.getInstance('Person');
    var obj2 = factory.getInstance('Animal');
    console.log(obj1.name); // Person1
    console.log(obj2.name); // Animal1

 // 3) 代理: 就是新建个类调用老类的接口,包一下
    function Person() { }
    Person.prototype.sayName = function() { console.log('michaelqin'); }
    Person.prototype.sayAge = function() { console.log(30); }

    function PersonProxy() {
        this.person = new Person();
        var that = this;
        this.callMethod = function(functionName) {
            console.log('before proxy:', functionName);
            that.person[functionName](); // 代理
            console.log('after proxy:', functionName);
        }
    }

    var pp = new PersonProxy();
    pp.callMethod('sayName'); // 代理调用Person的方法sayName()
    pp.callMethod('sayAge'); // 代理调用Person的方法sayAge()

  // 4) 观察者: 就是事件模式,比如按钮的onclick这样的应用.
    function Publisher() {
        this.listeners = [];
    }
    Publisher.prototype = {
        'addListener': function(listener) {
            this.listeners.push(listener);
        },

        'removeListener': function(listener) {
            delete this.listeners[listener];
        },

        'notify': function(obj) {
            for(var i = 0; i &lt; this.listeners.length; i++) {
                var listener = this.listeners[i];
                if (typeof listener !== 'undefined') {
                    listener.process(obj);
                }
            }
        }
    }; // 发布者

    function Subscriber() {

    }
    Subscriber.prototype = {
        'process': function(obj) {
            console.log(obj);
        }
    }; // 订阅者

    var publisher = new Publisher();
    publisher.addListener(new Subscriber());
    publisher.addListener(new Subscriber());
    publisher.notify({name: 'michaelqin', ageo: 30}); // 发布一个对象到所有订阅者
    publisher.notify('2 subscribers will both perform process'); // 发布一个字符串到所有订阅者

59.处理字符串常用的十个函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
charAt()   // 返回在指定位置的字符。
concat()   // 连接字符串。
fromCharCode()   // 从字符编码创建一个字符串。
indexOf()  // 检索字符串。
match()   // 找到一个或多个正则表达式的匹配。
replace()   // 替换与正则表达式匹配的子串。
search()   // 检索与正则表达式相匹配的值。
slice()   // 提取字符串的片断,并在新的字符串中返回被提取的部分。
split()   // 把字符串分割为字符串数组。
substr()   // 从起始索引号提取字符串中指定数目的字符。
substring()   // 提取字符串中两个指定的索引号之间的字符。
toLocaleLowerCase()   // 把字符串转换为小写。
toLocaleUpperCase()   // 把字符串转换为大写。
toLowerCase()   // 把字符串转换为小写。
toUpperCase()   // 把字符串转换为大写。
toString()   // 返回字符串。
valueOf()   // 返回某个字符串对象的原始值。

60.如何判断一个变量是对象还是数组

1
2
3
4
5
6
7
8
9
10
11
function isObjArr(variable){
     if (Object.prototype.toString.call(value) === "[object Array]") {
            console.log('value是数组');
       }else if(Object.prototype.toString.call(value)==='[object Object]'){//这个方法兼容性好一点
            console.log('value是对象');
      }else{
          console.log('value不是数组也不是对象')
      }
}

// 注意:千万不能使用typeof来判断对象和数组,因为这两种类型都会返回"object"

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

  ES5的继承是通过prototype或构造函数机制来实现。

  ES5的继承实质上是先创建子类的实例对象,然后再将父类的方法添加到this上(Parent.apply(this))。

  ES6的继承机制实质上是先创建父类的实例对象this(所以必须先调用父类的super()方法),然后再用子类的构造函数修改this。具体为ES6通过class关键字定义类,里面有构造方法,类之间通过extends关键字实现继承。子类必须在constructor方法中调用super方法,否则新建实例报错。因为子类没有自己的this对象,而是继承了父类的this对象,然后对其调用。如果不调用super方法,子类得不到this对象。

注意:super关键字指代父类的实例,即父类的this对象。在子类构造函数中,调用super后,才可使用this关键字,否则报错。

62.下面的ul,如何点击每一列的时候alert其index?(闭包)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<ul id="test">
 <li>这是第一条</li>
 <li>这是第二条</li>
 <li>这是第三条</li>
 </ul>

// 方法一:
var lis=document.getElementById('test').getElementsByTagName('li');
for(var i=0;i<3;i++)
{
lis[i].index=i;
lis[i].onclick=function(){
alert(this.index);
};
}

//方法二:
var lis=document.getElementById('test').getElementsByTagName('li');
for(var i=0;i<3;i++)
{
lis[i].index=i;
lis[i].onclick=(function(a){
return function() {
alert(a);
}
})(i);
}

63.对于MVVM的理解

  MVVM是Model-View-ViewModel的缩写。

  Model代表数据模型,也可以在Model中定义数据修改和操作的业务逻辑。

  View代表UI组件,它负责将数据模型转化成UI展现出来。

  ViewModel监听模型数据的改变和控制视图行为、处理用户交互,

  简单理解就是一个同步View和Model的对象,连接Model和View。

  在MVVM架构下,View和Model之间并没有直接的联系,

  而是通过ViewModel进行交互,Model和ViewModel之间的交互是双向的,

  因此View数据的变化会同步到Model中,而Model数据的变化也会立即反应到View上。

  ViewModel通过双向数据绑定把View层和Model层连接了起来,

  而View和Model之间的同步工作完全是自动的,无需人为干涉,

  因此开发者只需关注业务逻辑,不需要手动操作DOM,

  不需要关注数据状态的同步问题,

  复杂的数据状态维护完全由MVVM来统一管理。

64.解释Vue的生命周期

Vue实例从创建到销毁的过程,就是生命周期。从开始创建、初始化数据、编译模板、挂载Dom->渲染、更新->渲染、销毁等一系列过程,称之为Vue的生命周期。

  Vue的生命周期包括:

  beforeCreate(创建前)在数据观测和初始化事件还未开始,

  created(创建后)完成数据观测,属性和方法的运算,初始化事件,$el属性还没有显示出来;

  beforeMount(载入前)在挂载开始之前被调用,相关的render函数首次被调用,实例已完成以下的配置:编译模板,把data里面的数据和模板生成html,注意此时还没有挂载html到页面上;

  mounted(载入后)在el被新创建的vm.$el替换,并挂载到实例上去之后调用,实例已完成以下配置:用上面编译好的html内容替换el属性指向的DOM对象,完成模板中的html渲染到html页面中,此过程中进行ajax交互。

  beforeUpdate(更新前)在数据更新之前调用,发生在虚拟DOM重新渲染和打补丁之前,可以在该钩子中进一步地更改状态,不会触发附加的重渲染过程。

  updated(更新后)在由于数据更改导致的虚拟DOM重新渲染和打补丁之后调用。调用时,组件DOM已经更新,所以可以执行依赖于DOM的操作。然而在大多数情况下,应该避免在此期间更改状态,因为这可能会导致更新无限循环,该钩子在服务器渲染期间不被调用。

  beforeDestroy(销毁前)在实例销毁之前调用,实例仍然完全可用。

  destroyed(销毁后)在实例销毁之后调用。调用后,所有的事件监听器会被移除,所有的子实例也会被销毁。该钩子在服务器端渲染期间不被调用。

65.为什么使用Node.js,它有哪些优缺点?

  优点:

  事件驱动,通过闭包很容易实现客户端的生命活期。

  不用担心多线程,锁,并行计算的问题

  V8引擎速度非常快

  对于游戏来说,写一遍游戏逻辑代码,前端后端通用

  缺点:

  node.js更新很快,可能会出现版本兼容

  node.js还不算成熟,还没有大制作

  node.js不像其他的服务器,对于不同的链接,不支持进程和线程操作

66.什么是错误优先的回调函数?

  错误优先(Error-first)的回调函数(Error-FirstCallback)用于同时返回错误和数据。

  第一个参数返回错误,并且验证它是否出错;其他参数返回数据。

1
2
3
4
5
6
7
8
9
fs.readFile(filePath, function(err, data)
{
    if (err)
    {
        // 处理错误
        return console.log(err);
    }
    console.log(data);
});

67.使用npm有哪些好处?

  通过npm,你可以安装和管理项目的依赖,

  并且能够指明依赖项的具体版本号。

  对于Node应用开发而言,

  可以通过package.json文件来管理项目信息,

  配置脚本,以及指明依赖的具体版本。

68.在JavaScript源文件的开头包含 use strict 有什么意义和好处?

  sestrict是一种在JavaScript代码运行时自动实行更严格解析和错误处理的方法。(严格模式)

  将值分配给一个未声明的变量会自动创建该名称的全局变量。这是JavaScript中最常见的错误之一。在严格模式下,这样做的话会抛出错误。消除this强制。

  当检测到对象(例如,varobject={foo:"bar",foo:"baz"};)中重复命名的属性,或检测到函数中(例如,functionfoo(val1,val2,val1){})重复命名的参数时,严格模式会抛出错误,因此捕捉几乎可以肯定是代码中的bug可以避免浪费大量的跟踪时间。比eval()更安全。

69.vuejs与angularjs以及react的区别?

  与AngularJS的区别

  相同点:

  都支持指令:内置指令和自定义指令。

  都支持过滤器:内置过滤器和自定义过滤器。

  都支持双向数据绑定。

  都不支持低端浏览器。

  不同点:

  1.AngularJS的学习成本高,比如增加了DependencyInjection特性,而Vue.js本身提供的API都比较简单、直观。

  2.在性能上,AngularJS依赖对数据做脏检查,所以Watcher越多越慢。

  Vue.js使用基于依赖追踪的观察并且使用异步队列更新。所有的数据都是独立触发的。

  对于庞大的应用来说,这个优化差异还是比较明显的。

  与React的区别

  相同点:

  React采用特殊的JSX语法,Vue.js在组件开发中也推崇编写.vue特殊文件格式,对文件内容都有一些约定,两者都需要编译后使用。

  中心思想相同:一切都是组件,组件实例之间可以嵌套。

  都提供合理的钩子函数,可以让开发者定制化地去处理需求。

  都不内置列数AJAX,Route等功能到核心包,而是以插件的方式加载。

  在组件开发中都支持mixins的特性。

  不同点:

  React依赖VirtualDOM,而Vue.js使用的是DOM模板。React采用的VirtualDOM会对渲染出来的结果做脏检查。

  Vue.js在模板中提供了指令,过滤器等,可以非常方便,快捷地操作VirtualDOM。

70.标签keep-alive的作用是什么?

<keep-alive></keep-alive> 包裹动态组件时,会缓存不活动的组件实例,主要用于保留组件状态或避免重新渲染。

71.WeakMap 和 Map 的区别?

  WeakMap结构与Map结构基本类似,唯一的区别是它只接受对象作为键名(null除外),不接受其他类型的值作为键名,而且键名所指向的对象,不计入垃圾回收机制。

  WeakMap最大的好处是可以避免内存泄漏。一个仅被WeakMap作为key而引用的对象,会被垃圾回收器回收掉。

  WeakMap拥有和Map类似的set(key,value)、get(key)、has(key)、delete(key)和clear()方法,没有任何与迭代有关的属性和方法。

72.http和https的基本概念?

  http:超文本传输协议,是互联网上应用最为广泛的一种网络协议,是一个客户端和服务器端请求和应答的标准(TCP),用于从WWW服务器传输超文本到本地浏览器的传输协议,它可以使浏览器更加高效,使网络传输减少。

  https:是以安全为目标的HTTP通道,简单讲是HTTP的安全版,即HTTP下加入SSL层,HTTPS的安全基础是SSL,因此加密的详细内容就需要SSL。

  https协议的主要作用是:建立一个信息安全通道,来确保数组的传输,确保网站的真实性。

73.git fetch和git pull的区别?

  git pull:相当于是从远程获取最新版本并merge到本地

  git fetch:相当于是从远程获取最新版本到本地,不会自动merge

74.介绍一下对浏览器内核的理解?

  主要分成两部分:渲染引擎(layout engineer或Rendering Engine)和JS引擎。

  渲染引擎:负责取得网页的内容(HTML、XML、图像等等)、

  整理讯息(例如加入CSS等),以及计算网页的显示方式,然后会输出至显示器或打印机。

  浏览器的内核的不同对于网页的语法解释会有不同,所以渲染的效果也不相同。

  所有网页浏览器、电子邮件客户端以及其它需要编辑、显示网络内容的应用程序都需要内核。

  JS引擎:解析和执行javascript来实现网页的动态效果。

  最开始渲染引擎和JS引擎并没有区分的很明确,后来JS引擎越来越独立,内核就倾向于只指渲染引擎。

75.什么是微格式

  微格式(Microformats)是一种让机器可读的语义化XHTML词汇的集合,是结构化数据的开放标准。

  是为特殊应用而制定的特殊格式

  优点:将智能数据添加到网页上,让网站内容在搜索引擎结果界面可以显示额外的提示。

76.数据绑定基本的实现

1
2
3
4
5
6
7
8
9
10
11
 // 实现一个方法,可以给 obj 所有的属性添加动态绑定事件,当属性值发生变化时会触发事件
let obj = {
  key_1: 1,
  key_2: 2
}
function func(key) {
  console.log(key + ' 的值发生改变:' + this[key]);
}
bindData(obj, func);
obj.key_1 = 2; // 此时自动输出 "key_1 的值发生改变:2"
obj.key_2 = 1; // 此时自动输出 "key_2 的值发生改变:1"

答案:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function bindData(obj, fn) {
  for (let key in obj) {
    Object.defineProperty(obj, key, {
      set(newVal) {
        if (this.value !== newVal) {
          this.value = newVal;
          fn.call(obj, key);
        }
      },
      get() {
        return this.value;
      }
    })
  }
}

77.数据结构处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
// 有一个祖先树状 json 对象,当一个人有一个儿子的时候,其 child 为其儿子对象,如果有多个儿子,child 为儿子对象的数组。

请实现一个函数,找出这个家族中所有有多个儿子的人的名字(name),输出一个数组。

列子:
// 样例数据
let data = {
  name: 'jack',
  child: [
    { name: 'jack1' },
    {
      name: 'jack2',
      child: [{
        name: 'jack2-1',
        child: { name: 'jack2-1-1' }
      }, {
        name: 'jack2-2'
      }]
    },
    {
      name: 'jack3',
      child: { name: 'jack3-1' }
    }
  ]
}


// 答案:

// 用递归
function findMultiChildPerson(data) {
  let nameList = [];

  function tmp(data) {
    if (data.hasOwnProperty('child')) {
      if (Array.isArray(data.child)) {
        nameList.push(data.name);
        data.child.forEach(child =&gt; tmp(child));
      } else {
        tmp(data.child);
      }
    }
  }
  tmp(data);
  return nameList;
}

// 不用递归
function findMultiChildPerson(data) {
  let list = [data];
  let nameList = [];

  while (list.length &gt; 0) {
    const obj = list.shift();
    if (obj.hasOwnProperty('child')) {
      if (Array.isArray(obj.child)) {
        nameList.push(obj.name);
        list = list.concat(obj.child);
      } else {
        list.push(obj.child);
      }
    }
  }
  return nameList;
}

78.JavaScript如何实现二分法查找?

  二分法查找,也称折半查找,是一种在有序数组中查找特定元素的搜索算法。

  查找过程可以分为以下步骤:

  (1)首先,从有序数组的中间的元素开始搜索,

  如果该元素正好是目标元素(即要查找的元素),则搜索过程结束,否则进行下一步。

  (2)如果目标元素大于或者小于中间元素,

  则在数组大于或小于中间元素的那一半区域查找,然后重复第一步的操作。

  (3)如果某一步数组为空,则表示找不到目标元素。

  代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
// 非递归算法
 function binary_search(arr, key) {
   var low = 0,
   high = arr.length - 1;
   while(low <= high){
   var mid = parseInt((high + low) / 2);
       if(key == arr[mid]){
           return  mid;
       }else if(key > arr[mid]){
           low = mid + 1;
       }else if(key < arr[mid]){
           high = mid -1;
       }else{
           return -1;
        }
   }
};

 var arr = [1,2,3,4,5,6,7,8,9,10,11,23,44,86];
 var result = binary_search(arr,10);
 alert(result); // 9 返回目标元素的索引值

 // 递归算法
 function binary_search(arr,low, high, key) {
     if (low > high){
       return -1;
        }
     var mid = parseInt((high + low) / 2);
      if(arr[mid] == key){
        return mid;
     }else if (arr[mid] > key){
        high = mid - 1;
        return binary_search(arr, low, high, key);
     }else if (arr[mid] < key){
        low = mid + 1;
        return binary_search(arr, low, high, key);
     }
};

 var arr = [1,2,3,4,5,6,7,8,9,10,11,23,44,86];
 var result = binary_search(arr, 0, 13, 10);
 alert(result); // 9 返回目标元素的索引值

79.有一楼梯共M级,刚开始时你在第一级,若每次只能跨上一级或二级,要走上第M级,共有多少种走法?

  这个问题要倒过来看,要到达n级楼梯,只有两种方式,从(n-1)级或(n-2)级到达的。

  所以可以用递推的思想去想这题,假设有一个数组s[n],那么s[1]=1(由于一开始就在第一级,只有一种方法),s[2]=1(只能从s[1]上去没有其他方法)。

  那么就可以推出s[3]~s[n]了。

  下面继续模拟一下,s[3]=s[1]+s[2],

  因为只能从第一级跨两步,或者第二级跨一步。

1
2
3
4
5
6
7
function cStairs(n) {
    if(n === 1 || n === 2) {
        return 1;
    } else {
        return cStairs(n-1) + cStairs(n-2)
    }
}

80.递归设计。 实现一个函数,给该函数一个DOM节点,函数访问其所有子元素(所有子元素,不仅仅是直接子元素),每次访问子元素的时候,并为其传一个callback?

1
2
3
4
5
6
7
8
//访问一个DOM tree,是一个经典的深度优先搜索的算法
function Traverse(DOM,callback) {
    callback(DOM);
    var list = DOM.children;
    Array.prototype.forEach.apply(list,(item)=>{
        Traverse(item,callback); //递归
    })
}

81.介绍一下对webpack的认识?

  WebPack是一个模块打包工具,可以使用WebPack管理模块依赖,并编绎输出模块们所需的静态文件。

  它能够很好地管理、打包Web开发中所用到的HTML、javaScript、CSS以及各种静态文件(图片、字体等),让开发过程更加高效。

  对于不同类型的资源,webpack有对应的模块加载器。webpack模块打包器会分析模块间的依赖关系,最后生成了优化且合并后的静态资源。

  webpack的两大特色:

  1)codesplitting(可以自动完成)

  2)loader可以处理各种类型的静态文件,并且支持串联操作

  webpack是以commonJS的形式来书写脚本,但对AMD/CMD的支持也很全面,方便旧项目进行代码迁移。

  webpack具有requireJs和browserify的功能,但仍有很多自己的新特性:

  1)对CommonJS、AMD、ES6的语法做了兼容

  2)对js、css、图片等资源文件都支持打包

  3)串联式模块加载器以及插件机制,让其具有更好的灵活性和扩展性,例如提供对CoffeeScript、ES6的支持

  4)有独立的配置文件webpack.config.js

  5)可以将代码切割成不同的chunk,实现按需加载,降低了初始化时间

  6)支持SourceUrls和SourceMaps,易于调试

  7)具有强大的Plugin接口,大多是内部插件,使用起来比较灵活

  8)webpack使用异步IO并具有多级缓存。这使得webpack很快且在增量编译上更加快

82.关于HTTP2.0的认识

  HTTP/2引入了“服务端推(serverpush)”的概念,它允许服务端在客户端需要数据之前就主动地将数据发送到客户端缓存中,从而提高性能。

  HTTP/2提供更多的加密支持,HTTP/2使用多路技术,允许多个消息在一个连接上同时交差。

  它增加了头压缩(headercompression),因此即使非常小的请求,其请求和响应的header都只会占用很小比例的带宽。

83.对AMD和Commonjs的理解?

  CommonJS是服务器端模块的规范,nodejs采用了这个规范。

  CommonJS规范加载模块是同步的,也就是说,只有加载完成,才能执行后面的操作。

  AMD规范则是非同步加载模块,允许指定回调函数。

  AMD推荐的风格通过返回一个对象做为模块对象,CommonJS的风格通过对module.exports或exports的

  属性赋值来达到暴露模块对象的目的。

84.mongoDB和MySQL的区别?

  MySQL是传统的关系型数据库,MongoDB则是非关系型数据库

  mongodb以JSON结构(二进制)进行存储,对海量数据存储有着很明显的优势。

  对比传统关系型数据库,NoSQL有着非常显著的性能和扩展性优势,与关系型数据库相比,MongoDB的优点有:

  ①弱一致性(最终一致),更能保证用户的访问速度:

  ②文档结构的存储方式,能够更便捷的获取数据。

85.讲讲304缓存的原理?

  服务器首先产生ETag,服务器可在稍后使用它来判断页面是否已经被修改。

  本质上,客户端通过将该记号传回服务器,要求服务器验证其(客户端)缓存。

  304是HTTP状态码,服务器用来标识这个文件没修改,不返回内容,浏览器在接收到个状态码后,会使用浏览器已缓存的文件。

  客户端请求一个页面A。

  服务器返回页面A,并在给A加上一个ETag。

  客户端展现该页面,并将页面连同ETag一起缓存。

  客户再次请求页面A,并将上次请求时服务器返回的ETag一起传递给服务器。

  服务器检查该ETag,并判断出该页面自上次客户端请求之后还未被修改,直接返回响应304(未修改——NotModified)和一个空的响应体。

86.用node模拟客户端发起请求?

1
2
3
4
5
6
7
8
9
10
11
12
13
var http = require("http");
var request = http.request({
    host:"localhost",
    port:"8080",
    path:"/request",
    method:"post"
},function(res){
    res.on("data",function(chunk){
        console.log(chunk.toString());
    });
});
request.write("user=zhang&pass=111");
request.end("请求结束");//结束本次请求

87.CommonJS 中的 require/exports 和 ES6 中的 import/export 区别?

  CommonJS模块的重要特性是加载时执行,即脚本代码在require的时候,就会全部执行。

  一旦出现某个模块被”循环加载”,就只输出已经执行的部分,还未执行的部分不会输出。

  ES6模块是动态引用,如果使用import从一个模块加载变量,那些变量不会被缓存,而是成为一个指向被加载模块的引用,需要开发者自己保证,真正取值的时候能够取到值。

  import/export最终都是编译为require/exports来执行的。

  CommonJS规范规定,每个模块内部,module变量代表当前模块。

  这个变量是一个对象,它的exports属性(即module.exports)是对外的接口。

  加载某个模块,其实是加载该模块的module.exports属性。

  export命令规定的是对外的接口,必须与模块内部的变量建立一一对应关系。

88.数组方法

  1)join()把数组上午所有元素放入一个字符串。元素通过指定的分隔符进行分隔。

  该方法只接收一个参数,用作分隔符的字符串,然后返回包含所有数组项的字符串,如果不给join()方法传入任何值,则使用逗号作为分隔符。

1
2
3
4
5
6
var a = [1,2,3];
console.log(a.join());//'1,2,3'
console.log(a.join(' '));//'1 2 3'
console.log(a.join(''));//'123'
var b = new Array(10);
b.join('-');//'---------'9个连字符组成的字符串

  注意:如果join()方法的参数是undefined,标准浏览器以逗号为分隔符返回字符串,而IE7-浏览器以"undefined"为分隔符返回字符串;

  如果数组中某一项的值是null或者undefined,则该值在join()方法返回的结果中以空字符串表示。

  2)push()方法可以接收任意数量的参数,把它们逐个添加到数组末尾,并且返回修改后数组的长度。

1
2
3
4
5
var a = [];
console.log(a,a.push(1));//[1] 1
console.log(a,a.push('a'));//[1,'a'] 2
console.log(a,a.push(true, {}));//[1,'a',true,{}] 4
console.log(a,a.push([5,6]));//[1,'a',true,{},[5,6]] 5

  3)pop()方法从数组末尾移除最后一项,减少数组的length,然后返回移除的项。

1
2
var a = ['a', 'b', 'c'];
console.log(a,a.pop()); // ['a', 'b'] 'c'

  注意:给pop参数传其他数字不起作用,也不报错。还是只删除最后一项;

  对空数组使用pop()方法,不会报错,而是返回undefined

  4)shift()方法移除数组中的第一个项并返回该项,同时数组的长度减1

1
2
3
4
var a = ['a', 'b', 'c'];
console.log(a,a.shift());//['b', 'c'] 'a'
var arr6 = [1];
console.log(arr6,arr6.shift()); //[] 1

  注意:对空数组使用shift()方法,不会报错,而是返回undefined

  5)unshift()方法在数组前面添加任意个项并返回新数组长度。

1
2
var a = ['a', 'b', 'c'];
console.log(a,a.unshift('x')); //['x', 'a', 'b', 'c'] 4

  注意:当传入多个参数时,是一次性插入。最终的数组中插入的元素的顺序和它们在参数列表中的顺序一致;

  在IE-7浏览器中,unshift()方法的返回值总是undefined

  6)reserve()方法用于反转数组的顺序,返回经过排序之后的数组;而原来数组的顺序也发生改变。

1
2
3
4
var array = [1,2,4,3,5];
console.log(array,array.reverse());//[5,3,4,2,1] [5,3,4,2,1]
var array = ['str',true,3];
console.log(array,array.reverse());//[3,true,'str'] [3,true,'str']

  7)sort()按照字符编码的顺序进行排序。sort()方法会调用每个数组项的toString()方法,然后比较得到的字符串排序,返回经过排序之后的数组,而原数组顺序也发生改变。

1
2
3
4
var array = [2,1,4,3,5];
console.log(array,array.sort());//[1,2,3,4,5] [1,2,3,4,5]
var array = ['3str',3,2,'2'];
console.log(array,array.sort());//[2, "2", 3, "3str"] [2, "2", 3, "3str"]

  注意:如果数组包含undefined元素,它们会被排到数组的尾部;

  arrayObject.sort(sortby)参数可选。规定排序顺序。必须是函数。比较函数接收两个参数,如果第一个参数应该位于第二个之前则返回一个负数,如果两个参数相等则返回0,如果第一个参数应该位于第二个之后则返回一个正数。

  8)concat()方法基于当前数组中的所有项创建一个新的数组,先创建当前数组一个副本,然后将接收到的参数添加到这个副本的末尾,最后返回新构建的数组。所以concat()不影响原数组。

1
2
3
4
5
6
7
8
9
10
11
12
13
// 如果不给concat()方法传递参数时,它只是复制当前的数组;
var arr = [1,2,3];
console.log(arr,arr.concat()); //[1,2,3] [1,2,3]

// 如果参数是一个或多个数组,则该方法会将这些数组中的每一项都添加到结果数组中;
console.log(arr,arr.concat([6,7,8],[77,33,44]));
//[1, 2, 3] [1, 2, 3, 6, 7, 8, 77, 33, 44]
var arr1 = [4,5,6];
console.log(arr,arr.concat(arr1)); //[1,2,3] [1,2,3,4,5,6]

// 如果传递的值不是数组,这些值就会被简单地添加到结果数组的末尾。console.log(arr,arr.concat(4,5));//[1,2,3] [1,2,3,4,5]
console.log(arr,arr.concat(4,[5,[6,7]]));
//[1,2,3] [1, 2, 3, 4, 5, [6,7]]

  浅拷贝

  如果不提供参数,concat()方法返回当前数组的一个浅拷贝。

1
2
3
4
5
6
7
8
9
10
11
12
// 该方法实际只复制了数组的第一维。
// 数组第一维存放的是第二维的引用,而第二维才是实际存放他们的内容
var numbers = [1,2];
var newNumbers = numbers.concat();
console.log(numbers,newNumbers);//[1,2] [1,2]
numbers[0] = 0;
console.log(numbers,newNumbers);//[0,2] [1,2]
var numbers = [[1,2]];
var newNumbers = numbers.concat();
console.log(numbers,newNumbers);//[[1,2]] [[1,2]]
numbers[0][0] = 0;
console.log(numbers,newNumbers);//[[0,2]] [[0,2]]

  9)slice()方法基于当前数组中的一个或多个项创建一个新数组,接受一个或两个参数,最后返回新数组,所以slice()不影响原数组。

  slice(start,end)方法需要两个参数start和end,返回这个数组从start位置到end位置(不包含)的一个子数组,左闭右开。

  注意:a.如果end为undefined或不存在,则返回从start位置到数组结尾的所有项;

  b.如果没有参数,则返回原数组,即返回当前数组的一个浅拷贝;

  10)splice()方法用于删除原数组的一部分成员,并可以在被删除的位置添加入新的数组成员,该方法会改变原数组。

  splice()返回一个由删除元素组成的数组,或者如果没有删除元素就返回一个空数组

  splice(start,number…)的第一个参数start指定了插入或删除的起始位置,第二个参数number指定了应该从数组中删除的元素的个数,如果后面还有更多的参数,则表示这些就是要被插入数组的新元素。

  11)indexOf(search,start)方法接收search和start两个参数,返回search首次出现的位置,如果没有找到则返回-1,start代表从start位置开始寻找。

  12)lastIndexOf(search,start)方法从右向左查找。

  接收search和start两个参数,返回search第一次出现的位置,如果没有找到则返回-1

  13)reduce()方法需要两个参数,第一个是执行化简操作的函数,化简函数的任务就是用某种方法把两个值组合或化简为一个值,并返回化简后的值。

1
2
3
4
var total = [0, 1, 2, 3].reduce(function(sum, value) {
  return sum + value;
}, 0);
// total is 6

  reduceRight()则从右到左执行对应的化简函数

  14)map()方法对数组中的每一项运行给定的函数,返回每次函数调用的结果组成的数组,

  map方法还可以接受第二个参数,表示回调函数执行时this所指向的对象。

  15)forEach()方法对数组中的每一项运行给定的函数,这个方法没有返回值。本质上和for循环迭代数组一样。如果需要有返回值,一般使用map方法。

  forEach()方法除了接受一个必须的回调函数参数,第二个参数还可以接受一个可选的上下文参数(改变回调函数里面的this指向)

1
2
3
array.forEach(callback(currentValue, index, array){
    //do something
}, this)

  16)filter()方法对数组中的每一项运行给定的函数,返回该函数会返回true的项组成的数组。该方法常用于查询符合条件的所有数组项。

  filter()方法还可以接受第二个可选的上下文参数(改变回调函数里面的this指向)

1
2
3
4
5
var arr= [1,10,20,30]
var brr = arr.filter((item)=&gt;{
    return item&gt;10;
})
//[20,30]

  17)some()方法对数组中的每一项运行给定函数,如果该函数对任一项返回true,则返回true。并且当且仅当数值中的所有元素调用判定函数都返回false,它才返回false

  注意:在空数组上调用some()方法会返回false

1
2
3
4
5
6
7
8
9
const isBiggerThan10 = (element, index, array) => {
  return element > 10;
}

[2, 5, 8, 1, 4].some(isBiggerThan10);  
// false

[12, 5, 8, 1, 4].some(isBiggerThan10);
// true

  18)every()方法对数组中的每一项运行给定函数,如果函数对每一项都返回true,则返回true;只要有一项返回false,则返回false

  19)fill()方法,用一个固定值填充一个数组中起始索引到终止索引内的全部元素

1
2
3
4
arr.fill(value, start, end)
var numbers = [1, 2, 3]
numbers.fill(1);
// results in [1, 1, 1]

  20)find()方法返回数组中满足提供的测试函数的第一个元素的值

1
2
3
4
function isBigEnough(element) {
    return element >= 15;
}
[12, 5, 8, 130, 44].find(isBigEnough); // 130

  21)findIndex()方法返回数组中满足提供的测试函数的一个元素的索引

1
2
3
4
5
function isBigEnough(element) {
  return element >= 15;
}
[12, 5, 8, 130, 44].findIndex(isBigEnough);
//'3'

  22)includes()方法用来判断一个数组是否包含一个指定的值,如果是,则返回true,如果没有则返回false

1
2
3
4
5
let a = [1, 2, 3];
a.includes(2);
// true
a.includes(4);
// false

  23)toLocaleString()方法返回一个字符串表示数组中的元素。数组中的元素将使用各自的toLocaleString方法转成字符串,这些字符串将使用一个特定语言环境的字符串(例如一个逗号",")隔开

1
2
3
4
5
6
var number = 1337;
var date = new Date();
var myArr = [number, date, "foo"];
var str = myArr.toLocaleString();
console.log(str);
// 输出 "1,337,2019/2/15 下午8:32:24,foo"

  24)copyWithin(target,start,end)方法浅复制数组的一部分到同一数组的另一个位置

  25)Array.isArray()方法用于确定传递的值是否是一个Array

1
2
Array.isArray([]) => true;
Array.isArray({}) => false;

  26)Array.of()

1
2
3
4
5
Array.of(7);       // [7]
Array.of(1, 2, 3); // [1, 2, 3]

Array(7);          // [ , , , , , , ]
Array(1, 2, 3);    // [1, 2, 3]

  27)Array.from()

  对伪数组或可迭代对象(包括arguments Array,Map,Set,String…)转换成数组对象

  语法Array.from(arrayLike,mapFn,thisArg)

  arrayLike

  想要转换成数组的伪数组对象或可迭代对象。

  mapFn(可选参数)

  如果指定了该参数,新数组中的每个元素会执行该回调函数。

  thisArg(可选参数)

  可选参数,执行回调函数mapFn时this对象。

  返回值

  一个新的数组实例

89.数组降维

方法一:

1
2
3
4
5
6
7
8
function flattenDeep(arr) {
        arr = "" + arr;  // 或者arr = arr.toString();

        arr = arr.split(",");
        arr = arr.map(Number)
        return arr;
    }
flattenDeep([1, [[2],[3, [4]], 5]]);

方法二:

1
2
3
4
5
6
7
8
9
function flattenDeep(arr) {
    if(!Array.isArray(arr))
        return [arr];
    return arr.reduce((prev,cur) => {        
        return [...prev, ...flattenDeep(cur)];
    },[]);
}

flattenDeep([1, [[2], [3, [4]], 5]]);fang

方法三:

1
2
3
4
5
6
function flattenDeep(arr){
    while(arr.some(item=>Array.isArray(item)){
        arr = [].concat(...arr);
    }
    return arr;
}

90.栈的压入和弹出

  输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列5,4,3,2,1或3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function IsPopOrder(pushV,popV){
    if(pushV.length === 0) return false;
    var stack = []; // 模拟栈
    for(var i = 0, j = 0; i < pushV.length;){
        stack.push(pushV[i]);
        i += 1;
        // 压入栈的值需要被弹出
        while(j < popV.length && stack[stack.length-1] === popV[j]){
            stack.pop();
            j++;
            if(stack.length === 0) break;
        }
    }
    return stack.length === 0;
}

91.利用栈模拟队列

思路:

  • 对栈A添加数据。
  • 如果栈B为空,循环将栈A中内容弹出放入栈B,并弹出栈B最后一项
  • 如果栈B不为空,则直接弹出栈B的最后一项
1
2
3
4
5
6
7
8
9
10
11
12
13
14
var stackA = [];
var stackB = [];

function push(node){
    stackA.push(node);
}
function pop(){
    if(!stackB.length){
        while(stackA.length){
            stackB.push(stackA.pop());
        }
    }
    return stackB.pop();
}

92.连续最长不重复字符串

  在一个字符串中找出连续的不重复的最大长度的字符串,解决这类问题的思路:

  • 利用循环叠加字符串,直到出现重复为止
  • 每一次叠加,记录下来最大长度的字符串
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 连续最长不重复字符串
function getMaxLenStr(str) {
    var cur = [];
    var maxLenStr = '';
    for(var i = 0; i < str.length; i++) {
        if(!cur.includes(str[i])) {
            cur.push(str[i]);
        } else {
            cur = []; // 置为空
            cur.push(str[i]);
        }
        // 存储最大长度的字符串
        if(maxLenStr.length < cur.length) {
            maxLenStr = cur.join('');
        }        
    }
    return maxLenStr;
}
getMaxLenStr('ababcabcde'); // abcde

93.求一个数组当中,连续子向量的最大和。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function FindGreatestSumOfSubArray(arr) {
    let sum = arr[0];
    let max = arr[0];
    for(let i = 1; i < arr.length; i++) {
        if(sum < 0) {
            sum = arr[i];
        }else{
            sum += arr[i];
        }
        // 记录最大值
        if(max < sum) {
            max = sum;
        }
    }
    return max;
}

94.给定一个编码字符,按编码规则进行解码,输出字符串

  编码规则:coount[letter],将letter的内容count次输出,count是0或正整数,letter是区分大小写的纯字母。

  实例:

  • const s= 3[a]2[bc]; decodeString(s); // 返回 ‘aaabcbc’
  • const s= 3[a2[c]]; decodeString(s); // 返回 ‘accaccacc’
  • const s= 2[ab]3[cd]ef; decodeString(s); // 返回 ‘ababcdcdcdef’

  思路:

  使用栈这种数据结构,如果push的内容为‘]’,则循环pop字符,直到碰到’[‘,然后将pop出来的字符串按规则整理后,重新push进栈中,最后将栈内的内容拼接成字符串输出即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
function decodeString(str) {
    let stack = []; // 存储字符串的栈
    for (let i = 0; i < str.length; i++) {
        let cur = str[i];
        if (cur !== ']') {
            stack.push(cur);
        } else { // 弹出
            let count = 0;
            let loopStr = [];
            let popStr = '';
            while ((popStr = stack.pop()) !== '[') {
                loopStr.unshift(popStr);
            }
            count = stack.pop();
            // 添加结果
            let item = '';
            for (let i = 0; i < count; i++) {
                item += loopStr.join('');
            }
            stack.push(...(item.split('')));
        }
    }
    return stack.join('');
}

95.['1', '2', '3'].map(parseInt) 的运行结果

  答案为:[1,NaN,NaN]

  解析:

1
arr.map(functioncallback(currentValue[,index[,array]]){//Returnelementfornew_array}[,thisArg])

  这个callback一共可以接收三个参数,其中第一个参数代表当前被处理的元素,而第二个参数代表该元素的索引。

  而parseInt则是用来解析字符串的,使字符串成为指定基数的整数。

  -parseInt(string,radix)

  接收两个参数,第一个表示被处理的值(字符串),第二个表示为解析时的基数。

  parseInt('1',0)//radix为0时,且string参数不以“0x”和“0”开头时,按照10为基数处理。这个时候返回1

  parseInt('2',1)//基数为1(1进制)表示的数中,最大值小于2,所以无法解析,返回NaN

  -parseInt('3',2)//基数为2(2进制)表示的数中,最大值小于3,所以无法解析,返回NaN

  map函数返回的是一个数组,所以最后结果为[1,NaN,NaN]

96.自定义事件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
var content = document.querySelector('.content');
    // 自定义事件
    var evt = new Event('custom');
    var customEvt = new CustomEvent('customEvt', {
        // 通过这个属性传递参数
        detail: {
            name: 'tom',
            age: 12
        }
    });
    content.addEventListener('custom', (e) => {
        console.log('自定义事件被触发,无参数...');
        console.log(e);
    });
    content.addEventListener('customEvt', (e) => {
        console.log('自定义事件被触发,有参数...');
        console.log(e);
        console.log(e.detail);
    });
    // 点击时触发这个自定义事件
    content.addEventListener('click', (e) => {
        content.dispatchEvent(evt);
        content.dispatchEvent(customEvt);
    });

97.以下递归函数存在栈溢出的风险,请问如何优化?

1
2
3
function factorial(n){
    return n*factorial(n-1)
}

答案:

1
2
3
function factorial(n){
    return n > 1 ? n * factorial(n-1) : 1;
}

98.请实现一个计算最大公约数的函数

1
2
3
4
5
6
function greatestCommonDivisor(a,b){
//在这里编写代码
}
greatestCommonDivisor(8, 12) //4
greatestCommonDivisor(8, 16) //8
greatestCommonDivisor(8, 17) //1

解答:

1
2
3
4
5
6
7
8
9
function greatestCommonDivisor(a,b){
  var num=0;  
      while(b!=0){      
           num=a%b;  
           a=b;  
           b=num;  
      }  
      return a;
}

99.数组去重(如果数组中有NaN)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Array.prototype.uniq = function () {
   var resArr = [];
   var flag = true;
     
   for(var i=0;i&lt;this.length;i++){
       if(resArr.indexOf(this[i]) == -1){
           if(this[i] != this[i]){  

               //排除 NaN
              if(flag){
                   resArr.push(this[i]);
                   flag = false;
              }
           }else{
                resArr.push(this[i]);
           }
       }
   }
    return resArr;
}

100. 用 JavaScript 实现斐波那契数列函数,返回第n个斐波那契数。 f(1) = 1, f(2) = 1 等

1
2
3
4
5
6
function fibonacci(n) {
    if(n ==1 || n == 2){
        return 1
    }
    return fibonacci(n - 1) + fibonacci(n - 2);
}

101.根据包名,在指定空间中创建对象

输入描述:

1
namespace({a: {test: 1, b: 2}}, 'a.b.c.d')

输出描述:

1
{a: {test: 1, b: {c: {d: {}}}}}
1
2
3
4
5
6
7
8
9
10
11
12
function namespace(oNamespace, sPackage) {
    var properties = sPackage.split('.');
    var parent = oNamespace;
    for (var i = 0, lng = properties.length; i < lng; ++i) {
        var property = properties[i];
        if (Object.prototype.toString.call(parent[property])!== '[object Object]') {
            parent[property] = {};
        }
        parent = parent[property];
    }
    return oNamespace;
}

102.封装函数 f,使 f 的 this 指向指定的对象

1
2
3
4
5
function bindThis(f, oTarget) {
    return function(){
        var parames = Array.prototype.slice.call(arguments);
        return f.apply(oTarget,parames); //注意这里需要返回f的执行结果
    }

103.dom 节点查找

查找两个节点的最近的一个共同父节点,可以包括节点自身

输入描述:

oNode1 和 oNode2 在同一文档中,且不会为相同的节点

1
2
3
4
5
6
7
8
9
function commonParentNode(oNode1, oNode2) {
    if(oNode1.contains(oNode2)){
        return oNode1;
    }else if(oNode2.contains(oNode1)){
        return oNode2;
    }else{
        return commonParentNode(oNode1.parentNode,oNode2);
    }
}

104.关系型数组转换成树形结构对象

关系型数组:

1
2
3
4
5
var obj = [
    { id:3, parent:2 },
    { id:1, parent:null },
    { id:2, parent:1 },
]

期望结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
o = {
  obj: {
    id: 1,
    parent: null,
    child: {
      id: 2,
      parent: 1,
      child: {
          id: ,3,
          parent: 2
      }
    }
  }
}

实现源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
function treeObj(obj) {
  obj.map(item => {
    if (item.parent !== null) {
      obj.map(o => {
        if (item.parent === o.id) {
          if (!o.child) {
            o.child = [];
          }
          o.child.push(item);
          o.child = o.child;
        }
      });
    }
  });
  return obj.filter(item => item.parent === null)[0]
}
</pre>
<!-- /wp:html -->

<!-- wp:paragraph -->
<p>或者:</p>
<!-- /wp:paragraph -->

<!-- wp:html -->
[cc lang="html"]
function treeObj(obj) {
  return obj.sort((a, b) => b.parent - a.parent)
      .reduce((acc, cur) => (acc ? { ...cur, child: acc } : cur));
}

105.JS如何判断一组数字是否连续

1
2
// 当出现连续数字的时候以‘-’输出
[1, 2, 3, 4, 6, 8, 9, 10]

期望结果:

1
["1-4", 6, "8-10"]

实现代码:

判断是否连续:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var arrange = function(arr){
    var result = [],temp = [];
    arr.sort(function(source, dest){
        return source - dest;
    }).concat(Infinity).reduce(function(source, dest){
        temp.push(source);
        if(dest-source > 1){
            result.push(temp);
            temp = [];
        }
        return dest;
    });
    return result;
};

格式化实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var formatarr = function(arr) {
    var newArr = []
    var arr1 = arrange(arr)
    for (var i in arr1) {
        var str = '';
        if (arr1[i].length > 1) {
            str = arr1[i][0] + '-' + arr1[i][arr1[i].length - 1];
            newArr.push(str)
        } else {
            newArr.push(arr1[i][0]);
        }
   }
   return newArr;
}

106.创建子类Child,使用原型和构造函数的方式继承父类People的方法,并调用say函数说出姓名和年龄。

父类:

1
2
3
4
5
6
7
function People(name,age){
     this.name=name;
     this.age=age;
     this.say=function(){
         console.log("我的名字是:"+this.name+"我今年"+this.age+"岁!");
     };
}

原型继承:

1
2
3
4
5
6
7
function Child(name, age){
    this.name = name;
    this.age = age;
}
Child.prototype = new People();
var child = new Child('Rainy', 20);
child.say()

构造函数继承:

1
2
3
4
5
6
7
function Child(name, age){
    People.call(this)
    this.name = name;
    this.age = age;
}
var child = new Child('Rainy', 20);
child.say()

组合继承:

1
2
3
4
5
6
7
8
function Child(name, age){
    People.call(this);
    this.name = name;
    this.age = age;
}
Child.prototype = People.prototype;
var child = new Child('Rainy', 20);
child.say()

组合继承优化:

1
2
3
4
5
6
7
8
9
function Child(name, age){
    People.call(this);
    this.name = name;
    this.age = age;
}
Child.prototype = Object.create(People.prototype);
Child.prototype.constructor = Child;
var child = new Child('Rainy', 20);
child.say()

结束语

以上就是今天为大家带来的web前端开发经典面试题整理,内容有点多,但是干货却是满满,大家可以收藏下来。每次复习都有一种温故而知新的感觉,学会的可以时常复习一下,毕竟时间长了人都是会遗忘的,大佬也可以适当的补充更好的方案帮助小伙帮们学到更多知识。

「除特别注明外,本站所有文章均为码云笔记原创,转载请保留出处!」

赞(17) 打赏

觉得文章有用就打赏一下文章作者

支付宝
微信
17

觉得文章有用就打赏一下文章作者

支付宝
微信

上一篇:

下一篇:

你可能感兴趣

共有 2 条评论 - web前端开发经典面试题整理

  1. Actor Linux Chrome 62.0.3202.84

    金三银四,找工作

    1. 码云 Windows 7 Chrome 69.0.3497.100

      @Actor多学一下,对技术面试有帮助

博客简介

码云笔记 mybj123.com,一个专注Web前端开发技术的博客,主要记录和总结博主在前端开发工作中常用的实战技能及前端资源分享,分享各种科普知识和实用优秀的代码,以及分享些热门的互联网资讯和福利!码云笔记有你更精彩!
更多博客详情请看关于博客

精彩评论

站点统计

  • 文章总数: 476 篇
  • 分类数目: 13 个
  • 独立页面: 8 个
  • 评论总数: 228 条
  • 链接总数: 15 个
  • 标签总数: 1050 个
  • 建站时间: 525 天
  • 访问总量: 8648224 次
  • 最近更新: 2019年11月21日