• 最全前端面试题


    即使身为最难毕业生,也要积极应对,一起来看一下前端岗位的面试题吧,准备好自己总是没错的。以下是我遇到的以及从各路前辈处总结的一些题目。

    1.盒模型

      在网页中,一个元素占有空间的大小由几个部分构成,其中包括元素的内容(content),元素的内边距(padding),元素的边框(border),元素的外边距(margin)四个部分。这四个部分占有的空间中,有的部分可以显示相应的内容,而有的部分只用来分隔相邻的区域或区域。4个部分一起构成了css中元素的盒模型。

    2.行内元素有哪些?块级元素有哪些? 空(void)元素有那些?

    行内元素:a、b、span、img、input、strong、select、label、em、button、textarea

    块级元素:div、ul、li、dl、dt、dd、p、h1-h6、blockquote

    空元素:即系没有内容的HTML元素,例如:br、meta、hr、link、input、img

    3.行内元素、块级元素区别

    行内元素:和其他元素都在一行上,高度、行高及外边距和内边距都不可改变,文字图片的宽度不可改变,只能容纳文本或者其他行内元素;其中img是行元素。
    块级元素:总是在新行上开始,高度、行高及外边距和内边距都可控制,可以容纳内敛元素和其他元素;行元素转换为块级元素方式:display:block;

    4.flex与Grid区别:

    Flex 主要用于一维布局,而 Grid 则用于二维布局。
    Flex
    flex容器中存在两条轴, 横轴和纵轴, 容器中的每个单元称为flex item。
    在容器上可以设置6个属性: flex-direction flex-wrap flex-flow justify-content align-items align-content
    注意:当设置 flex 布局之后,子元素的 float、clear、vertical-align 的属性将会失效。
    Flex 项目属性
    有六种属性可运用在 item 项目上: 1. order 2. flex-basis 3. flex-grow 4. flex-shrink 5. flex 6. align-self
    Grid
    CSS网格布局用于将页面分割成数个主要区域,或者用来定义组件内部元素间大小、位置和图层之间的关系。
    像表格一样,网格布局让我们能够按行或列来对齐元素。 但是,使用CSS网格可能还是比CSS表格更容易布局。 例如,网格容器的子元素可以自己定位,以便它们像CSS定位的元素一样,真正的有重叠和层次。

    5.css值

    css角度:deg指定以度为单位的角度(值从0deg到360deg);grad指定渐变中的角度(值从0grad到400grad);rad指定以弧度表示的角度(值从0rad到6.28rad);turn指定整圈的角度(1turn等于360deg)。

    css时间单位:可使用css时间测量间隔,包括s和ms,其中1s = 1000ms

    6.css的单位

      px:绝对单位,为css像素

      em:相对单位,以父节点字体大小为基准,如果自身设置了font-size,以自身的来计算。

      rem:相对单位,以根节点的font-size为基准。

      vw:视窗宽度,1vw=1%视窗宽度

      vh:视窗高度,1vh=1%视窗高度

      vmin:vw和vh中较小的那个

      vmax:vw和vh中较大的那个

           %:百分比

    7.css选择器

    css的基础选择器包括:标记选择器、类选择器、id选择器、通配符选择器、标签指定式选择器、后代选择器、并集选择器。

    标记选择器:按标记名称分类,为页面某一类标记指定统一样式(eg:h1、p);

    类选择器:用“.”进行标识,后紧跟类名(类名为class属性值);

    id选择器:用“#”进行标识,后紧跟id名(id值唯一);

    通配符选择器:用“*”号表示,作用范围最广能匹配所有元素,会降低代码执行速度;

    标签指定式选择器:由两个选择器构成(一个标记选择器,第二个为类选择器或id选择器,两个选择器中没有空格)eg:h3.special;

    后代选择器:用来选择元素或元素的后代,外层标记写前边,里层写后边,中间用空格隔开。(eg:p strong{color:red;} )

    并集选择器:各个选择器通过逗号连接,把连接起来的统一定义成一种样式。(eg:h3,.special,#one{text-decoration:underline;})

    伪类选择器: E:link, 匹配所有未被点击的链接;E:hover, 匹配鼠标悬停其上的E元素等

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

    1、同向margin的重叠(父子):

      父层的margin-top与子层的margin-top发生重叠,父层的margin-bottom与子层的margin-bottom发生重叠。这时候重叠之后的margin值由发生重叠两片的最大值决定;如果其中一个出现负值,则由最大的正边距减去绝对值最大的负边距,如果没有最大正边距,则由0减去绝对值最大的负边距。

    解决同向重叠的方法:

    (1)在父层的div中加入overflow:hidden;zoom:1

    (2)在父层加入padding:1px;属性

    (3)在父层加入:border:1px solid #cacbcc;

    2、异向重叠问题(兄弟):

      兄弟1的margin-bottom与兄弟2的margin-top发生重叠,这时候重叠之后的margin值同样遵循上述规则。

    解决异向重叠问题:

    (1)BFC格式化上下文

    (2)float:left(只能解决IE6浏览器中的异向重叠问题,可以解决IE8以上、chorme、firefox、opera下的同向重叠问题)

    9.常见页面布局

    常见的页面布局包括:“国”字型、拐角型、标题正文型、左右框架型、上下框架型、综合框架型、封面型、Flash型、变化型等

    10.响应式布局

    响应式布局指的是同一页面在不同屏幕尺寸下有不同的布局。传统的开发方式是PC端开发一套,手机端再开发一套,而使用响应式布局只要开发一套就够,通过检测视口分辨率,针对不同客户端在客户端做代码处理,来展现不同的布局和内容,缺点就是CSS比较重。

    包括以下这四个步骤:

      1、布局及设置meta标签:

      当你完成当你已经完成了无响应的网站,做的第一件事是在你的 HTML 页面,粘贴下面的代码到和标签之间。这将设置屏幕按1:1的尺寸显示,在 iPhone 和其他智能手机的浏览器提供网站全视图浏览,并禁止用户缩放页面。

    <meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no"><meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"><meta name="HandheldFriendly" content="true">

    user-scalable属性能够解决ipad切换横屏之后触摸才能回到具体尺寸的问题。

      2、通过媒体查询来设置样式media query:

    media query 是响应式设计的核心,它能够和浏览器进行沟通,告诉浏览器页面如何呈现,假如一个终端的分辨率小于980px,那么可以这样写

    @media screen and (max-980px){

    #head { … }

    #content { … }

    #footer { … }

    }这里面的样式会覆盖掉之前所定义的样式。

      3、设置多种视图宽度:

    假如我们要兼容ipad和iphone视图,我们可以这样设置:

    /**ipad**/@media only screen and (min-768px)and(max-1024px){}/**iphone**/

     @media only screen and (320px)and (768px){}

      4、字体设置:css3引入了新的单位叫做rem,和em类似但对于Html元素,rem更方便使用。rem是相对于根元素的,不要忘记重置根元素字体大小。

    html{font-size:100%;} 完成后,你可以定义响应式字体:

    @media (min-640px){body{font-size:1rem;}}

    @media (min-960px){body{font-size:1.2rem;}}

    @media (min-1200px){body{font-size:1.5rem;}}

    11.css预处理、后处理

    Sass、LESS、Stylus是目前最主流的CSS预处理器。

    实现原理

    1. 取到 DSL 源代码分析树
    2. 将含有 动态生成 相关节点的 分析树 转换为 静态分析树
    3. 静态分析树 转换为 CSS 的 静态分析树
    4. 将 CSS 的 静态分析树 转换为 CSS 代码

    现实中的 CSS 预处理器 更复杂一点儿,因为大多功能要同时支持 特有 DSL原生 CSS,一件事情要同时考虑两种情况下的处理。

    预处理优点:

    • 提高 CSS 可维护性。
    • 易于编写嵌套选择器。
    • 引入变量,增添主题功能。可以在不同的项目中共享主题文件。
    • 通过混合(Mixins)生成重复的 CSS。
    • Splitting your code into multiple files. CSS files can be split up too but doing so will require a HTTP request to download each CSS file.
    • 将代码分割成多个文件。不进行预处理的 CSS,虽然也可以分割成多个文件,但需要建立多个 HTTP 请求加载这些文件。

    缺点:

    • 需要预处理工具。
    • 重新编译的时间可能会很慢。

    后处理器CSS 后处理器 是对 CSS 进行处理,并最终生成 CSS 的 预处理器,它属于广义上的 CSS 预处理器。

    实现原理:

    1. 源代码 做为 CSS 解析,获得 分析树
    2. CSS分析树 进行 后处理
    3. CSS分析树 转换为 CSS 代码

    优缺点:

    • 优点:使用 CSS 语法,容易进行模块化,贴近 CSS 的未来标准
    • 缺点:逻辑处理能力有限

    12.描述伪元素及其用途。

      CSS 伪元素是添加到选择器的关键字,去选择元素的特定部分。它们可以用于装饰(:first-line,:first-letter)或将元素添加到标记中(与 content:...组合),而不必修改标记(:before,:after)。

    :first-line和:first-letter可以用来修饰文字。

    上面提到的.clearfix方法中,使用clear: both来添加不占空间的元素。

    使用:before和:after展示提示中的三角箭头。鼓励关注点分离,因为三角被视为样式的一部分,而不是真正的 DOM。如果不使用额外的 HTML 元素,只用 CSS 样式绘制三角形是不太可能的。

    13.用css伪元素画三角形

    .info-tab {
        position: relative;
    }
    .info-tab::after {
        content: '';
        border: 4px solid transparent;
        border-top-color: #2c8ac2;
        position: absolute;
        top: 0;
    }

    14.css3新特性

    1.CSS3的选择器

    1)E:last-child 匹配父元素的最后一个子元素E。
    2)E:nth-child(n)匹配父元素的第n个子元素E。 
    3)E:nth-last-child(n) CSS3 匹配父元素的倒数第n个子元素E。

    2. @Font-face 特性

      Font-face 可以用来加载字体样式,而且它还能够加载服务器端的字体文件,让客户端显示客户端所没有安装的字体。

    @font-face { 
     font-family: BorderWeb; 
     src:url(BORDERW0.eot); 
     } 
     @font-face { 
     font-family: Runic; 
     src:url(RUNICMT0.eot); 
     } 
     .border { FONT-SIZE: 35px; COLOR: black; FONT-FAMILY: "BorderWeb" } 
     .event { FONT-SIZE: 110px; COLOR: black; FONT-FAMILY: "Runic" }

    淘宝网字体使用

     @font-face {
                    font-family: iconfont;
                    src: url(//at.alicdn.com/t/font_1465189805_4518812.eot);              
     }

    3. 圆角

    border-radius: 15px;

    4. 多列布局 (multi-column layout)

    <div class="mul-col">
        <div>
            <h3>新手上路</h3>
            <p>新手专区 消费警示 交易安全 24小时在线帮助 免费开店</p>
        </div>
        <div>
            <h3>付款方式</h3>
            <p>快捷支付 信用卡 余额宝 蚂蚁花呗 货到付款</p>
        </div>
        <div>
            <h3>淘宝特色</h3>
            <p>手机淘宝 旺信 大众评审 B格指南</p>
        </div>
    </div>
    .mul-col{
        column-count: 3;
        column-gap: 5px;
        column-rule: 1px solid gray;
        border-radius: 5px;
        border:1px solid gray;
        padding: 10px   ;
    }

    兼容性不好

    5.阴影(Shadow)

     .class1{ 
          text-shadow:5px 2px 6px rgba(64, 64, 64, 0.5); 
     } 

    6.CSS3 的渐变效果 

    background-image:-webkit-gradient(linear,0% 0%,100% 0%,from(#2A8BBE),to(#FE280E));

    7.css弹性盒子模型

    <div class="boxcontainer">
        <div class="item">1</div>
        <div class="item">2</div>
        <div class="item">3</div>
        <div class="item">4</div>
    </div>
    .boxcontainer { 
         1000px; 
        display: -webkit-box; 
        display: -moz-box; 
        -webkit-box-orient: horizontal; 
        -moz-box-orient: horizontal; 
    } 
                
     .item { 
        background: #357c96; 
        font-weight: bold; 
        margin: 2px; 
        padding: 20px; 
        color: #fff; 
        font-family: Arial, sans-serif; 
    }

    8. CSS3制作特效

    1) Transition 对象变换时的过渡效果

     transition-property 对象参与过渡的属性
     transition-duration 过渡的持续时间
     transition-timing-function 过渡的类型
     transition-delay 延迟过渡的时间

    2) Transforms 2D转换效果

    主要包括 translate(水平移动)、rotate(旋转)、scale(伸缩)、skew(倾斜)

    3) Animation动画特效 

    animation和translate的相关属性

    animate和translate

    15.相邻的两个inline-block节点为什么会出现间隔,该如何解决实现

    归根结底这是一个西文排版的问题,英文有空格作为词分界,而中文则没有。这个问题的原因可以上述到SGML(标准通用标记语言)和TeX(排版工具),它实际上是一个行内(inline)的问题,它由空格、换行或回车所产生空白符所致。

    方法1: 改变书写方式,去掉HTML中的空格。

    方法2:font-size,font-size基本上可以解决大部分浏览器下inline-block元素之间的间距。

    方法3:使用margin负值

    方法4:使用word-spacing或letter-spacing。letter-spacing子元素要设置letter-spacing为0,不然会继承父元素的值;使用word-spacing时,只需设置父元素word-spacing为合适值即可。

    16.meta viewport 移动端适配

     <meta name="viewport" content="width=device-width, initial-scale=1.0">

      meta viewport 的6个属性: width:设置viewport 的宽度;height: 设置viewport 的高度;initial-scale : 设置页面的初始缩放值;minimum-scale :允许用户的最小缩放值;maximum-scale:允许用户的最大缩放值;user-scalable: 是否允许用户进行缩放,值为"no"或"yes", no 代表不允许,yes代表允许。

    (1)layout viewport

      如果把移动设备上浏览器的可视区域设为viewport的话,某些网站会因为viewport太窄而显示错乱,所以这些浏览器就默认会把viewport设为一个较宽的值,比如980px,使得即使是那些为PC浏览器设计的网站也能在移动设备浏览器上正常显示。这个浏览器默认的viewport叫做 layout viewport。layout viewport的宽度可以通过 document.documentElement.clientWidth来获取。

    (2)visual viewport

      layout viewport的宽度是大于浏览器可视区域的宽度的,所以还需要一个viewport来代表浏览器可视区域的大小,这个viewport叫做 visual viewport。visual viewport的宽度可以通过 document.documentElement.innerWidth来获取。

    (3)ideal viewport

      ideal viewport是一个能完美适配移动设备的viewport。首先,不需要缩放和横向滚动条就能正常查看网站的所有内容;其次,显示的文字、图片大小合适,如14px的文字不会因为在一个高密度像素的屏幕里显示得太小而无法看清,无论是在何种密度屏幕,何种分辨率下,显示出来的大小都差不多。这个viewport叫做 ideal viewport。

      ideal viewport并没有一个固定的尺寸,不同的设备有不同的ideal viewport。例如,所有的iphone的ideal viewport宽度都是320px,无论它的屏幕宽度是320还是640。ideal viewport 的意义在于,无论在何种分辨率的屏幕下,针对ideal viewport 而设计的网站,不需要缩放和横向滚动条都可以完美地呈现给用户。

    17.css实现宽度自适应100%,宽高16:9的比例的矩形

    <style type="text/css">
    *{
        margin: 0;padding: 0
    }
    .box{
        width: 100%;
    }
    .scale{
        width: 100%;
        padding-bottom: 56.25%;
        position: relative;
    }
    .item{
        width: 100%;
        height: 100%;
        position:absolute;
        background-color: blue;
    }
    </style>
    <body>
        <div class="box">
            <div class="scale">
                <div class="item"></div>
            </div>
        </div>
    </body>

    18.bfc清除浮动

    .container{
       overflow:auto;
    }
    .container::after{
        content:"";
        display:block;
        clear:left;
    }

    19.请阐述块格式化上下文(Block Formatting Context)及其工作原理。

      块格式上下文(BFC)是 Web 页面的可视化 CSS 渲染的部分,是块级盒布局发生的区域,也是浮动元素与其他元素交互的区域。

    一个 HTML 盒(Box)满足以下任意一条,会创建块格式化上下文:

      float的值不是none.

      position的值不是static或relative.

      display的值是table-cell、table-caption、inline-block、flex、或inline-flex。

      overflow的值不是visible。

      在 BFC 中,每个盒的左外边缘都与其包含的块的左边缘相接。

      两个相邻的块级盒在垂直方向上的边距会发生合并(collapse)。

    20.重置css和标准化css的区别是什么?你会选择那种方式?

    • 重置(Resetting): 重置意味着除去所有的浏览器默认样式。对于页面所有的元素,像margin、padding、font-size这些样式全部置成一样。你将必须重新定义各种元素的样式。
    • 标准化(Normalizing): 标准化没有去掉所有的默认样式,而是保留了有用的一部分,同时还纠正了一些常见错误。

    当需要实现非常个性化的网页设计时,我会选择重置的方式,因为我要写很多自定义的样式以满足设计需求,这时候就不再需要标准化的默认样式了。

    21.Reflow和Repaint

    Reflow(重排):

      当涉及到DOM节点的布局属性发生变化时,就会重新计算该属性,浏览器会重新描绘相应的元素,此过程叫Reflow(回流或重排)。

    Repaint(重绘):

      当影响DOM元素可见性的属性发生变化 (如 color) 时, 浏览器会重新描绘相应的元素, 此过程称为Repaint(重绘)。因此重排必然会引起重绘。

    引起Repaint和Reflow的一些操作:

      调整窗口大小;

      字体大小;

      样式表变动;

      元素内容变化,尤其是输入控件;

      CSS伪类激活,在用户交互过程中发生;

      DOM操作,DOM元素增删、修改;

      width, clientWidth, scrollTop等布局宽高的计算。

    Repaint和Reflow是不可避免的,只能说对性能的影响减到最小,给出下面几条建议:

      避免逐条更改样式。建议集中修改样式,例如操作className。

      避免频繁操作DOM。创建一个documentFragment或div,在它上面应用所有DOM操作,最后添加到文档里。设置display:none的元素上操作,最后显示出来。

      避免频繁读取元素几何属性(例如scrollTop)。绝对定位具有复杂动画的元素。

      绝对定位使它脱离文档流,避免引起父元素及后续元素大量的回流

    22.img中的alt和元素的title属性作用

    img的alt属性
    如果无法显示图像,浏览器将显示alt指定的内容

    元素title属性
    在鼠标移到元素上时显示title的内容

    23.href与src区别

      href标识超文本引用,用在link和a等元素上,href是引用和页面关联,是在当前元素和引用资源之间建立联系。
      若在文档中添加href ,浏览器会识别该文档为 CSS 文件,就会并行下载资源并且不会停止对当前文档的处理。这也是为什么建议使用 link 方式加载 CSS,而不是使用 @import 方式。
      src表示引用资源,替换当前元素,用在img,script,iframe上,src是页面内容不可缺少的一部分。

      当浏览器解析到src ,会暂停其他资源的下载和处理(图片不会暂停其他资源下载),直到将该资源加载、编译、执行完毕,类似于将所指向资源应用到当前内容。这也是为什么建议把 js 脚本放在底部而不是头部的原因。

    24.浏览器的渲染过程

    1. 解析HTML生成DOM树。
    2. 解析CSS生成CSSOM规则树。
    3. 将DOM树与CSSOM规则树合并在一起生成渲染树。
    4. 遍历渲染树开始布局,计算每个节点的位置大小信息。
    5. 将渲染树每个节点绘制到屏幕。

    25.为何会出现浏览器兼容问题

    同一产品,版本越老 bug 越多;

    同一产品,版本越新,功能越多;

    不同产品,不同标准,不同实现方式。

    处理兼容问题的思路

    1. 要不要做

    产品的角度(产品的受众、受众的浏览器比例、效果优先还是基本功能优先)

    成本的角度 (有无必要做某件事)

    2. 做到什么程度 ,让哪些浏览器支持哪些效果

    3. 如何做 ,根据兼容需求选择技术框架/库(jquery) 根据兼容需求选择兼容工具(html5shiv.js、respond.js、css reset、normalize.css、Modernizr) 条件注释、CSS Hack、js 能力检测做一些修补,运用渐进增强或优雅降级。

    26.编写高效的 CSS 应该注意什么?

    1、使用 reset 但非全局 reset:使用 reset 可重置浏览器元素的一些默认属性,以达到浏览器的兼容,但需要注意的是,请不要使用全局 reset。

    2、良好的命名习惯

    3、代码缩写

    4、利用 css 的继承

    5、使用多重选择器

    6、适当的代码注释

    7、给你的 css 代码排序

    8、保持 css 的可读性

    9、选择更优的样式属性值

    10、使用 link 代替 @import

    11、使用外部样式表

    12、避免使用 css 表达式(expression)

    13、代码压缩

    27.请阐述float定位的工作原理?

      浮动元素是脱离文档流的,不占据空间。浮动元素碰到包含它的元素的边框或者其他浮动元素的边框会停留下来。

      浮动(float)是 CSS 定位属性。浮动元素从网页的正常流动中移出,但是保持了部分的流动性,会影响其他元素的定位(比如文字会围绕着浮动元素)。这一点与绝对定位不同,绝对定位的元素完全从文档流中脱离。

      CSS 的clear属性通过使用left、right、both,让该元素向下移动(清除浮动)到浮动元素下面。

      如果父元素只包含浮动元素,那么该父元素的高度将塌缩为 0。我们可以通过清除(clear)从浮动元素后到父元素关闭前之间的浮动来修复这个问题。

      有一种 hack 的方法,是自定义一个.clearfix类,利用伪元素选择器::after清除浮动。另外还有一些方法,比如添加空的<div></div>和设置浮动元素父元素的overflow属性。与这些方法不同的是,clearfix方法,只需要给父元素添加一个类,定义如下:

    .clearfix::after {

      content: '';

      display: block;

      clear: both;}

      值得一提的是,把父元素属性设置为overflow: auto或overflow: hidden,会使其内部的子元素形成块格式化上下文(Block Formatting Context),并且父元素会扩张自己,使其能够包围它的子元素。

    28.请阐述z-index属性,并说明如何形成层叠上下文

        所有主流浏览器都支持 z-index 属性,z-index 属性设置元素的堆叠顺序。拥有更高堆叠顺序的元素总是会处于堆叠顺序较低的元素的前面。

        注释:元素可拥有负的 z-index 属性值。

        注释:Z-index 仅能在定位元素上奏效(例如 position:absolute;)

        可能值:auto:默认,堆叠顺序与父元素相等;number:设置元素的堆叠顺序,;inherit:规定应该从父元素继承 z-index 属性的值。

    29.请解释什么是雪碧图,以及如何实现?

        雪碧图是把多张图片整合到一张上的图片。它被运用在众多使用了很多小图标的网站上(Gmail 在使用)。实现方法:

    使用生成器将多张图片打包成一张雪碧图,并为其生成合适的 CSS。

        每张图片都有相应的 CSS 类,该类定义了background-image、background-position和background-size属性。

        使用图片时,将相应的类添加到你的元素中。

    好处:

    减少加载多张图片的 HTTP 请求数(一张雪碧图只需要一个请求)。但是对于 HTTP2 而言,加载多张图片不再是问题。

    提前加载资源,防止在需要时才在开始下载引发的问题,比如只出现在:hover伪类中的图片,不会出现闪烁。

    30.display的属性值都有哪些?

    None

    此元素不会被显示

    block

    此元素将显示为块级元素,此元素前后会带有换行符

    Inline

    默认。此元素会被显示为内联元素,元素前后没有换行符

    inline-block

    行内块元素

    list-item

    此元素会作为列表显示

    run-in

    此元素会根据上下文作为块级元素或内联元素显示

    table

    此元素会作为块级表格来显示(类似 <table>),表格前后带有换行符

    inline-table

    此元素会作为内联表格来显示(类似 <table>),表格前后没有换行符

    table-row-group

    此元素会作为一个或多个行的分组来显示(类似 <tbody>)

    table-header-group

    此元素会作为一个或多个行的分组来显示(类似 <thead>)

    table-footer-group

    此元素会作为一个或多个行的分组来显示(类似 <tfoot>)

    table-row

    此元素会作为一个表格行显示(类似 <tr>)

    table-column-group

    此元素会作为一个或多个列的分组来显示(类似 <colgroup>)

    table-column

    此元素会作为一个单元格列显示(类似 <col>)

    table-cell

    此元素会作为一个表格单元格显示(类似 <td> 和 <th>)

    table-caption

    此元素会作为一个表格标题显示(类似 <caption>)

    inherit

    规定应该从父元素继承 display 属性的值

    31.relative、fixed、absolute和static四种定位有什么区别?

        经过定位的元素,其position属性值必然是relative、absolute、fixed或sticky。

    static

    默认定位属性值。该关键字指定元素使用正常的布局行为,即元素在文档常规流中当前的布局位置。此时 top, right, bottom, left 和 z-index 属性无效。

    relative

    该关键字下,元素先放置在未添加定位时的位置,再在不改变页面布局的前提下调整元素位置(因此会在此元素未添加定位时所在位置留下空白)。

    absolute

    不为元素预留空间,通过指定元素相对于最近的非 static 定位祖先元素的偏移,来确定元素位置。绝对定位的元素可以设置外边距(margins),且不会与其他边距合并。

    fixed

    不为元素预留空间,而是通过指定元素相对于屏幕视口(viewport)的位置来指定元素位置。元素的位置在屏幕滚动时不会改变。打印时,元素会出现在的每页的固定位置。fixed 属性会创建新的层叠上下文。当元素祖先的 transform 属性非 none 时,容器由视口改为该祖先。

    sticky

    盒位置根据正常流计算(这称为正常流动中的位置),然后相对于该元素在流中的 flow root(BFC)和containing block(最近的块级祖先元素)定位。在所有情况下(即便被定位元素为 table 时),该元素定位均不对后续元素造成影响。当元素 B 被粘性定位时,后续元素的位置仍按照 B 未定位时的位置来确定。position: sticky 对 table 元素的效果与 position: relative 相同。

    32.简述响应式设计与自适应设计的不同。

        响应式设计的适应性原则:网站应该凭借一份代码,在各种设备上都有良好的显示和使用效果。响应式网站通过使用媒体查询,自适应栅格和响应式图片,基于多种因素进行变化,创造出优良的用户体验。就像一个球通过膨胀和收缩,来适应不同大小的篮圈。
        自适应设计更像是渐进式增强的现代解释。与响应式设计单一地去适配不同,自适应设计通过检测设备和其他特征,从早已定义好的一系列视窗大小和其他特性中,选出最恰当的功能和布局。与使用一个球去穿过各种的篮筐不同,自适应设计允许使用多个球,然后根据不同的篮筐大小,去选择最合适的一个。

    33.什么情况下,用translate()而不用绝对定位?什么时候,情况相反。

        translate()是transform的一个值。改变transform或opacity不会触发浏览器重新布局(reflow)或重绘(repaint),只会触发复合(compositions)。而改变绝对定位会触发重新布局,进而触发重绘和复合。transform使浏览器为元素创建一个 GPU 图层,但改变绝对定位会使用到 CPU。 因此translate()更高效,可以缩短平滑动画的绘制时间。
        当使用translate()时,元素仍然占据其原始空间(有点像position:relative),这与改变绝对定位不同。

    34.DOM和BOM有什么区别

    DOM

     Document Object Model,文档对象模型;

     DOM 是为了操作文档出现的 API,document 是其的一个对象;

     DOM和文档有关,这里的文档指的是网页,也就是html文档。DOM和浏览器无关,他关注的是网页本身的内容。

    BOM

     Browser Object Model,浏览器对象模型;

     BOM 是为了操作浏览器出现的 API,window 是其的一个对象;

     window 对象既为 javascript 访问浏览器提供API,同时在 ECMAScript 中充当 Global 对象。 

    35.水平、垂直居中的方式

    1、flex

    // 父容器
    display: flex;
    justify-content: center;
    align-items: center;

    2、position

    // 父容器
    position: relative;
    // 子容器
    position:absolute;
    margin:auto;
    top:0;
    bottom:0;
    left:0;
    right:0;

    3、position+transform

    // 父容器
    position: relative;
    // 子容器
    position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);

    4、table-cell

    <div class="box">
        <div class="content">
            <div class="inner"></div>
        </div>
    </div>
    html, body {
        height: 100%;
         100%;
        margin: 0;
    }
    .box {
        display: table;
        height: 100%;
         100%;
    }
    .content {
        display: table-cell;
        vertical-align: middle;
        text-align: center;
    }
    .inner {
        background-color: #000;
        display: inline-block;
         200px;
        height: 200px;}

    36.display:none、visibile:hidden、opacity:0的区别

     

    是否隐藏

    是否在文档中占用空间

    是否会触发事件

    display:none

    visibile:hidden

    opacity:0

     

    display:none 隐藏对应的元素,在文档布局中不再给它分配空间,就当他从来不存在。

    visibility:hidden 隐藏对应的元素,但在文档布局中仍保留原来的空间。

    opacity:0  隐藏对应元素,只改变透明度,在文档布局中仍保留原来的空间。

    37.什么叫优雅降级和渐进增强?(常见)

    渐进增强 progressive enhancement

    一开始就针对低版本浏览器进行构建页面,完成基本的功能,然后再针对高级浏览器进行效果、交互、追加功能达到更好的体验。优先考虑老版本浏览器的可用性,相当于向上兼容。

    优雅降级 graceful degradation

    一开始就构建完整的功能,然后再针对低版本浏览器进行兼容。优先考虑新版本浏览器的可用性,相当于向下兼容。

    区别:

    a. 优雅降级是从复杂的现状开始,并试图减少用户体验的供给

    b. 渐进增强则是从一个非常基础的,能够起作用的版本开始,并不断扩充,以适应未来环境的需要

    c. 降级(功能衰减)意味着往回看;而渐进增强则意味着朝前看,同时保证其根基处于安全地带

    38.sessionStorage 、localStorage 和 cookie 之间的区别

     共同点:用于浏览器端存储的缓存数据

    不同点:

    (1)、存储内容是否发送到服务器端:当设置了Cookie后,数据会发送到服务器端,造成一定的宽带浪费;而sessionStorage和localStorage不会自动把数据发给服务器,仅在本地保存,不会造成宽带浪费;

    (2)、数据存储大小不同:Cookie数据不能超过4K,适用于会话标识;web storage数据存储可以达到5M;

    (3)、数据存储的有效期限不同:cookie只在设置了Cookid过期时间之前一直有效,即使关闭窗口或者浏览器;sessionStorage,仅在关闭浏览器之前有效;localStorage,数据存储永久有效;

    (4)、作用域不同:cookie和localStorage是在同源同窗口中都是共享的;sessionStorage不在不同的浏览器窗口中共享,即使是同一个页面;sessionStorage 支持事件通知机制,可以将数据更新的通知发送给监听者。sessionStorage 的 api 接口使用更方便。

    39.px、emrem的区别

     相同点:px、em和rem都是长度单位;

    异同点:px的值是固定的,相对于屏幕分辨率,IE无法调整那些使用px作为单位的字体大小。

    em的值不是固定的,相对于当前对象内文本的字体尺寸,并且em会继承父级元素的字体大小。

    rem是css3新增元素,仍然是相对大小,但相对的只是HTML根元素,除了IE8及更早版本外,所有浏览器均已支持rem。对于不支持它的浏览器,应对方法也很简单,就是多写一个绝对单位的声明。

    浏览器的默认字体高都是16px。所以未经调整的浏览器都符合: 1em=16px。那么12px=0.75em, 10px=0.625em。

    40.你有哪些性能优化的方法?

      (1) 减少http请求次数:CSS Sprites, JS、CSS源码压缩、图片大小控制合适;网页Gzip,CDN托管,data缓存 ,图片服务器。

      (2) 前端模板 JS+数据,减少由于HTML标签导致的带宽浪费,前端用变量保存AJAX请求结果,每次操作本地变量,不用请求,减少请求次数

      (3) 用innerHTML代替DOM操作,减少DOM操作次数,优化javascript性能。

      (4) 当需要设置的样式很多时设置className而不是直接操作style。

      (5) 少用全局变量、缓存DOM节点查找的结果。减少IO读取操作。

      (6) 避免使用CSS Expression(css表达式)又称Dynamic properties(动态属性)。

      (7) 图片预加载,将样式表放在顶部,将脚本放在底部加上时间戳。

    41.http状态码有那些?分别代表是什么意思?

    100-199 用于指定客户端应相应的某些动作。

    200-299 用于表示请求成功。

    300-399 用于已经移动的文件并且常被包含在定位头信息中指定新的地址信息。

    400-499 用于指出客户端的错误。400    1、语义有误,当前请求无法被服务器理解。401   当前请求需要用户验证 403  服务器已经理解请求,但是拒绝执行它。

    500-599 用于支持服务器错误。 503 – 服务不可用

    42.GET和POST的区别,何时使用POST?

    GET:一般用于信息获取,使用URL传递参数,对所发送信息的数量也有限制,一般在2000个字符需要使用Request.QueryString来取得变量的值通过地址栏来传值

    POST:一般用于修改服务器上的资源,对所发送的信息没有限制通过Request.Form来获取变量的值通过提交表单来传值。

    然而,在以下情况中,请使用 POST 请求:

    无法使用缓存文件(更新服务器上的文件或数据库)

    向服务器发送大量数据(POST 没有数据量限制)

    发送包含未知字符的用户输入时,POST 比 GET 更稳定也更可靠

    43.什么是mvvm mvc是什么区别 原理

    一、MVC(Model-View-Controller)

    MVC是比较直观的架构模式,用户操作->View(负责接收用户的输入操作)->Controller(业务逻辑处理)->Model(数据持久化)->View(将结果反馈给View)。

    MVC使用非常广泛,比如JavaEE中的SSH框架 

    二、MVVM(Model-View-ViewModel)

    如果说MVP是对MVC的进一步改进,那么MVVM则是思想的完全变革。它是将“数据模型数据双向绑定”的思想作为核心,因此在View和Model之间没有联系,通过ViewModel进行交互,而且Model和ViewModel之间的交互是双向的,因此视图的数据的变化会同时修改数据源,而数据源数据的变化也会立即反应view。

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

    渲染的流程如下:

    1.解析HTML文件,创建DOM树。

       自上而下,遇到任何样式(link、style)与脚本(script)都会阻塞(外部样式不阻塞后续外部脚本的加载)。

    2.解析CSS。优先级:浏览器默认设置<用户设置<外部样式<内联样式<HTML中的style样式;

    3.将CSS与DOM合并,构建渲染树(Render Tree)

    4.布局和绘制,重绘(repaint)和重排(reflow)

    45.js的基本数据类型

    JavaScript中有六种基本数据类型,它们分别是:undefined,null,boolean,number,string,symbol。

    引用数据类型包括object、Array、Function。

    46.从输入url到显示页面,都经历了什么

    一般会经历以下几个过程:

    1、首先,在浏览器地址栏中输入url

    2、浏览器先查看浏览器缓存-系统缓存-路由器缓存,如果缓存中有,会直接在屏幕中显示页面内容。若没有,则跳到第三步操作。

    3、在发送http请求前,需要域名解析(DNS解析)(DNS(域名系统,Domain Name System)是互联网的一项核心服务,它作为可以将域名和IP地址相互映射的一个分布式数据库,能够使人更方便的访问互联网,而不用去记住IP地址。),解析获取相应的IP地址。

    4、浏览器向服务器发起tcp连接,与浏览器建立tcp三次握手。(TCP即传输控制协议。TCP连接是互联网连接协议集的一种。)

    5、握手成功后,浏览器向服务器发送http请求,请求数据包。

    6、服务器处理收到的请求,将数据返回至浏览器

    7、浏览器收到HTTP响应

    8、读取页面内容,浏览器渲染,解析html源码

    9、生成Dom树、解析css样式、js交互

    10、客户端和服务器交互

    11、ajax查询

    47.undefined 和 null 区别

    null: Null类型,代表“空值”,代表一个空对象指针,使用typeof运算得到 “object”,所以你可以认为它是一个特殊的对象值。

    undefined: Undefined类型,当一个声明了一个变量未初始化时,得到的就是undefined。

    null是javascript的关键字,可以认为是对象类型,它是一个空对象指针,和其它语言一样都是代表“空值”,不过 undefined 却是javascript才有的。undefined是在ECMAScript第三版引入的,为了区分空指针对象和未初始化的变量,它是一个预定义的全局变量。没有返回值的函数返回为undefined,没有实参的形参也是undefined。

    javaScript权威指南: null 和 undefined 都表示“值的空缺”,你可以认为undefined是表示系统级的、出乎意料的或类似错误的值的空缺,而null是表示程序级的、正常的或在意料之中的值的空缺。

    48.let const var比较

    在ES6中,新增了let命令,用于声明变量,用来取代ES5中var命令,消除var声明的变量的不合理,不严谨之处。const用于声明常量。

    1.let不存在变量提升

      使用let声明的变量,不会像使用var那样存在“变量提升“”的现象。所以使用let声明变量,必须遵循“先声明,后使用”的原则。否则会报错

    2.let声明的变量,存在块级作用域 

       let声明的变量只在所声明的代码块内有效。块级作用域由 { } 包括,if语句和for语句里面的{ }也属于块作用域。

    3.let不允许在同一作用域内重复声明同一个变量

      在同一作用域内,如果使用var声明同一个变量,则后面的覆盖前面的

    4.暂时性死区:在代码块内,使用let声明变量之前,该变量都是不可以使用

      只要在同一作用域内存在let命令,他所声明的变量就“绑定”在这个作用域内,不管外部有没有声明

    ES6规定,如果在区块中存在let和const声明的变量,则这个区块对这些声明的变量从一开始就形成一个封闭的作用域。不管在外部有没有声明这个变量。必须遵守“先声明,后使用”的原则,否则报错;

      ES6规定暂时性死区和不存在变量提升,主要是为了减少运行程序的错误,防止出现“先使用(变量),后声明(变量)”的情况,从而导致意料之外的行为。这种错误在ES5中很常见,现在有了这种规定,就可以避免出现此类错误了;总之,暂时性死区的本质就是,只要一进入当前作用域,所使用的变量就已存在,但是不可获取,只有等到声明变量的哪一行代码的出现,在可以获取和使用该变量。

    const命令的基本使用

    1.const声明的常量不能改变,意味着const一旦声明常量,就必须同时初始化。不能先声明,后初始化,这样会报错

    2.与let一样。const声明的常量也只在块级作用域内有效
    3.与let一样,必须先声明,后使用
    4.与let一样,在同一作用域,const不能重复声明同一常量
    用const声明对象的属性是可以修改的

    49.HTML全局属性(global attribute)有哪些

    accesskey 规定激活元素的快捷键;

    class 规定元素的一个或多个类名(引用样式表中的类);

    contenteditable 规定元素内容是否可编辑;

    contextmenu 规定元素的上下文菜单。上下文菜单在用户点击元素时显示。

    data-* 用于存储页面或应用程序的私有定制数据。

    dir 规定元素中内容的文本方向。

    draggable 规定元素是否可拖动。

    dropzone 规定在拖动被拖动数据时是否进行复制、移动或链接。

    hidden  样式上会导致元素不显示,但是不能用这个属性实现样式。

    id 规定元素的唯一 id。

    lang 规定元素内容的语言。

    spellcheck 规定是否对元素进行拼写和语法检查。

    style 规定元素的CSS行内元素。

    tabindex 规定元素的tab键次序。

    title 规定有关元素的额外信息。

    translate 规定是否应该翻译元素内容。

    50.网页验证码是干嘛的,是为了解决什么安全问题

      网页验证码是用来区分计算机和人类的。验证码原理:服务器端随机生成验证码字符串,保存在内存中,并写入图片,发送给浏览器端显示,浏览器输入验证码图片上字符,然后提交服务器端,提交的字符和服务器端保存的该字符比较是否一致,一致就继续,否则返回提示。攻击者编写robot程序,很难识别验证码字符,顺利完成自动注册,登录;而用户可以识别填写,所以这就实现了阻拦攻击作用。而图片的字符识别;就是看图片的干扰强度了。就实际的效果来说,验证码只是增加攻击者的难度,而不可能完全的防止。

    51.Canvas和SVG有什么区别?

      canvas不依赖分辨率,canvas支持事件处理器,canvas最适合带有大型渲染区域的应用程序(比如谷歌地图),canvas复杂度高会减慢渲染速度(任何过度使用 DOM 的应用都不快),canvas不适合游戏应用。

      svg依赖分辨率,svg不支持事件处理器,svg弱的文本渲染能力,svg能够以 .png 或 .jpg 格式保存结果图像,svg最适合图像密集型的游戏,其中的许多对象会被频繁重绘。

    52.ES6新的特性有哪些?

    1、箭头操作符:我们知道在JS中回调是经常的事,而一般回调又以匿名函数的形式出现,每次都需要写一个function,甚是繁琐。当引入箭头操作符后可以方便地写回调了 

    2、ES6中添加了对类的支持,引入了class关键字(其实class在JavaScript中一直是保留字,目的就是考虑到可能在以后的新版本中会用到,现在终于派上用场了)。JS本身就是面向对象的,ES6中提供的类实际上只是JS原型模式的包装。现在提供原生的class支持后,对象的创建,继承更加直观了,并且父类方法的调用,实例化,静态方法和构造函数等概念都更加形象化。

    3、增强的对象字面量。对象字面量被增强了,写法更加简洁与灵活,同时在定义对象的时候能够做的事情更多了。具体表现在:

      • 可以在对象字面量里面定义原型

      • 定义方法可以不用function关键字

      • 直接调用父类方法

    4、字符串模板

      字符串模板相对简单易懂些。ES6中允许使用反引号 ` 来创建字符串,此种方法创建的字符串里面可以包含由美元符号加花括号包裹的变量${vraible}。

    5、解构

      自动解析数组或对象中的值。比如若一个函数要返回多个值,常规的做法是返回一个对象,将每个值做为这个对象的属性返回。但在ES6中,利用解构这一特性,可以直接返回一个数组,然后数组中的值会自动被解析到对应接收该值的变量中。

    6、参数默认值,不定参数,拓展参数

      默认参数值,现在可以在定义函数的时候指定参数的默认值了,而不用像以前那样通过逻辑或操作符来达到目的了。

      不定参数,不定参数是在函数中使用命名参数同时接收不定数量的未命名参数。这只是一种语法糖,在以前的JavaScript代码中我们可以通过arguments变量来达到这一目的。不定参数的格式是三个句点后跟代表所有不定参数的变量名。

      拓展参数,拓展参数则是另一种形式的语法糖,它允许传递数组或者类数组直接做为函数的参数而不用通过apply。

    7、let与const 关键字

      可以把let看成var,只是它定义的变量被限定在了特定范围内才能使用,而离开这个范围则无效。const则很直观,用来定义常量,即无法被更改值的变量。

    8、for of 值遍历

      我们都知道for in 循环用于遍历数组,类数组或对象,ES6中新引入的for of循环功能相似,不同的是每次循环它提供的不是序号而是值。

    9、模块

      在ES6标准中,JavaScript原生支持module了。这种将JS代码分割成不同功能的小块进行模块化的概念是在一些三方规范中流行起来的,比如CommonJS和AMD模式。

    将不同功能的代码分别写在不同文件中,各模块只需导出公共接口部分,然后通过模块的导入的方式可以在其他地方使用。 

    10、Map,Set 和 WeakMap,WeakSet

      这些是新加的集合类型,提供了更加方便的获取属性值的方法,不用像以前一样用hasOwnProperty来检查某个属性是属于原型链上的呢还是当前对象的。同时,在进行属性值添加与获取时有专门的get,set 方法。

    11、Proxies

      Proxy可以监听对象身上发生了什么事情,并在这些事情发生后执行一些相应的操作。一下子让我们对一个对象有了很强的追踪能力,同时在数据绑定方面也很有用处。

    12、Symbols

      我们知道对象其实是键值对的集合,而键通常来说是字符串。而现在除了字符串外,我们还可以用symbol这种值来做为对象的键。Symbol是一种基本类型,像数字,字符串还有布尔一样,它不是一个对象。Symbol 通过调用symbol函数产生,它接收一个可选的名字参数,该函数返回的symbol是唯一的。之后就可以用这个返回值做为对象的键了。Symbol还可以用来创建私有属性,外部无法直接访问由symbol做为键的属性值。

    13、Math,Number,String,Object 的新API

      Promises是处理异步操作的一种模式,之前在很多三方库中有实现,比如jQuery的deferred 对象。当你发起一个异步请求,并绑定了.when(), .done()等事件处理程序时,其实就是在应用promise模式。

    53.反引号(`)标识

      模板字符串(Template String)是增强版的字符串,用反引号(`)标识,它可以当作普通字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量。

    // 普通字符串
    `In JavaScript '
    ' is a line-feed.`
    
    // 多行字符串
    `In JavaScript this is
    not legal.`
    
    // 字符串中嵌入变量
    var name = "Bob", time = "today";
    `Hello ${name}, how are you ${time}?`   // Hello Bob, how are you today?

    上面代码中,模板字符串都是用反引号表示,如果在模板字符串中需要使用反引号,则前面需要用反斜杠转义。

    var greeting = `\`Yo\` World!`; // `Yo` World!

    如果使用模板字符串表示多行字符串,则所有的空格、缩进和换行都会被保留在输出中。

    $('#list').html(`
    <ul>
      <li>first</li>
      <li>second</li>
    </ul>
    `);

    上面代码中,所有模板字符串的空格和换行都是被保留的,比如<ul>标签前面会有一个换行。如果想把行首和行尾的换行、空格等去掉,则使用trim方法即可。

    $('#list').html(`
    <ul>
      <li>first</li>
      <li>second</li>
    </ul>
    `.trim());

    模板字符串中嵌入变量,要将变量名写在${}之中。大括号内可以放入任意的JavaScript表达式,可以进行运算,以及引入对象属性。

    var x = 1, y = 2;
    
    `${x} + ${y} = ${x + y}`;
    // "1 + 2 = 3"
    
    `${x} + ${y * 2} = ${x + y * 2}`;
    // "1 + 4 = 5"
    
    var obj = {x: 1, y: 2};
    `${obj.x + obj.y}`
    // "3"

    模板字符串之中还可以调用函数。

    function func() {
        return 'Hello';
    }
    
    `${func()} World`;
    // "Hello World"

    如果大括号中的值不是字符串,则将按照一般的规则转换为字符串。如,若大括号中是一个对象,则将默认调用对象的toString方法,把对象转换为字符串。

    如果模板字符串中的变量没有声明,则会报错。

    // 变量place没有声明
    var msg = `Hello, ${place}`;
    // ReferenceError: place is not defined

    模板字符串之间还可以进行嵌套。

    var tmpl = addrs => `
        <table>
        ${addrs.map(addr => `
            <tr><td>${addr.first}</td></tr>
            <tr><td>${addr.last}</td></tr>
        `).join('')}
        </table>
    `;
    tmpl([{first:'a', last: 'b'}]);
    // output:
    /*"
        <table>
            <tr><td>a</td></tr>
            <tr><td>b</td></tr>
        </table>
    "*/

    如果需要引用模板字符串本身,在需要时执行,可以像下面这样写

    // 写法一
    var str = 'return ' + '`Hello ${name}!`';
    var func = new Function('name', str);
    func('Amy');    // "Hello Amy!"
    // 写法二
    var str = '(name) => `Hello ${name}!`';
    var func = eval.call(null, str);
    func('Amy');    // "Hello Amy!"

    54.函数默认参数

    ES6中,可以为函数的参数指定默认值。函数默认参数允许在没有值或undefined被传入时使用默认形参。

    function log(x, y = 'World') {
      console.log(x, y);
    }
    log('Hello') // Hello World
    log('Hello', 'China') // Hello China
    log('Hello', '') // Hello

    55.箭头函数

    在es6中,提供了一种简洁的函数写法,我们称作“箭头函数”。

    写法:函数名=(形参)=>{……}     当函数体中只有一个表达式时,{}和return可以省略,当函数体中形参只有一个时,()可以省略。

    特点:箭头函数中的this始终指向箭头函数定义时的离this最近的一个函数,如果没有最近的函数就指向window。

    //省略写法
    var people = name => 'hello' + name;
    var getFullName = (firstName, lastName) => {
    var fullName = firstName + lastName;
    return fullName;
    }

    56.Object.keys()方法,获取对象的所有属性名或方法名

    Object.keys(arg):Object 是固定格式;arg 是需要检测的对象;

    var obj={name: "john", age: "21", getName: function () { alert(this.name)}};
    console.log(Object.keys(obj)); // ["name", "age", "getName"]
    console.log(Object.keys(obj).length); //3
    console.log(Object.keys(["aa", "bb", "cc"])); //["0", "1", "2"]
    console.log(Object.keys("abcdef")); //["0", "1", "2", "3", "4", "5"]

    57.for...of 循环

      for...of 语句创建一个循环来迭代可迭代的对象。在 ES6 中引入的 for...of 循环,以替代 for...in 和 forEach() ,并支持新的迭代协议。for...of 允许你遍历 Arrays(数组), Strings(字符串), Maps(映射), Sets(集合)等可迭代的数据结构等。

    语法

    for (variable of iterable) {
        statement
    }
    • variable:每个迭代的属性值被分配给该变量。
    • iterable:一个具有可枚举属性并且可以迭代的对象。

    for...of 更多用于特定于集合(如数组和对象),但不包括所有对象。

    58.import和export

    ES6模块主要有两个功能:export和import

    export用于对外输出本模块(一个文件可以理解为一个模块)变量的接口
    import用于在一个模块中加载另一个含有export接口的模块。
    也就是说使用export命令定义了模块的对外接口以后,其他JS文件就可以通过import命令加载这个模块(文件)

    59.Promise对象

    Promise是异步编程的一种解决方案,比传统的解决方案(回调函数和事件)更合理更强大。

    所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件 (通常是一个异步操作)的结果。从语法上说,Promise是一个对象,从它可以获取异步操作的消息。

    Promise对象有以下2个特点:
    1.对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:Pending(进行中)、Resolved(已完成)和Rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是Promise这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。
    2.一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从Pending变为Resolved;从Pending变为Rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果。就算改变已经发生了,你再对Promise对象田静回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。

    有了Promise对象,就可以把异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。此外,Promise对象提供了统一的接口,使得控制异步操作更加容易。

    60.promise 有几种状态, Promise 有什么优缺点 ?

    一个`Promise`可以有下面几种状态:
    • pending:初始状态,既不是成功也不是失败
    • fulfilled:意味着操作完全成功
    • rejected:意味着操作失败
    一个等待状态的promise对象能够成功后返回一个值,也能失败后带回一个错误
    当这两种情况发生的时候,处理函数会排队执行通过then方法会被调用

    Promise的优点:

    1) 一旦状态改变,就不会再变,任何时候都可以得到这个结果

    2) 可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数

    Promise的缺点:

    1) 无法取消 Promise

    2) 当处于pending状态时,无法得知目前进展到哪一个阶段

    61.如何实现 Promise.all ?

    1.Promise.all() 方法执行完成之后还是返回一个 promise对象 所以封装方法的时候必须最终返回一个promise对象

    function promiseAll(arrayPromise){
    return new Promise((resolve,reject)=>{
    })
    }

    2.传入Promise.all方法内的promise数组内所有执行完成最终耗时为最长耗时的promise,所以可以知道内部应该是promise数组内的方法都是异步执行的,并且最终返回的结果是一个按传入promise数组顺序的promise结果,还需要知道的是 只要其中一个 报错那么 就会 视作失败。

    function promiseAll(arrayPromise){
    return new Promise((resolve,reject)=>{
    const array = []; //最终返回的数组
    let count = 0;    
    arrayPromise.forEach(async (promise,index)=>{
    array[index] = await promise().catch((err)=>{
    reject(err); //只要其中一个 报错 那么 就抛出异常
    });
    count ++;
    if(count === arrayPromise.length){ //结果数组长度 等于参数数组长度 并且无空 视作完成
    resolve(array);
    }
    })})}

    62.解构赋值

    解构是一种打破数据结构,将其拆分为更小部分的过程。通过解构赋值, 可以将属性/值从对象/数组中取出,赋值给其他变量。

    数组的解构赋值
    数组中的值会自动被解析到对应接收该值的变量中,数组的解构赋值要一一对应 如果有对应不上的就是undefined

    var [name, pwd, sex]=["admin", "123456", "女"];
    console.log(name) //admin
    console.log(pwd)//123456
    console.log(sex)//女

    对象的解构赋值
    对象的解构与数组有一个重要的不同。数组的元素是按次序排列的,变量的取值由它的位置决定;而对象的属性没有次序,变量必须与属性同名,才能取到正确的值。

    var obj={name:"admin", pwd:"123456", sex:"女"}
    var {name, pwd, sex}=obj;
    console.log(name) //admin
    console.log(pwd)//123456
    console.log(sex)//女
    //若想要变量名和属性名不同
    let { foo: foz, bar: baz } = { foo: "111", bar: "222" };
    console.log(foz) // "111"
    console.log(foo) // error: foo is not defined

    63.set数据结构(可用于快速去重)

    Set数据结构,类似数组。所有的数据都是唯一的,没有重复的值。它本身是一个构造函数。

    属性和方法:

    size 数据的长度
    add() 添加某个值,返回 Set 结构本身。
    delete() 删除某个值,返回一个布尔值,表示删除是否成功。
    has() 查找某条数据,返回一个布尔值。
    clear() 清除所有成员,没有返回值。
    应用:数组去重。

    var arr = [1,1,2,2,3];
    var s = new Set(arr);
    console.log(s);    //{1, 2, 3}
    console.log(s.size);    //3
    console.log(s.add(4));    //{1, 2, 3, 4}
    console.log(s.delete(4));    //true
    console.log(s.has(4));    //false
    s.clear();

    64.Spread Operator 展开运算符(...)

    将字符串转成数组

    var str="abcd";
    console.log([...str]) // ["a", "b", "c", "d"]

    将集合转成数组

    var sets=new Set([1,2,3,4,5])
    console.log([...sets]) // [1, 2, 3, 4, 5]

    两个数组的合并

    var a1=[1,2,3];
    var a2=[4,5,6];
    console.log([...a1,...a2]); //[1, 2, 3, 4, 5, 6]

    在函数中,用来代替arguments参数
    rest参数  …变量名称

    rest 参数是一个数组 ,它的后面不能再有参数,不然会报错

    function func(...args){
    console.log(args);//[1, 2, 3, 4]
    }
    func(1, 2, 3, 4);
    function f(x, ...y) {
    console.log(x);
    console.log(y);
    }
    f('a', 'b', 'c'); //a 和 ["b","c"]
    f('a') //a 和 []
    f() //undefined 和 []

    65.字符串新增方法

    es6新增了4个字符串处理的方法:startsWith,endsWith,includes,repeat。

    let str="lxy";
            //字符串是否以某个字符开头
            console.log(str.startsWith('l'));//true
            console.log(str.startsWith('x'));//false
            //字符串是否以某个字符结尾
            console.log(str.endsWith('x'));//false
            console.log(str.endsWith('y'));//true
            //字符串是否包含某个字符
            console.log(str.includes('x'));//true
            console.log(str.includes('z'));//false
            //repeat()重复某个字符串几次
            console.log(str.repeat(3));//lxylxylxy
            console.log(str.repeat(5));//lxylxylxylxylxy

    includes(),startsWith(),endsWith()都支持第2个参数。

    使用第2个参数n时,endsWith的行为与其他两个方法有所不同。

    • endsWith针对前n个字符。

    • 其他2个方法:针对从第n个位置直到字符串结束的字符。

    var s="hello world!";
    s.startsWith('world',6);//true
    s.endsWith('hello',5);//true
    s.includes('hello',6);//false

    66.简述同步和异步的区别

    同步:所有的操作都做完,才返回给用户。这样用户在线等待的时间太长,给用户一种卡死了的感觉。这种情况下,用户不能关闭界面,如果关闭了,即迁移程序就中断了。

    异步:将用户请求放入消息队列,并反馈给用户,系统迁移程序已经启动,你可以关闭浏览器了。然后程序再慢慢地去写入数据库去。这就是异步。但是用户没有卡死的感觉,会告诉你,你的请求系统已经响应了。你可以关闭界面了。

    同步和异步本身是相对的

      同步就相当于是 当客户端发送请求给服务端,在等待服务端响应的请求时,客户端不做其他的事情。当服务端做完了才返回到客户端。这样的话客户端需要一直等待。用户使用起来会有不友好。

      异步就是,当客户端发送给服务端请求时,在等待服务端响应的时候,客户端可以做其他的事情,这样节约了时间,提高了效率。

    存在就有其道理 异步虽然好 但是有些问题是要用同步用来解决,比如有些东西我们需要的是拿到返回的数据在进行操作的。这些是异步所无法解决的。

    67.怎么添加、移除、复制、创建、和查找节点

    (1)创建新节点  

          createDocumentFragment()    //创建一个DOM片段

          createElement()   //创建一个具体的元素

          createTextNode()   //创建一个文本节点

    (2)添加、移除、替换、插入

          appendChild()  //这个方法一般是在指定元素节点的最后一个子节点之后添加节点

          removeChild()  //removeChild() 方法可从子节点列表中删除某个节点

          replaceChild()   //node.replaceChild(newnode,oldnode)

          insertBefore()  //insertBefore() 方法可在已有的子节点前插入一个新的子节点

    (3)查找

          getElementsByTagName()    //通过标签名称

          getElementsByName()    //通过元素的Name属性的值

          getElementById()    //通过元素Id,唯一性

      (4)复制
      cloneNode() 方法,用于复制节点, 接受一个布尔值参数, true 表示深复制(复制节点及其所有子节点), false 表示浅复制(复制节点本身,不复制子节点)

    68.实现一个函数clone 可以对Javascript中的五种主要数据类型(Number、string、Object、Array、Boolean)进行复制

    function clone(obj) {
        var o;
        switch (typeof obj) {
            case "undefined":
                break;
            case "string":
                o = obj + "";
                break;
            case "number":
                o = obj - 0;
                break;
            case "boolean":
                o = obj;
                break;
            case "object": // object 分为两种情况 对象(Object)或数组(Array)
                if (obj === null) {
                    o = null;
                } else {
                    if (Object.prototype.toString.call(obj).slice(8, -1) === "Array") {
                        o = [];
                        for (var i = 0; i < obj.length; i++) {
                            o.push(clone(obj[i]));
                        }
                    } else {
                        o = {};
                        for (var k in obj) {
                            o[k] = clone(obj[k]);
                        }
                    }
                }
                break;
            default:
                o = obj;
                break;
        }
        return o;
    }

    69.如何消除一个数组里面重复的元素

    即创建一个新数组,把原数组中的元素逐个添加到新数组中(判断新数组中是否已经包含原数组中的元素,如果没有,把原数组中的元素添加到新数组,如果已经存在,则不添加),因此就可以避免重复元素的产生了。请看下面的代码:

    var data = ['blue', 'red', 'green', 'blue'];
    
    function newData(data) {
        var nData = new Array();
        for (var i = 0; i < data.length; i++) {
            if (nData.indexOf(data[i]) == -1) {
                nData.push(data[i]);
            }
        }
        return nData;
    }
    newData(data);

    70.写一个返回闭包的函数

    1.闭包函数是指有权访问另一个函数作用域中的变量的函数
    2.创建闭包函数最常见的方式是在一个函数内创建另一个函数,通过另一个函数访问这个函数的局部变量

    3.闭包的特点:1函数嵌套函数,
             2 函数内部可以引用外部的参数和变量
             3 参数和变量不会被垃圾回收机制回收

    4.闭包的优点:1 希望一个变量长期驻扎在内存中 
           2 避免全局变量的污染 
           3 私有变量存在

    5.闭包的实现 1 函数嵌套函数 
           2 外层函数返回内层函数 
           3 外面有一全局变量接受外层函数

    function fun1() {
            var sum=0;
            function fun2() {
                sum++;
                return sum
            }
            return fun2
        }
        var s=fun1();
        console.log(s());

    返回闭包时牢记一点:返回函数不要引用任何循环变量,或者后续会发生变化的变量!

    71.使用递归完成1到100的累加

    function num(n){
        if(n==1) return 1;
        return num(n-1)+n;
    }
    num(100);

    72.如何判断数据类型

    1、最常见的判断方法:typeof      //alert(typeof a) ------------> string

    2、判断已知对象类型的方法: instanceof    //alert(c instanceof Array) ---------------> true

    3、根据对象的constructor判断: constructor    //alert(c.constructor === Array) ----------> true

    4、通用但很繁琐的方法: prototype    //alert(Object.prototype.toString.call(a) === ‘[object String]’) -------> true;

    5、无敌万能的方法:jquery.type()    //jQuery.type( 3 ) === "number"

    73.Js的事件委托是什么,原理是什么

    作用:

    1. 支持为同一个DOM元素注册多个同类型事件
    2. 可将事件分成事件捕获和事件冒泡机制

    事件委托的优点:

    1. 提高性能:每一个函数都会占用内存空间,只需添加一个事件处理程序代理所有事件,所占用的内存空间更少。
    2. 动态监听:使用事件委托可以自动绑定动态添加的元素,即新增的节点不需要主动添加也可以一样具有和其他元素一样的事件。

    用addEventListener(type,listener,useCapture)实现

    • type: 必须,String类型,事件类型
    • listener: 必须,函数体或者JS方法
    • useCapture: 可选,boolean类型。指定事件是否发生在捕获阶段。默认为false,事件发生在冒泡阶段

    事件捕获和事件冒泡机制

    事件捕获:当一个事件触发后,从Window对象触发,不断经过下级节点,直到目标节点。在事件到达目标节点之前的过程就是捕获阶段。

    事件冒泡:当事件到达目标节点后,会沿着捕获阶段的路线原路返回。

    js事件委托原理:把事件委托到父元素上,利用冒泡原理,当子元素点击时,由于冒泡原理,事件会冒泡到父元素上,父元素上面的事件就会触发执行。

    74.如何改变函数内部的this指针的指向

    1.如果一个函数,是某个对象的key 值,那么,this就指向这个对象。

    var a = function(obj)
    
    {
    alert(this == obj);
    }
    var o = {};
    o.afun = a;
    o.afun(o); //true
      函数就是一个变量,但是可以绑定到某个对象的下面,并且 this 就会指向 o 对象。
    这里必须要注意,没有被绑定的对象,默认this 指向window 对象

    2.如果函数new 了一下,那么就会创建一个对象,并且this 指向 新创建的对象。

    var o = new a();
    这个时候,o 不再是个函数,而实际上,可以认为是这样的一个过程。
    创建一个对象 var o = {};
    然后,把this 指向 o,通过this 把 o 给初始化了。

    3.通过apply 可以改变this 的指向

    var a = function (obj)
    {
    alert(this == obj);
    };
    obj.fun = a;
    obj.fun(obj);//true
      简单的,可以a.apply(obj, [obj]); // true

    javascript 的this 可以简单的认为是 后期绑定,没有地方绑定的时候,默认绑定window。

    75.谈谈垃圾回收机制的方式及内存管理

    回收机制方式
    1、定义和用法:垃圾回收机制(GC:Garbage Collection),执行环境负责管理代码执行过程中使用的内存。

    2、原理:垃圾收集器会定期(周期性)找出那些不在继续使用的变量,然后释放其内存。但是这个过程不是实时的,因为其开销比较大,所以垃圾回收器会按照固定的时间间隔周期性的执行。

    3、实例如下:

    function fn1() {
    var obj = {name: ‘hanzichi’, age: 10};
    }
    function fn2() {
    var obj = {name:‘hanzichi’, age: 10};
    return obj;
    }
    var a = fn1();
    var b = fn2();

      fn1中定义的obj为局部变量,而当调用结束后,出了fn1的环境,那么该块内存会被js引擎中的垃圾回收器自动释放;在fn2被调用的过程中,返回的对象被全局变量b所指向,所以该块内存并不会被释放。

    4、垃圾回收策略:标记清除(较为常用)和引用计数。

    标记清除:

      定义和用法:当变量进入环境时,将变量标记"进入环境",当变量离开环境时,标记为:“离开环境”。某一个时刻,垃圾回收器会过滤掉环境中的变量,以及被环境变量引用的变量,剩下的就是被视为准备回收的变量。

    到目前为止,IE、Firefox、Opera、Chrome、Safari的js实现使用的都是标记清除的垃圾回收策略或类似的策略,只不过垃圾收集的时间间隔互不相同。

    引用计数:

      定义和用法:引用计数是跟踪记录每个值被引用的次数。

      基本原理:就是变量的引用次数,被引用一次则加1,当这个引用计数为0时,被视为准备回收的对象。

    内存管理
    1、什么时候触发垃圾回收?

      垃圾回收器周期性运行,如果分配的内存非常多,那么回收工作也会很艰巨,确定垃圾回收时间间隔就变成了一个值得思考的问题。

      IE6的垃圾回收是根据内存分配量运行的,当环境中的变量,对象,字符串达到一定数量时触发垃圾回收。垃圾回收器一直处于工作状态,严重影响浏览器性能。

      IE7中,垃圾回收器会根据内存分配量与程序占用内存的比例进行动态调整,开始回收工作。

    2、合理的GC方案:(1)、遍历所有可访问的对象; (2)、回收已不可访问的对象。

    3、GC缺陷:(1)、停止响应其他操作;

    4、GC优化策略:(1)、分代回收(Generation GC);(2)、增量GC

    76.写一个function ,清除字符串前后的空格

    第一种:循环替换
    
    //供使用者调用  
    function trim(s){  
        return trimRight(trimLeft(s));  
    }  
    //去掉左边的空白  
    function trimLeft(s){  
        if(s == null) {  
            return "";  
        }  
        var whitespace = new String(" 	
    
    ");  
        var str = new String(s);  
        if (whitespace.indexOf(str.charAt(0)) != -1) {  
            var j=0, i = str.length;  
            while (j < i && whitespace.indexOf(str.charAt(j)) != -1){  
                j++;  
            }  
            str = str.substring(j, i);  
        }  
        return str;  
    }  
    
    //去掉右边的空白 www.2cto.com   
    function trimRight(s){  
        if(s == null) return "";  
        var whitespace = new String(" 	
    
    ");  
        var str = new String(s);  
        if (whitespace.indexOf(str.charAt(str.length-1)) != -1){  
            var i = str.length - 1;  
            while (i >= 0 && whitespace.indexOf(str.charAt(i)) != -1){  
               i--;  
            }  
            str = str.substring(0, i+1);  
        }  
        return str;  
    }     
    第二种:正则替换
    <SCRIPT LANGUAGE="JavaScript">  
    <!--  
    String.prototype.Trim = function()  
    {  
    return this.replace(/(^s*)|(s*$)/g, "");  
    }  
    String.prototype.LTrim = function()  
    {  
    return this.replace(/(^s*)/g, "");  
    }  
    String.prototype.RTrim = function()  
    {  
    return this.replace(/(s*$)/g, "");  
    }  
    //-->  
    </SCRIPT> 
    //去左空格;
    function ltrim(s){
        return s.replace(/(^s*)/g, "");
    }
    //去右空格;
    function rtrim(s){
        return s.replace(/(s*$)/g, "");
    }
    //去左右空格;
    function trim(s){
        return s.replace(/(^s*)|(s*$)/g, "");
    }
    第三种:使用jquery
    $().trim();
    jquery的内部实现为:
    function trim(str){   
        return str.replace(/^(s|u00A0)+/,'').replace(/(s|u00A0)+$/,'');   
    }
    第四种:使用motools
    function trim(str){   
        return str.replace(/^(s|xA0)+|(s|xA0)+$/g, '');   
    }  
    第五种:剪裁字符串方式
    function trim(str){   
        str = str.replace(/^(s|u00A0)+/,'');   
        for(var i=str.length-1; i>=0; i--){   
            if(/S/.test(str.charAt(i))){   
                str = str.substring(0, i+1);   
                break;   
            }   
        }   
        return str;   
    }  
    //----------------------------------------------------------
    //     去掉字符串前后的空格
    //    返回值:
    //    去除空格后的字符串
    //----------------------------------------------------------
    function trim(param) {
        if ((vRet = param) == '') { return vRet; }
        while (true) {
            if (vRet.indexOf (' ') == 0) {
                vRet = vRet.substring(1, parseInt(vRet.length));
            } else if ((parseInt(vRet.length) != 0) && (vRet.lastIndexOf (' ') == parseInt(vRet.length) - 1)) {
                vRet = vRet.substring(0, parseInt(vRet.length) - 1);
            } else {
                return vRet;
            }
        }
    }

    77.js实现继承的方法有哪些

    1. 原型链继承  //将构造函数的原型设置为另一个构造函数的实例对象,这样就可以继承另一个原型对象的所有属性和方法,可以继续往上,最终形成原型链。

    2. 借用构造函数继承  //为了解决原型中包含引用类型值的问题,开始使用借用构造函数,也叫伪造对象或经典继承

    3. 组合继承  //也叫伪经典继承,将原型链和借用构造函数的技术组合到一块。使用原型链实现对原型属性和方法的继承,而通过构造函数来实现对实例属性的继承。

    4. 原型式继承  //不自定义类型的情况下,临时创建一个构造函数,借助已有的对象作为临时构造函数的原型,然后在此基础实例化对象,并返回。

    5. 寄生式继承  //就是在原型式继承得到对象的基础上,在内部再以某种方式来增强对象,然后返回。

    6. 寄生组合式继承  //组合继承是JS中最常用的继承模式,但其实它也有不足,组合继承无论什么情况下都会调用两次超类型的构造函数,并且创建的每个实例中都要屏蔽超类型对象的所有实例属性。

    寄生组合式继承就解决了上述问题,被认为是最理想的继承范式

    78.判断一个变量是否是数组,有哪些办法

    1、instanceof

    function isArray (obj) {
      return obj instanceof Array;
    }

    2、Array对象的 isArray方法

    function isArray (obj) {
      return Array.isArray(obj);
    }

    3、Object.prototype.toString

    function isArray (obj) {
      return Object.prototype.toString.call(obj) === '[object Array]';
    }

    79.箭头函数与普通函数有什么区别

    箭头函数:

    let fun = () => {
        console.log('lalalala');
    }

    普通函数:

    function fun() {
        console.log('lalla');
    }

      箭头函数相当于匿名函数,并且简化了函数定义。箭头函数有两种格式,一种只包含一个表达式,连{ ... }和return都省略掉了。还有一种可以包含多条语句,这时候就不能省略{ ... }和return。

    总结

    • 箭头函数的 this永远指向其上下文的this,任何方法都改变不了其指向,如call(), bind(), apply().

    • 普通函数的this指向调用它的那个对象

    80.随机取1-10之间的整数

    var num=Math.floor(Math.random()*10+1);
    
    alert(num);  //所得到的的是1-10之间的随机数,每次刷新都不同

    81.new操作符具体干了什么

    new共经过了4个阶段

    1、创建一个空对象

    varobj=new Object();

    2、设置原型链

    obj.__proto__= Func.prototype;

    3、让Func中的this指向obj,并执行Func的函数体。

    var result =Func.call(obj);

    4、判断Func的返回值类型:

    如果是值类型,返回obj。如果是引用类型,就返回这个引用类型的对象。

    if (typeof(result) == "object"){
    func=result;
    }
    else{
    func=obj;;
    }

    82.Ajax原理

      Ajax的工作原理相当于在用户和服务器之间加了—个中间层(AJAX引擎),使用户操作与服务器响应异步化。并不是所有的用户请求都提交给服务器。像—些数据验证和数据处理等都交给Ajax引擎自己来做,,只有确定需要从服务器读取新数据时再由Ajax引擎代为向服务器提交请求。

      使用Ajax可以完成的功能:动态更新购物车的物品总数,无需用户单击Update并等待服务器重新发送整个页面。
      提升站点的性能,这是通过减少从服务器下载的数据量而实现的。例如,在购物车页面,当更新篮子中的一项物品的数量时,会重新载入整个页面,这必须下载数据。如果使用Ajax计算新的总量,服务器只会返回新的总量值,因此所需的带宽仅为原来的百分之一。
      消除了每次用户输入时的页面刷新。例如,在Ajax中,如果用户在分页列表上单击Next,则服务器数据只刷新列表而不是整个页面。
      直接编辑表格数据,而不是要求用户导航到新的页面来编辑数据。对于Ajax,当用户单击Edit时,可以将静态表格刷新为内容可编辑的表格。用户单击Done之后,就可以发出一个Ajax请求来更新服务器,并刷新表格,使其包含静态、只读的数据。 

    83.模块化开发怎么做

      模块化就是:1. 将大的个体分解成多个小的个体;2. 独立的、闭合的去分析处理这个个体和其与外界的关系;3. 将这些个体组织、集成为一个新的大的个体;4. 持续的、迭代的进行这个过程直至解决问题。

    模块化开发主要有两种方式模块:

      依赖加载。这种方式是最广泛的,像requirejs,sea.js等,除了 编写规范 不一样,实际都是通过相关require api把模块chunk文件拿回来,当加载完成之后再运行逻辑代码。

      依赖打包。经典代表就是webpack,其实就是写代码的时候分开模块,但打包的时候按依赖关系找到各个模块,最后打包到同一个文件上,并给每个chunk标识id,运行逻辑代码时将模块引用指向该id,从而实现模块化。

    84.xml和 json的区别

      (1).数据体积方面。JSON相对于XML来讲,数据的体积小,传递的速度更快些。

      (2).数据交互方面。JSON与JavaScript的交互更加方便,更容易解析处理,更好的数据交互。

      (3).数据描述方面。JSON对数据的描述性比XML较差。

      (4).传输速度方面。JSON的速度要远远快于XML。

    85.webpack如何实现打包的

    Webpack的工作方式是:把你的项目当做一个整体,通过一个给定的主文件(如:index.js),Webpack将从这个文件开始找到你的项目的所有依赖文件,使用loaders处理它们,最后打包为一个浏览器可识别的JavaScript文件。

    1.安装好npm,这个不再复述,然后在一个目录下执行 npm init,这样就会初始化一个项目包,里面就有了一个package.json的文件。

    2.然后安装一下webpack,既然我们想打包,就要把webpack这个工具安装好,安装方式有两种,一个是全局安装一个是安装在项目中,在项目的package.json目录下执行的命令分别是npm install -g webpack 和 npm install --save-dev webpack,在这里我们安装在项目里面,使用第二种安装方式

    3.安装完成之后我们能看到项目目录下有一个node_module的文件夹,然后我们就可以写自己的项目了,我们首先建立一个app和public的文件夹,在app中新建两个文件,分别是test.js和main.js,在pulic中新建一个index.html文件,这样我们的基本项目雏形就产生了

    4.我们在index.html中写入一下片段:

    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="utf-8">
        <title>Webpack Project</title>
      </head>
      <body>
        <div id='root'>
        </div>
        <script src="bundle.js"></script>
      </body>
    </html>

    5.我们在test.js中写入这样一个方法:

    //test.js
    module.exports = function() {
      var test= document.createElement('div');
      test.textContent = "Hi there and testing!";
      return test;
    };

    6.我们在main.js中把test.js的方法导入进来:

    //main.js 
    var test= require('./test.js');
    document.getElementById('root').appendChild(test());

    7.下面我们就可以使用webpack工具进行打包了,在项目的根目录,也就是包含node_module的目录下执行下面这个命令node_modules/.bin/webpack app/main.js public/bundle.js,这条命令的是使用webpack把打包后的文件命名为bundle.js放在public文件夹下,其中app/main,js是项目的入口。我们能看到终端上会打印出包含这样的log

    8.这就说明我们的打包工作完成了,然后我们打开index.html文件就能看到我们输入的内容:Hi there and testing!

    9.这样要配置项目入口,又要配置输出文件名之类的东西,在命令行输入比较麻烦,我们可以使用文件配置的方式,在项目的根目录中新建一个webpack.congfig.js的文件,把下面这些内容写入进去

    module.exports = {
      entry:  __dirname + "/app/main.js",//已多次提及的唯一入口文件
      output: {
        path: __dirname + "/public",//打包后的文件存放的地方
        filename: "bundle.js"//打包后输出文件的文件名
      }
    }

    这样我们就可以直接使用node_modules/.bin/webpack直接进行打包操作了

    10.如果我们不想使用node_modules/.bin/webpack这样的命令,习惯使用npm xxx之类的,我们在我们的package.json中设置一下启动命令即可:

    "scripts": {
        "webpack": "webpack" //配置的地方就是这里啦
      }

    然后我们直接执行npm run webpack同样可以执行打包任务

    11.接下来我们介绍,如何直接引入json类型的文件,这里我们使用loaders模块,先说一下应用场景吧。我们现在有一个json文件,我们想把它导入到模块中,然后读取里面的信息,下面我们的文件目录是这样的:

    12.如果我们想在任意一个模块,如test.js或者main.js中导入这个json文件,比如,我们的test.json文件中有这样一个内容

    //test.json
    {
      "Test": "Hi there and geetings from JSON!"
    }

    我们想在test.js使用这样Test字段

    var test = require('./test.json');
    module.exports = function() {
      var geet = document.createElement('div');
      geet.textContent = test.greetText;
      return geet;
    };

    我们就要引入json-loader,具体的办法是:在根目录下执行

    //安装可以装换JSON的loader

    npm install --save-dev json-loader

    然后把我们的webpack.config.js配置成下面这样

    module.exports = {
      entry:  __dirname + "/app/main.js",
      output: {
        path: __dirname + "/public",
        filename: "bundle.js"
      },
      module: {//在配置文件里添加JSON loader
        loaders: [
          {
            test: /.json$/,
            use: "json-loader"
          }]}}

    最后我们执行一下npm run webpack,打包完成,打开index.html页面就会显示test.json里面的Hi there and geetings from JSON!这个内容

    13.如果我们想把css样式也一起打包,就npm install --save-dev style-loader css-loader,然后在webpack.config.js进行相应的配置就行了,这样是把js和css打包成一个文件,也可以把他们分开打包。

    86.常见web安全及防护原理

    sql注入原理:就是通过把SQL命令插入到Web表单递交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令

    防范:1.永远不要信任用户的输入,要对用户的输入进行校验,可以通过正则表达式,或限制长度,对单引号和双"-"进行转换等。

       2.永远不要使用动态拼装SQL,可以使用参数化的SQL或者直接使用存储过程进行数据查询存取。

       3.永远不要使用管理员权限的数据库连接,为每个应用使用单独的权限有限的数据库连接。

       4.不要把机密信息明文存放,请加密或者hash掉密码和敏感的信息

    xss:跨站脚本(Cross-site Scripting)是一种网站应用程序的安全漏洞攻击,是代码注入的一种。它允许恶意用户将代码注入到网页上,其他用户在观看网页时就会受到影响。这类攻击通常包含了HTML以及用户端脚本语言。例如:攻击者在论坛中放一个看似安全的链接,骗取用户点击后,窃取cookie中的用户私密信息;或者攻击者在论坛中加一个恶意表单,当用户提交表单的时候,却把信息传送到攻击者的服务器中,而不是用户原本以为的信任站点。

    防范:1.首先代码里对用户输入的地方和变量都需要仔细检查长度和对”<” , ”>” ,  ”;” , ”’” 等字符做过滤;其次任何内容写到页面之前都必须加以encode,避免不小心把html tag 弄出来。这一个层面做好,至少可以堵住超过一半的XSS 攻击。

       2.永远不要使用动态拼装SQL,可以使用参数化的SQL或者直接使用存储过程进行数据查询存取。

         3.永远不要使用管理员权限的数据库连接,为每个应用使用单独的权限有限的数据库连接。

         4.不要把机密信息明文存放,请加密或者hash掉密码和敏感的信息

    CSRF跨站请求伪造(英语:Cross-site request forgery),也被称为 one-click attack 或者 session riding,通常缩写为 CSRF 或者 XSRF, 是一种挟制用户在当前已登录的Web应用程序上执行非本意的操作的攻击方法。就是说冒充用户发起请求(在用户不知情的情况下),完成一些违背用户意愿的请求(如恶意发帖,删帖,改密码,发邮件等)。只要是伪造用户发起的请求,都可成为CSRF攻击。

    防范:服务端的CSRF方式方法很多样,但总的思想都是一致的,就是在客户端页面增加伪随机数。通过验证码的方法

    XSS与CSRF的区别:

      1.XSS是获取信息,不需要提前知道其他用户页面的代码和数据包。CSRF是代替用户完成指定的动作,需要知道其他用户页面的代码和数据包。

      2.要完成一次CSRF攻击,受害者必须依次完成两个步骤:a.登录受信任网站A,并在本地生成Cookie。b.在不登出A的情况下,访问危险网站B。

    87.用过哪些设计模式

    工厂模式:

      主要好处就是可以消除对象间的耦合,通过使用工程方法而不是new关键字。将所有实例化的代码集中在一个位置防止代码重复。

          工厂模式解决了重复实例化的问题 ,但还有一个问题,那就是识别问题,因为根本无法 搞清楚他们到底是哪个对象的实例。

    function createObject(name,age,profession){//集中实例化的函数var obj = new Object();
        obj.name = name;
        obj.age = age;
        obj.profession = profession;
        obj.move = function () {
            return this.name + ' at ' + this.age + ' engaged in ' + this.profession;
        };
        return obj;
    }
    var test1 = createObject('trigkit4',22,'programmer');//第一个实例var test2 = createObject('mike',25,'engineer');//第二个实例

    构造函数模式:使用构造函数的方法 ,即解决了重复实例化的问题 ,又解决了对象识别的问题,该模式与工厂模式的不同之处在于:

    1.构造函数方法没有显示的创建对象 (new Object());

    2.直接将属性和方法赋值给 this 对象;

    3.没有 renturn 语句。

    88.为什么要同源限制

      我们举例说明:比如一个黑客程序,他利用Iframe把真正的银行登录页面嵌到他的页面上,当你使用真实的用户名,密码登录时,他的页面就可以通过Javascript读取到你的表单中input中的内容,这样用户名,密码就轻松到手了。

      缺点:现在网站的JS 都会进行压缩,一些文件用了严格模式,而另一些没有。这时这些本来是严格模式的文件,被 merge 后,这个串就到了文件的中间,不仅没有指示严格模式,反而在压缩后浪费了字节。

    89.javascript有哪些方法定义对象

    方式一:
    通过对象字面量表示法(又称为直接量、原始方式)。
    var obj = {name:"moyu"};
    方式二:
    通过new和构造函数Object()、String()等。
    var obj = new Object();
    方式三:
    自定义一个对象的构造函数,然后实例化对象。
    function a(o){
    this.name = "moyu"
    }
    var obj = new a();
    方式四:
    通过Object.create()
     
    var o1 = Object.create({x:1, y:2});      // o1继承了属性x和y

    90.谈谈你对AMD、CMD的理解

    AMD(异步模块定义)规范, CMD (通用模块定义)规范。

    区别:
    1. 对于依赖的模块,AMD 是提前执行,CMD 是延迟执行。不过 RequireJS 从 2.0 开始,也改成可以延迟执行(根据写法不同,处理方式不同)。CMD 推崇 as lazy as possible.
    2. CMD 推崇依赖就近,AMD 推崇依赖前置。

    // CMD
    define(function(require, exports, module) {
    var a = require('./a')
    a.doSomething()
    // 此处略去 100 行
    var b = require('./b') // 依赖可以就近书写
    b.doSomething()
    // ...
    })
    // AMD 默认推荐的是
    define(['./a', './b'], function(a, b) { // 依赖必须一开始就写好
    a.doSomething()
    // 此处略去 100 行
    b.doSomething()
    ...
    })

    虽然 AMD 也支持 CMD 的写法,同时还支持将 require 作为依赖项传递,但 RequireJS 的作者默认是最喜欢上面的写法,也是官方文档里默认的模块定义写法。
    3. AMD 的 API 默认是一个当多个用,CMD 的 API 严格区分,推崇职责单一。比如 AMD 里,require 分全局 require 和局部 require,都叫 require。CMD 里,没有全局 require,而是根据模块系统的完备性,提供 seajs.use 来实现模块系统的加载启动。CMD 里,每个 API 都简单纯粹。

    91.web开发中会话跟踪的方法有哪些

      会话跟踪引入的原因:HTTP是一种无状态协议,每当用户发出请求时,服务器就会做出响应,客户端与服务器之间的联系是离散的、非连续的。当用户在同一网站的多个页面之间转换时,根本无法确定是否是同一个客户,会话跟踪技术就可以解决这个问题。当一个客户在多个页面间切换时,服务器会保存该用户的信息。

    • 隐藏表单域:<input type="hidden">非常适合步需要大量数据存储的会话应用。
    • URL 重写:URL 可以在后面附加参数,和服务器的请求一起发送,这些参数为名字/值对。
    • Cookie:一个 Cookie 是一个小的,已命名数据元素。服务器使用 SET-Cookie 头标将它作为 HTTP响应的一部分传送到客户端,客户端被请求保存 Cookie 值,在对同一服务器的后续请求使用一个Cookie 头标将之返回到服务器。与其它技术比较,Cookie 的一个优点是在浏览器会话结束后,甚至在客户端计算机重启后它仍可以保留其值。
    • Session:使用 setAttribute(String str,Object obj)方法将对象捆绑到一个会话
    • IP地址

    92.介绍js有哪些内置对象?

    Arguments 函数参数集合
    Array 数组
    Boolean 布尔对象
    Date 日期时间
    Error 异常对象
    Function 函数构造器
    Math 数学对象
    Number 数值对象
    Object 基础对象
    RegExp 正则表达式对象
    String 字符串对象

    93.说几条写JavaScript的基本规范?

    • 不要在同一行声明多个变量

    • 请使用 === / !==来比较true/false或者数值

    • 请使用对象字面量替代new Array 这种形式

    • 不要使用全局函数

    • switch 语句必须带有default分支

    • 函数不应该有时候有返回值,有时候没有返回值

    • fo r循环必须使用大括号

    • if 语句必须使用大括号

    • for - in 循环中的变量应该使用var关键字明确限定作用域,从而避免作用域污染

    94.javascript创建对象的几种方式?

    1、通过Object构造函数或对象字面量创建单个对象;缺点:使用同一个接口创建很多对象,会产生大量的重复代码。

    2、工厂模式;考虑在ES中无法创建类(ES6前),开发人员发明了一种函数,用函数来封装以特定接口创建对象的细节。(实现起来是在一个函数内创建好对象,然后把对象返回)。工厂模式虽然解决了创建多个相似对象的问题,但却没有解决对象识别的问题,即怎么知道一个对象的类型。

    3、构造函数模式;像Object和Array这样的原生构造函数,在运行时会自动出现在执行环境。此外,也可以创建自定义的构造函数,从而定义自定义对象类型的属性和方法

     与工厂模式相比,具有以下特点:

    • 没有显式创建对象;
    • 直接将属性和方法赋给了this对象;
    • 没有return语句;
    • 要创建新实例,必须使用new操作符;(否则属性和方法将会被添加到window对象)
    • 可以使用instanceof操作符检测对象类型

      构造函数内部的方法会被重复创建,不同实例内的同名函数是不相等的。可通过将方法移到构造函数外部解决这一问题,但面临新问题:封装性不好。

    4、原型模式;我们创建的每个函数都有一个prototype属性,这个属性是一个指针,指向一个对象,而这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法。(prototype就是通过调用构造函数而创建的那个对象实例的原型对象)。

      使用原型对象的好处是可以让所有对象实例共享它所包含的属性和方法。换句话说,不必在构造函数中定义对象实例的信息,而是可以将这些信息直接添加到原型对象中。

    原型对象的问题:

    • 他省略了为构造函数传递初始化参数这一环节,结果所有实例在默认情况下都将取得相同的属性值,虽然这会在一定程度带来一定的不便,但不是最大的问题,最大的问题是由其共享的本性所决定的。
    • 对于包含基本值的属性可以通过在实例上添加一个同名属性隐藏原型中的属性。然后,对于包含引用数据类型的值来说,会导致问题。

      这些问题导致很少单独使用原型模式。

    5、组合使用构造函数模式和原型模式;

    这是创建自定义类型的最常见的方式。

      构造函数模式用于定义实例属性,而原型模式用于定义方法和共享的属性。所以每个实例都会有自己的一份实例属性的副本,但同时共享着对方法的引用,最大限度的节省了内存。同时支持向构造函数传递参数。

    6、动态原型模式;只会在初次调用构造函数时才执行。对原型所做的修改,能够立刻在所有实例中得到反映。

    7、Object.create();ES5定义了一个名为Object.create()的方法,它创建一个新对象,其中第一个参数是这个对象的原型,第二个参数对对象的属性进行进一步描述。

    95.eval是做什么的?

      eval()的作用:把字符串参数解析成JS代码并运行,并返回执行的结果;例如:

    eval("2+3");//执行加运算,并返回运算值。
    eval("varage=10");//声明一个age变量

    应该避免使用eval,不安全,非常耗性能(2次,一次解析成js语句,一次执行)。

    96.[“1”, “2”, “3”].map(parseInt) 答案是多少?

    答案是:[1, NaN, NaN].

    原因:主要是下面这3点

    • map函数传递参数的定义
    • parseInt函数针对于radix这个参数的理解
    • 二进制当中没有"3"这个数码

    97.说说严格模式的限制

    变量必须声明后再使用
    函数的参数不能有同名属性,否则报错
    不能使用with语句
    不能对只读属性赋值,否则报错
    不能使用前缀0表示八进制数,否则报错
    不能删除不可删除的属性,否则报错
    不能删除变量delete prop,会报错,只能删除属性delete global[prop]
    eval不会在它的外层作用域引入变量
    eval和arguments不能被重新赋值
    arguments不会自动反映函数参数的变化
    不能使用arguments.callee
    不能使用arguments.caller
    禁止this指向全局对象
    不能使用fn.caller和fn.arguments获取函数调用的堆栈
    增加了保留字(比如protected、static和interface

    注:经过测试IE6,7,8,9均不支持严格模式

    98.attribute和property的区别是什么?

      property 和 attribute非常容易混淆,两个单词的中文翻译也都非常相近(property:属性,attribute:特性),但实际上,二者是不同的东西,属于不同的范畴。

    • property是DOM中的属性,是JavaScript里的对象;
    • attribute是HTML标签上的特性,它的值只能够是字符串;

    简单理解,Attribute就是dom节点自带的属性,例如html中常用的id、class、title、align等。

    而Property是这个DOM元素作为对象,其附加的内容,例如childNodes、firstChild等。

    99.函数防抖节流的原理

      函数防抖,就是指触发事件后在 n 秒内函数只能执行一次,如果在 n 秒内又触发了事件,则会重新计算函数执行时间。简单的说,当一个动作连续触发,则只执行最后一次。打个比方,坐公交,司机需要等最后一个人进入才能关门。每次进入一个人,司机就会多等待几秒再关门。

      函数节流(throttle),限制一个函数在一定时间内只能执行一次。举个例子,乘坐地铁,过闸机时,每个人进入后3秒后门关闭,等待下一个人进入。

    100.为什么console.log(0.2+0.1==0.3) //false

    在JavaScript中的二进制的浮点数0.1和0.2并不是十分精确,在他们相加的结果并非正好等于0.3,而是一个比较接近的数字 0.30000000000000004 ,所以条件判断结果为 false

      那么应该怎样来解决0.1+0.2等于0.3呢? 最好的方法是设置一个误差范围值,通常称为”机器精度“,而对于 JavaScript 来说,这个值通常是2^-52,而在 ES6 中,已经为我们提供了这样一个属性:Number.EPSILON,而这个值正等于2^-52。这个值非常非常小,在底层计算机已经帮我们运算好,并且无限接近0,但不等于0,。这个时候我们只要判断(0.1+0.2)-0.3小于Number.EPSILON,在这个误差的范围内就可以判定0.1+0.2===0.3为true

    function numbersEqual(a,b){
        return Math.abs(a-b)<Number.EPSILON;
    }
    var a=0.1+0.2, b=0.3;
    console.log(numbersEqual(a,b));    //true

    101.说一下JS中类型转换的规则?

    显式转换:

    通过手动进行类型转换,Javascript提供了以下转型函数:

    1. 转换为数值类型:Number(mix)、parseInt(string,radix)、parseFloat(string)

    2. 转换为字符串类型:toString(radix)、String(mix)

    3. 转换为布尔类型:Boolean(mix)

    隐式转换:

    1、 isNaN(mix)

    2、递增递减操作符(包括前置和后置)、一元正负符号操作符

    3、 加法运算操作符

    4、 乘除、减号运算符、取模运算符

    5、 逻辑操作符(!、&&、||) 逻辑非(!)操作符

    6、 关系操作符(<, >, <=, >=)

    7、 相等操作符(==)

    102.深拷贝和浅拷贝的区别?如何实现

      如何区分深拷贝与浅拷贝,简单点来说,就是假设B复制了A,当修改A时,看B是否会发生变化,如果B也跟着变了,说明这是浅拷贝,拿人手短,如果B没变,那就是深拷贝,自食其力。

    103.什么是变量提升

    JavaScript 中,函数及变量的声明都将被提升到函数的最顶部。

    JavaScript 中,变量可以在使用后声明,也就是变量可以先使用再声明。

    牢记这三点:

    只有声明本身会被提升,而赋值操作不会被提升。

    变量会提升到其所在函数的最上面,而不是整个程序的最上面。

    函数声明会被提升,但函数表达式不会被提升。

    104.call、apply以及bind函数内部实现是怎么样的

      call, apply, bind都是改变函数执行的上下文,说的直白点就是改变了函数this的指向。不同的是:call和apply改变了函数的this,并且执行了该函数,而bind是改变了函数的this,并返回一个函数,但不执行该函数。

    var doThu = function(a, b) {
        console.log(this)
        console.log(this.name)
        console.log([a, b])
    }
    var stu = {
        name: 'shanliang',
        doThu: doThu,
    }
    stu.doThu(1, 2) // stu对象 xiaoming [1, 2]
    doThu.call(stu, 1, 2) // stu对象 xiaoming [1, 2]

      由此可见,在stu上添加一个属性doThu,再执行这个函数,就将doThu的this指向了stu。而call的作用就与此相当,只不过call为stu添加了doThu方法后,执行了doThu,然后再将doThu这个方法从stu中删除。

    call函数的内部实现原理:

    Function.prototype.call = function(thisArg, args) {
        // this指向调用call的对象
        if (typeof this !== 'function') { // 调用call的若不是函数则报错
            throw new TypeError('Error')
        }
        thisArg = thisArg || window
        thisArg.fn = this   // 将调用call函数的对象添加到thisArg的属性中
        const result = thisArg.fn(...[...arguments].slice(1)) // 执行该属性
        delete thisArg.fn   // 删除该属性
        return result
    }

    apply的内部实现原理:

    Function.prototype.apply = function(thisArg, args) {
        if (typeof this !== 'function') { 
            throw new TypeError('Error')
        }
        thisArg = thisArg || window
        thisArg.fn = this
        let result
        if(args) {
            result = thisArg.fn(...args)
        } else {
            result = thisArg.fn()
        }
        delete thisArg.fn
        return result
    }

    bind的实现原理比call和apply要复杂一些,bind中需要考虑一些复杂的边界条件。bind后的函数会返回一个函数,而这个函数也可能被用来实例化:

    Function.prototype.bind = function(thisArg) {
        if(typeof this !== 'function'){
            throw new TypeError(this + 'must be a function');
        }
        // 存储函数本身
        const _this  = this;
        // 去除thisArg的其他参数 转成数组
        const args = [...arguments].slice(1)
        // 返回一个函数
        const bound = function() {
            // 可能返回了一个构造函数,我们可以 new F(),所以需要判断
            if (this instanceof bound) {
                return new _this(...args, ...arguments)
            }
            // apply修改this指向,把两个函数的参数合并传给thisArg函数,并执行thisArg函数,返回执行结果
            return _this.apply(thisArg, args.concat(...arguments))
        }
        return bound
    }

    105.为什么会出现setTimeout倒计时误差?如何减少

      js是单线程的,是操作系统能够进行运算的最小单位,按代码书写顺序从头到尾,一行一行地执行代码,如果其中一行代码报错,那么剩下代码将不再执行。容易阻塞代码。执行栈可以理解为是用来存储函数调用的栈,遵循先进后出的原则。

      Node 的 Event Loop 分为 6 个阶段,它们会按照顺序反复运行。每当进入某一个阶段的时候,都会从对应的回调队列中取出函数去执行。当队列为空或者执行的回调函数数量到达系统设定的阈值,就会进入下一阶段。

    Event Loop 6 个阶段:

    1. timers

    2. I/O callbacks

    3. idle, prepare

    4. poll

    5. check

    6. close callbacks

    微任务(microtask):

    • process.nextTick

    • promise

    • Object.observe(曾经是提案,如今已经废除)

    • MutationOberver

    宏任务(macrotask):

    • script

    • setTimeout

    • setInterval

    • setImmediate

    • I/O

    • UI渲染

    执行顺序如下:

    • 执行同步代码,这是宏任务

    • 执行栈为空,查询是否有微任务要执行

    • 必要时渲染UI

    • 进行下一轮的 EventLoop ,执行宏任务中的异步代码

    定时器是属于 宏任务(macrotask) 。如果当前 执行栈 所花费的时间大于 定时器 时间,那么定时器的回调在 宏任务(macrotask) 里,来不及去调用,所有这个时间会有误差。

    setTimeout(function () {
        console.log('biubiu');
    }, 1000);
    
    某个执行时间很长的函数();

      如果定时器下面的函数执行要 5秒钟,那么定时器里的log 则需要 5秒之后再执行,函数占用了当前 执行栈 ,要等执行栈执行完毕后再去读取 微任务(microtask),等 微任务(microtask) 完成,这个时候才会去读取 宏任务(macrotask) 里面的 setTimeout 回调函数执行。setInterval 同理,例如每3秒放入宏任务,也要等到执行栈的完成。

    服务器当前时间=发请求时服务器时间+(客户端当前时间-客户端发请求时间),解决方法:

    countdown: function() { //倒计时
    var countdown_timer;
    var client_current_time = new Date(); //客户端当前时间
    var start_time_date = new Date(start_time); //活动开始时间
    var server_time_date = new Date(server_time); //发请求时服务器端的时间
    var server_current_time = server_time_date.getTime() + (client_current_time.getTime() - client_request_time.getTime()); //服务器端当前时间
    coundownTime = (start_time_date.getTime() - server_current_time) / 1000; //服务器端,活动开始时间与当前时间的时间差
    if(coundownTime <= 0) {
    clearTimeout(countdown_timer);
    this.$nextTick(function() {
    this.indexDom();
    })
    return;
    }
    this.countdown_hours = time_add_zero((Math.floor(coundownTime / 60 / 60))); //
    this.countdown_min = time_add_zero(Math.floor(coundownTime / 60 % 60)); //
    this.countdown_sec = time_add_zero(Math.floor(coundownTime % 60)); //
    countdown_timer = setTimeout(this.countdown, 500);
    }
    function time_add_zero(n) { //倒计时的 时/分/秒,如果小于10则在数字前面补0
      if(n < 10) {
      return '0' + n;
      } else {
      return n;
      }
    }

    106.谈谈你对JS执行上下文栈和作用域链的理解

      执行上下文(Execution Contexts)是一种规范设备,用于跟踪ECMAScript实现对代码的 运行时(runtime) 评估。在任何时间点,每个代理程序最多只有一个执行上下文实际执行代码。这称为 代理程序 的 运行执行上下文(running execution context]) 。

      执行上下文堆栈(execution context stack)用于跟踪执行上下文。正在运行的执行上下文始终是此堆栈的顶级元素。每当控制从与当前运行的执行上下文相关联的可执行代码转移到与该执行上下文无关的可执行代码时,就创建新的执行上下文。新创建的执行上下文被压入堆栈并成为正在运行的执行上下文。

      作用域链(Scope chain) 始终是 词法 创建的。 作用域 的父节点由 执行上下文(函数) 在代码中的词法或物理位置定义。

    • 每当编译器遇到变量或对象时,它都会遍历当前执行上下文的整个 作用域链(Scope chain) ,以查找它。如果没有在那里找到它,它遍历 原型链(prototype chain) ,如果它也没有找到,它会抛出未定义的错误。
    • 编译器通过查看函数在代码中的位置来创建函数的作用域。
    • 编译器创建称为 作用域链(Scope chain) 的等级层次结构, 全局作用域(Global Scope) 位于此层次结构的顶部。
    • 当代码中使用变量时,编译器会向后查看作用域链,如果找不到,则抛出未定义的错误。

    107.new的原理是什么?通过new的方式创建对象和通过字面量创建有什么区别?

    new的作用:

    1.创建一个空对象
    2.由this变量引用该对象
    3.该对象继承该函数的原型
    4.把属性和方法加入到this引用的对象中
    5.新创建的对象由this引用,最后隐式地返回this。

    let obj = {};//创建一个空对象
    obj.__proto__ = Person.prototype;//该对象继承该函数的原型
    Person.call(obj);//隐式地返回this

      new创建对象和字面量创建本质上是一样的,字面量的方式比较简单,也不用调用构造函数,性能较好。以下两种方法都可以:

    function Person(type) {
            this.type = type;
            // return 10;//Primitive value returned from constructor will be lost when called with 'new'
            // return {age:20};
        }
    //做出请求 let p = new Person('哺乳类'); console.log(p);
    /**
     * mockNew(构造器,构造器参数)
     */
    function mockNew() {
            let Constructor = [].shift.call(arguments);//拿到第一个参数(构造器)
            let obj = {};//创建一个对象
            obj.__proto__ = Constructor.prototype;//将新创建的对象的原型指向Constructor的prototype
            let res = Constructor.apply(obj,arguments);//调用Constructor并将其他参数传入
            //判断构造函数返回值的类型,若为object类型则返回res,若res为基本数据类型,则返回obj
            return res instanceof Object ? res : obj;
        }
    //提出请求 let p = mockNew(Person,'哺乳类'); console.log(p);

    108.取数组的最大值(ES5、ES6)

    // ES5 的写法

    Math.max.apply(null, [14, 3, 77, 30]);

    // ES6 的写法

    Math.max(...[14, 3, 77, 30]);
    // reduce
    [14,3,77,30].reduce((accumulator, currentValue)=>{
        return accumulator = accumulator > currentValue ? accumulator : currentValue
    });

    109.如何判断img加载完成

    1.load事件

    <!DOCTYPE HTML>
    <html>
    <head>
        <meta charset="utf-8">
        <title>img - load event</title>
    </head>
    <body>
        <img id="img1" src="http://pic1.win4000.com/wallpaper/f/51c3bb99a21ea.jpg">
        <p id="p1">loading...</p>
        <script type="text/javascript">
            img1.onload = function() {
                p1.innerHTML = 'loaded'
            }
        </script>
    </body>
    </html>

    所有浏览器都显示出了“loaded”,说明所有浏览器都支持img的load事件

    2.readystatechange事件

    <!DOCTYPE HTML>
    <html>
    <head>
        <meta charset="utf-8">
        <title>img - readystatechange event</title>
    </head>
    <body>
        <img id="img1" src="http://pic1.win4000.com/wallpaper/f/51c3bb99a21ea.jpg">
        <p id="p1">loading...</p>
        <script type="text/javascript">
            img1.onreadystatechange = function() {
                if(img1.readyState=="complete"||img1.readyState=="loaded"){
                    p1.innerHTML = 'readystatechange:loaded'
                }
            }
        </script>
    </body>
    </html>

    readyState为complete和loaded则表明图片已经加载完毕。测试IE6-IE10支持该事件,其它浏览器不支持。

    3.img的complete属性

    <!DOCTYPE HTML>
    <html>
    <head>
        <meta charset="utf-8">
        <title>img - complete attribute</title>
    </head>
    <body>
        <img id="img1" src="http://pic1.win4000.com/wallpaper/f/51c3bb99a21ea.jpg">
        <p id="p1">loading...</p>
        <script type="text/javascript">
            function imgLoad(img, callback) {
                var timer = setInterval(function() {
                    if (img.complete) {
                        callback(img)
                        clearInterval(timer)
                    }
                }, 50)
            }
            imgLoad(img1, function() {
                p1.innerHTML('加载完毕')
            })
        </script>
    </body>
    </html>

    如果图片加载失败,在IE中complete的值一直为false,而其他浏览器最后会变为true

    110.如何阻止冒泡?

    <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default5.aspx.cs"Inherits="Default5"%>
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
    <title>Porschev---Jquery 事件冒泡</title>
    <script src="jquery-1.3.2-vsdoc.js" type="text/javascript">
    </script>
    </head>
      <body>   
        <form id="form1" runat="server">     
          <div id="divOne" onclick="alert('我是最外层');">    
            <div id="divTwo" onclick="alert('我是中间层!')">    
            <a id="hr_three" href="http://www.baidu.com" mce_href="http://www.baidu.com"onclick="alert('我是最里层!')">点击我</a>    
            </div>   
          </div>  
        </form>
      </body>
    </html>

    事件冒泡过程(以标签ID表示):hr_three----> divTwo----> divOne 。从最里层冒泡到最外层。

      1.event.stopPropagation(); <script type="text/javascript"> $(function() { $("#hr_three").click(function(event) { event.stopPropagation(); }); }); <script> 再点击“点击我”,会弹出:我是最里层,然后链接到百度 2.return false; 如果头部加入的是以下代码 <script type="text/javascript"> $(function() {   $("#hr_three").click(function(event) {     return false; }); }); <script> 再点击“点击我”,会弹出:我是最里层,但不会执行链接到百度页面。

    由此可以看出:
      1.event.stopPropagation(); 事件处理过程中,阻止了事件冒泡,但不会阻击默认行为(它就执行了超链接的跳转)2.return false;事件处理过程中,阻止了事件冒泡,也阻止了默认行为(比如刚才它就没有执行超链接的跳转)还有一种有冒泡有关的:3.event.preventDefault(); 如果把它放在头部A标签的click事件中,点击“点击我”。会发现它依次弹出:我是最里层---->我是中间层---->我是最外层,但最后却没有跳转到百度它的作用是:事件处理过程中,不阻击事件冒泡,但阻击默认行为(它只执行所有弹框,却没有执行超链接跳转)。

    111.如何阻止默认事件?

    //全支持
    event.preventDefault();
    //该特性已经从 Web 标准中删除,虽然一些浏览器目前仍然支持它,但也许会在未来的某个时间停止支持,请尽量不要使用该特性。
    window.event.returnValue = false;
    //不建议滥用,jq中可以同时阻止冒泡和默认事件
    return false;
    // 兼容
    stopDefault(event);

    112.ajax请求时,如何解释json数据

    前端解析后端数据:
      前端在解析后端发来的数据,使用JSON.parse()方法把字符串转为json对象.

    前端向后端发送数据数据:
      前端在向后端发送数据,使用JSON.stringify()方法把json对象转为字符串.(使用jquery或者axios时,这些库内置了这些方法,只需设置配置项即可.)

    var jsonDate = '{ "name":"hello","age":23 }';
    var jsonObj = JSON.parse( jsonDate ); 
    // jsonObj为{ "name":alert("hello"),"age":23 }
    //JSON.parse()与JSON.stringify()实际功能一个去单引号,一个加单引号

    113.json和jsonp的区别?

    JSON是一种数据格式的定义,JSONP则是数据传输的方式。一个是静止的,一个是动态的。

    JSON是一种数据交换格式,而JSONP是一种依靠开发人员的聪明才智创造出的一种非官方跨域数据交互协议。

    json的特点:

    1)、基于纯文本,跨平台传递极其简单;
    2)、Javascript原生支持,后台语言几乎全部支持;
    3)、轻量级数据格式,占用字符数量极少,特别适合互联网传递;
    4)、可读性较强,虽然比不上XML那么一目了然,但在合理的依次缩进之后还是很容易识别的;
    5)、容易编写和解析,当然前提是你要知道数据结构;

    jsonp的使用方法 :

      jsonp的出现是为了解决Ajax跨域请求问题,所谓的跨域请求问题,即访问不同的域 (只要协议、域名、端口有任何一个不同,都被当作是不同的域) 的资源的时候会被拒绝。

    jsonp传输方式的原理:

      因为在HTML标签中<script>、<img>、<iframe>三个标签的跨域访问不受限制,所以其实可以利用这三个标签,把原来直接通过Ajax请求结果数据的方式,换为请求返回一段js代码,而这段代码可以通过<script>标签插入到DOM结构中,从而被执行,比较特别的是这段js代码其实就是一个包装了JSON数据的JS函数。具体可以表述为下面代码:

    $.getJSON('http://example.com/data.php?callback=?,function(jsondata)'){
           //处理获得的json数据
       });

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

    代码如下:

    Var btn=document.getElementById(‘btn’);
    //事件监听 绑定多个事件
    
    var btn4 = document.getElementById("btn4");
    btn4.addEventListener("click",hello1);
    btn4.addEventListener("click",hello2);
    function hello1(){
    alert("hello 1");
    }
    function hello2(){
    alert("hello 2");
    }

    115.拖拽会用到哪些事件

    ondragstart 事件:当拖拽元素开始被拖拽的时候触发的事件,此事件作用在被拖曳元素上
    ondragenter 事件:当拖曳元素进入目标元素的时候触发的事件,此事件作用在目标元素上
    ondragover 事件:拖拽元素在目标元素上移动的时候触发的事件,此事件作用在目标元素上
    ondragleave 事件:拖拽元素在目标元素上移动的时候触发的事件,此事件作用在目标元素上
    ondrop 事件:被拖拽的元素在目标元素上同时鼠标放开触发的事件,此事件作用在目标元素上
    ondragend 事件:当拖拽完成后触发的事件,此事件作用在被拖曳元素上
    event.preventDefault() 方法:阻止默认的些事件方法等执行。在ondragover中一定要执行preventDefault(),否则ondrop事件不会被触发。另外,如果是从其他应用软件或是文件中拖东西进来,尤其是图片的时候,默认的动作是显示这个图片或是相关信息,并不是真的执行drop。此时需要用用document的ondragover事件把它直接干掉。
    event.setDataTransfer.effectAllowed 属性:就是拖拽的效果。
    evetn.setDataTransfer.setDragImage() 方法:指定图片或者文档元素做拖动时的视觉效果。

    116.document.write和innerHTML的区别

      主要区别:document.write是直接将内容写入页面的内容流,会导致页面全部重绘(修改成更改过后的内容),innerHTML将内容写入某个DOM节点,不会导致页面全部重绘(直接写入,增加在原始内容后面)。

    117.jQuery的事件委托方法bind 、live、delegate、on之间有什么区别?

    (1)、bind 【jQuery 1.3之前】
    定义和用法:主要用于给选择到的元素上绑定特定事件类型的监听函数;

    语法:bind(type,[data],function(eventObject));

    特点:

    • 适用于页面元素静态绑定。只能给调用它的时候已经存在的元素绑定事件,不能给未来新增的元素绑定事件。
    • 当页面加载完的时候,你才可以进行bind(),所以可能产生效率问题。

    实例如下:$( “#members li a” ).bind( “click”, function( e ) {} );

    (2)、live 【jQuery 1.3之后】
    定义和用法:主要用于给选择到的元素上绑定特定事件类型的监听函数;

    语法:live(type, [data], fn);

    特点:

    • live方法并没有将监听器绑定到自己(this)身上,而是绑定到了this.context上了。
    • live正是利用了事件委托机制来完成事件的监听处理,把节点的处理委托给了document,新添加的元素不必再绑定一次监听器。
    • 使用live()方法但却只能放在直接选择的元素后面,不能在层级比较深,连缀的DOM遍历方法后面使用,即$("ul").live可以,但$(“body”).find(“ul”).live…不行;

    实例如下:$( document ).on( “click”, “#members li a”, function( e ) {} );

    (3)、delegate 【jQuery 1.4.2中引入】
    定义和用法:将监听事件绑定在就近的父级元素上

    语法:delegate(selector,type,[data],fn)

    特点:

    • 选择就近的父级元素,因为事件可以更快的冒泡上去,能够在第一时间进行处理。
    • 更精确的小范围使用事件代理,性能优于.live()。可以用在动态添加的元素上。

    实例如下:

    $(“#info_table”).delegate(“td”,”click”,function(){/显示更多信息/});

    $(“table”).find(“#info”).delegate(“td”,”click”,function(){/显示更多信息/});

    (4)、on 【1.7版本整合了之前的三种方式的新事件绑定机制】
    定义和用法:将监听事件绑定到指定元素上。

    语法:on(type,[selector],[data],fn)

    实例如下:$(“#info_table”).on(“click”,”td”,function(){/显示更多信息/});参数的位置写法与delegate不一样。

    说明:on方法是当前JQuery推荐使用的事件绑定方法,附加只运行一次就删除函数的方法是one()。

    总结:.bind(), .live(), .delegate(),.on()分别对应的相反事件为:.unbind(),.die(), .undelegate(),.off()

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

    1、解析文档构建DOM树
    浏览器的解析内容可以分为三个部分:

    • HTML/XHTML/SVG:解析这三种文件后,会生成DOM树(DOM Tree)
    • CSS:解析样式表,生成CSS规则树(CSS Rule Tree)
    • JavaScript:解析脚本,通过DOM API和CSSOM API操作DOM Tree和CSS Rule Tree,与用户进行交互。

    以上三类文件的执行顺序会根据其在文档中的位置及其标签属性的不同而有异同,具体在后文进行讨论。

    2、构建渲染树
    解析文档完成后,浏览器引擎会将 CSS Rule Tree 附着到DOM Tree 上,并根据DOM Tree 和 CSS Rule Tree构造 Rendering Tree(渲染树)。此处需要注意:

    • Render Tree和DOM Tree的区别在于,类似Head或display:node之类的东西不会放在渲染树中;
    • 将CSS Rule Tree匹配到DOM Tree需要解析CSS的选择器,为了提高该过程的性能,DOM树应该尽量小,CSS Selector应该尽量使用id和class,避免过度层叠。

    119.$(document).ready()方法和window.onload有什么区别?

    window.onload方法是在网页中所有的元素(包括元素的所有关联文件)完全加载到浏览器后才执行的。
    $(document).ready() 方法可以在DOM载入就绪时就对其进行操纵,并调用执行绑定的函数。

    120. jquery中$.get()提交和$.post()提交有区别吗?

    相同点:都是异步请求的方式来获取服务端的数据;
    异同点:
    1、请求方式不同:$.get() 方法使用GET方法来进行异步请求的。$.post() 方法使用POST方法来进行异步请求的。
    2、参数传递方式不同:get请求会将参数跟在URL后进行传递,而POST请求则是作为HTTP消息的实体内容发送给Web服务器的,这种传递是对用户不可见的。
    3、数据传输大小不同:get方式传输的数据大小不能超过2KB 而POST要大的多
    4、安全问题: GET 方式请求的数据会被浏览器缓存起来,因此有安全问题。

    121.对前端路由的理解?前后端路由的区别?

      前端路由就是把不同路由对应不同的内容或页面的任务交给前端来做,每跳转到不同的URL都是使用前端的锚点路由. 随着(SPA)单页应用的不断普及,前后端开发分离,目前项目基本都使用前端路由,在项目使用期间页面不会重新加载。

      后端路由是浏览器在地址栏中切换不同的url时,每次都向后台服务器发出请求,服务器响应请求,在后台拼接html文件传给前端显示, 返回不同的页面, 意味着浏览器会刷新页面,网速慢的话说不定屏幕全白再有新内容。后端路由的另外一个极大的问题就是 前后端不分离。

           优点:分担了前端的压力,html和数据的拼接都是由服务器完成。

           缺点:当项目十分庞大时,加大了服务器端的压力,同时在浏览器端不能输入制定的url路径进行指定模块的访问。另外一个就是如果当前网速过慢,那将会延迟页面的加载,对用户体验不是很友好。

           在单页面应用,大部分页面结构不变,只改变部分内容的使用时使用前端路由

    前端路由有什么优点和缺点?

    优点:

            1.用户体验好,和后台网速没有关系,不需要每次都从服务器全部获取,快速展现给用户

            2.可以再浏览器中输入指定想要访问的url路径地址。

            3.实现了前后端的分离,方便开发。有很多框架都带有路由功能模块。

     缺点:

            1.使用浏览器的前进,后退键的时候会重新发送请求,没有合理地利用缓存

            2.单页面无法记住之前滚动的位置,无法在前进,后退的时候记住滚动的位置

    122.vue优点

    轻量级框架,只关注视图层,是一个构建数据的视图集合,大小只有几十kb,Vue.js通过简洁的API提供高效的数据绑定和灵活的组件系统

    简单易学,国人开发,中文文档,不存在语言障碍,易于理解和学习

    双向数据绑定,也就是说,vue.js会自动响应数据的变化情况,并且根据用户在代码中预先写好的绑定关系,对所有绑定在一起的数据和视图内容都进行修改。而这种绑定关系,就是以input 标签的v-model属性来声明的,这也就是vue.js最大的优点,通过MVVM思想实现数据的双向绑定,让开发者不用再操作dom对象,有更多的时间去思考业务逻辑。

    组件化,Vue.js通过组件,把一个单页应用中的各种模块拆分到一个一个单独的组件(component)中,我们只要先在父级应用中写好各种组件标签(占坑),并且在组件标签中写好要传入组件的参数(就像给函数传入参数一样,这个参数叫做组件的属性),然后再分别写好各种组件的实现(填坑),然后整个应用就算做完了。

    视图,数据,结构分离,使数据的更改更为简单,不需要进行逻辑代码的修改,只需要操作数据就能完成相关操作

    虚拟DOM,在传统开发中,用JQuery或者原生的JavaScript DOM操作函数对DOM进行频繁操作的时候,浏览器要不停的渲染新的DOM树,导致页面看起来非常卡顿。

    而Virtual DOM则是虚拟DOM的英文,简单来说,他就是一种可以预先通过JavaScript进行各种计算,把最终的DOM操作计算出来并优化,由于这个DOM操作属于预处理操作,并没有真实的操作DOM,所以叫做虚拟DOM。最后在计算完毕才真正将DOM操作提交,将DOM操作变化反映到DOM树上。

    运行速度更快,像比较与react而言,同样都是操作虚拟dom,就性能而言,vue存在很大的优势

    123.vue父组件向子组件传递数据?

    父组件:

    <template>
        <parent>
            <child :list="list"></child> //在这里绑定list对象
        </parent>
    </template>
    import child from 'child.vue';
    export default{
      components:{child},
      data(){
       return {
       //父组件的数据绑定到子组件的包裹层上 
      list:["haha","hehe","xixi"];
     }
    }

    子组件:(子组件要嵌套到父组件中)

    child.vue
    <template>
       <ul>
            <li v-for="(item ,index)in list">{{item}}</li>
        </ul>
    </template>
    export default{
         props:{
        list:{
          type:Array,//type为Array,default为函数
          default(){
            return [
              "hahaxixihehe"//默认初始值
            ]}}
        },//用props属性进行传数据,此时子组件已经获取到list的数据了
           data(){
             return {}  
        }   
    } 

    124.子组件向父组件传递事件

    <div id="app">
        <hello list="list" v-on:wzhclick="wzhclick"></hello>
    </div>
    <template id="myT">
        <button v-on:click="childclick">调用父组件的方法</button>
    </template>
    <script>
        Vue.component('hello', {
            template: '#myT',
            methods: {
                childclick: function () {
                    this.$emit('wzhclick', {a:1,b:2});
                }
            }
        });
        var app=new Vue({
            el: '#app',
            methods: {
                wzhclick: function (data) {
                    alert("我是父组件,参数"+data.a+";"+data.b);
                },
            }
        });
    </script>

    125.v-show和v-if指令的共同点和不同点

      一般来说,v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用 v-show 较好;如果在运行时条件很少改变,则使用 v-if 较好。

    相同点:v-show和v-if都能控制元素的显示和隐藏。

    不同点:

    • 实现本质方法不同
      • v-show本质就是通过设置css中的display设置为none,控制隐藏
      • v-if是动态的向DOM树内添加或者删除DOM元素
    • 编译的区别
      • v-show其实就是在控制css
      • v-if切换有一个局部编译/卸载的过程,切换过程中合适地销毁和重建内部的事件监听和子组件
    • 编译的条件
      • v-show都会编译,初始值为false,只是将display设为none,但它也编译了
      • v-if初始值为false,就不会编译了
    • 性能
      • v-show只编译一次,后面其实就是控制css,而v-if不停的销毁和创建,故v-show性能更好一点。
      • 注意点:因为v-show实际是操作display:" "或者none,当css本身有display:none时,v-show无法让显示
      • 总结:如果要频繁切换某节点时,使用v-show(无论true或者false初始都会进行渲染,此后通过css来控制显示隐藏,因此切换开销比较小,初始开销较大),如果不需要频繁切换某节点时,使用v-if(因为懒加载,初始为false时,不会渲染,但是因为它是通过添加和删除dom元素来控制显示和隐藏的,因此初始渲染开销较小,切换开销比较大)

    126.如何让CSS只在当前组件中起作用

      当前组件<style>写成<style  scoped>

    127.<keep-alive></keep-alive>的作用是什么?

      keep-alive用来缓存组件,避免多次加载相应的组件,减少性能消耗,简单一点来说就是从页面1链接到其他页面后回退到页面1不用在重新执行页面1的代码,只会从缓存中加载之前已经缓存的页面1,这样可以减少加载时间及性能消耗,提高用户体验性。

      通过设置了keep-alive,可以简单理解为从页面1跳转到页面2后,然后后退到页面1,只会加载缓存中之前已经渲染好的页面1,而不会再次重新加载页面1,及不会再触发页面一种的created等类似的钩子函数,除非自己重新刷新该页面1。

    128. vue-loader是什么?使用它的用途有哪些?

    vue-loader作用:解析和转换.vue文件。提取出其中的逻辑代码 script,样式代码style,以及HTML 模板template,再分别把他们交给对应的loader去处理

    用途:js可以写es6,style样式可以写scss或less、template可以加jade等

    css-loader加载由vue-loader提取出的CSS代码;vue-template-compiler:把vue-loader提取出的HTML模板编译成可执行的jacascript代码

    129.vue中 key 值的作用?

      当 Vue.js 用 v-for 正在更新已渲染过的元素列表时,它默认用“就地复用”策略。如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序, 而是简单复用此处每个元素,并且确保它在特定索引下显示已被渲染过的每个元素。key的作用主要是为了高效的更新虚拟DOM。

    130. 组件间的通信

    1. props和$emit,父组件向子组件传递数据是通过prop传递的,子组件传递数据给父组件是通过$emit触发事件来做到的

    父组件传递了message数据给子组件,并且通过v-on绑定了一个getChildData事件来监听子组件的触发事件;
    子组件通过props得到相关的message数据,最后通过this.$emit触发了getChildData事件。

    2.$attrs和$listeners

    3.中央事件总线(解决只能在父子间的传值)

    4. provide和inject,父组件中通过provider来提供变量,然后在子组件中通过inject来注入变量。不论子组件有多深,只要调用了inject那么就可以注入provider中的数据。而不是局限于只能从当前父组件的prop属性来获取数据,只要在父组件的生命周期内,子组件都可以调用。

    5. v-model,父组件通过v-model传递值给子组件时,会自动传递一个value的prop属性,在子组件中通过this.$emit(‘input’,val)自动修改v-model绑定的值
    6. $parent和$children

    7.boradcast和dispatch

    8.vuex处理组件之间的数据交互,如果业务逻辑复杂,很多组件之间需要同时处理一些公共的数据,这个时候才有上面这一些方法可能不利于项目的维护,vuex的做法就是将这一些公共的数据抽离出来,然后其他组件就可以对这个公共数据进行读写操作,这样达到了解耦的目的。

    131.Vue中双向数据绑定是如何实现的

    • vue中视图上出现很多 {{message}}v-modelv-text等等模板,我们要对其进行编译。
    • 数据变化的时候,会动态更新到视图上,使用的Object.defineProperty(),进行数据劫持。
    • 通过Watcher观察数据的变化,然后重新编译模板,渲染到视图上
    <body>
        <div id="app">
        <input type="text" id="txt">
        <p id="show"></p>
    </div>
    </body>
    <script type="text/javascript">
        var obj = {}
        Object.defineProperty(obj, 'txt', {
            get: function () {
                return obj
            },
            set: function (newValue) {
                document.getElementById('txt').value = newValue
                document.getElementById('show').innerHTML = newValue
            }
        })
        document.addEventListener('keyup', function (e) {
            obj.txt = e.target.value
        })
    </script>

    132.单页面应用和多页面应用区别及优缺点

    133.assets和static的区别

    assests放置的是组件的资源,static放置的是非组件的资源。
    比如说即static下的文件资源作为src路径传入组件中,文件的path是可以被解析了,而assets则不行。
    比如你写一个音乐播放器,类似的播放键和上一曲下一曲这些图标就应该作为组件资源放在assests里面,而不同音乐选集的封面这些是应该作为文件资源放在static下。

    134.Vue.set视图更新

    Vue.set(target,key,value)

    target:要更改的数据源(可以是对象或者数组)

    key:要更改的具体数据(可以是字符串和数字)

    value :重新赋的值

    用法:向响应式对象中添加一个属性,并确保这个新属性同样是响应式的,且触发视图更新

    data:{
         namelist:[
             {message:"叶落森",id:"1"},
             {message:"姜艳霞",id:"2"},
             {message:"姜小帅",id:"3"}
          ]
    },
     Vue.set(this.namelist,1,{message:"yeluosen",id:"1"})

    注:Vue.set()在methods中也可以写成this.$set()

    Vue.set()不光能修改数据,还能添加数据

    data:{
         items:[
             {message:"Test one",id:"1"},
             {message:"Test two",id:"2"},
             {message:"Test three",id:"3"}
          ]
    },
    var itemLen=this.items.length;
    Vue.set(this.items,itemLen,{message:"Test add attr",id:itemLen});

    135.vue和jQuery的区别

    1.jquery介绍:这个曾经也是现在依然最流行的web前端js库,可是现在无论是国内还是国外他的使用率正在渐渐被其他的js库所代替,随着浏览器厂商对HTML5规范统一遵循以及ECMA6在浏览器端的实现,jquery的使用率将会越来越低。

    2.vue介绍:vue是一个兴起的前端js库,是一个精简的MVVM。从技术角度讲,Vue.js 专注于 MVVM 模型的 ViewModel 层。它通过双向数据绑定把 View 层和 Model 层连接了起来,通过对数据的操作就可以完成对页面视图的渲染。当然还有很多其他的mvmm框架如Angular,React都是大同小异,本质上都是基于MVVM的理念。 然而vue以他独特的优势简单,快速,组合,紧凑,强大而迅速崛起 

    3.vue和jquey对比 

      jQuery是使用选择器($)选取DOM对象,对其进行赋值、取值、事件绑定等操作,其实和原生的HTML的区别只在于可以更方便的选取和操作DOM对象,而数据和界面是在一起的。比如需要获取label标签的内容:$("lable").val();,它还是依赖DOM元素的值。 

      Vue则是通过Vue对象将数据和View完全分离开来了。对数据进行操作不再需要引用相应的DOM对象,可以说数据和View是分离的,他们通过Vue对象这个vm实现相互的绑定。这就是传说中的MVVM。

    136.Vue-cli打包命令是什么?打包后会导致路径问题,应该在哪里修改

    命令行输入:npm  run  build

    打包出来后项目中就会多了一个文件夹dist,这就是我们打包过后的项目。

    第一个问题,文件引用路径。我们直接运行打包后的文件夹中的index.html文件,会看到网页一片空白,f12调试,全是css,js路径引用错误的问题。

    解决:到config文件夹中打开index.js文件。文件里面有两个assetsPublicPath属性,更改第一个,也就是更改build里面的assetsPublicPath属性:

    assetsPublicPath属性作用是指定编译发布的根目录,‘/’指的是项目的根目录 ,’./’指的是当前目录。

    改好之后重新打包项目,运行index.html文件,我们可以看到没有报错了。但是router-view里面的内容却出不来了

    第二个问题:router-view中的内容显示不出来路由history模式。

    解决:// mode: 'history',//将这个模式关闭就好

    第三个问题 :背景图片引用资源错误  

    解决:打开build/utils.js,在图中相应位置加入红框内容,其中值可能会有不同,若不同,自己配置成相应的即可    

    136.delete和Vue.delete删除数组的区别 

    delete只是被删除的元素变成了 empty/undefined 其他的元素的键值还是不变。

    Vue.delete 直接删除了数组 改变了数组的键值。

    137.Vue-router跳转和location.href有什么区别

      Router是hash改变;location.href是页面跳转,刷新页面。

    138.你们vue项目是打包了一个js文件,一个css文件,还是有多个文件?

      根据vue-cli脚手架规范,一个js文件,一个CSS文件。

    139.RouterLink在IE和Firefox中不起作用(路由不跳转)的问题

    方法一

    将 clrDropdownItem 样式放在<a>标签,不使用<button>标签

    <a clrDropdownItem routerLink="/admin"> Admin </a>

    方法二

    使用<button>标签和Router.navigate方法

    main.component.html

    <button type="button" clrDropdownItem (click)="gotoAdmin()">Admin</button>

    main.component.js

    import { Router } from '@angular/router';
    ...
    export class MainComponent {
    constructor(
    private router: Router
    ) {}
    gotoAdmin() {
    this.router.navigate(['/admin']);
    }
    }

    140.axios的特点有哪些

    1. 从浏览器中创建 XMLHttpRequest
    2. 支持 Promise API
    3. 客户端支持防止CSRF
    4. 提供了一些并发请求的接口(重要,方便了很多的操作)
    5. 从 node.js 创建 http 请求
    6. 拦截请求和响应7.转换请求和响应数据
    7. 取消请求
    8. 自动转换JSON数据

      PS:防止CSRF:就是让你的每个请求都带一个从cookie中拿到的key, 根据浏览器同源策略,假冒的网站是拿不到你cookie中得key的,这样,后台就可以轻松辨别出这个请求是否是用户在假冒网站上的误导输入,从而采取正确的策略。

    141.请说下封装 vue 组件的过程?

    ● 首先,使用Vue.extend()创建一个组件

    ● 然后,使用Vue.component()方法注册组件

    ● 接着,如果子组件需要数据,可以在props中接受定义

    ● 最后,子组件修改好数据之后,想把数据传递给父组件,可以使用emit()方法

    142.vuex是什么?怎么使用?哪种功能场景使用它?

      Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。

      只用来读取的状态集中放在store中; 改变状态的方式是提交mutations,这是个同步的事物; 异步逻辑应该封装在action中。
    在main.js引入store,注入。新建了一个目录store,….. export 。
      场景有:单页应用中,组件之间的状态、音乐播放、登录状态、加入购物车

    state:Vuex 使用单一状态树,即每个应用将仅仅包含一个store 实例,但单一状态树和模块化并不冲突。存放的数据状态,不可以直接修改里面的数据。
    mutations:定义的方法动态修改Vuex 的 store 中的状态或数据。
    getters:类似vue的计算属性,主要用来过滤一些数据。
    actions:可以理解为通过将mutations里面处里数据的方法变成可异步的处理数据的方法,简单的说就是异步操作数据。view 层通过 store.dispath 来分发 action

    143.Vuex中如何异步修改状态

    在调用vuex中的方法action的时候,用promise实现异步修改

    const actions = {
        asyncInCrement({ commit }, n){
            return new Promise(resolve => {
                setTimeout(() => {
                    commit(types.TEST_INCREMENT, n);
                    resolve();
                },3000)
            })
        }
    }

      前端面试题终于阶段性的结束了,没想到越总结越多,真是太佩服很多前辈坚持更新的毅力,准备永远不会有百分百完美,在实践中成长吧。文中若有不正确的总结,希望各位大神能够指出,一起进步。

  • 相关阅读:
    react native 之页面跳转
    react native 之异步请求
    react native 之 redux
    react native 之页面布局
    ES6的相关新属性
    css中的选择器
    js中return的作用
    校园商铺-7商品类别模块-2商品类别列表从后到前
    校园商铺-6店铺编辑列表和列表功能-9店铺管理页面的前端开发
    校园商铺-6店铺编辑列表和列表功能-8店铺列表展示前端开发
  • 原文地址:https://www.cnblogs.com/zpp1/p/12811750.html
Copyright © 2020-2023  润新知