前端知识点

html

Doctype做用?标准模式与兼容模式各有什么区别?

  1. 声明位于HTML文档的第一行,告知浏览器的解析器用什么文档标准解析这个文档。DOCTYPE不存在或格式不正确会致使文档以兼容模式呈现。
  2. 标准模式的排版和JS运做模式都是以该浏览器支持的最高标准运行。在兼容模式中,页面以宽松的向后兼容的方式显示,模拟老式浏览器的行为以防止站点没法工做。简单的说,就是尽量的能显示东西给用户看。javascript

HTML5 为何只须要写 <!DOCTYPE HTML>

HTML5 不基于 SGML,所以不须要对DTD进行引用,可是须要doctype来规范浏览器的行为(让浏览器按照它们应该的方式来运行);css

而HTML4.01基于SGML,因此须要对DTD进行引用,才能告知浏览器文档所使用的文档类型。html

什么是盒子模型?CSS-标准盒模型和怪异盒模型的区别?哪一个css能够改变盒子模型?


css盒子模型 又称为框模型(Box Model),包含了元素内容(content)、内边距(padding)、边框(border)、外边距(margin)几个要素。前端

标准盒模型

怪异盒模型

区别:当不对doctype进行定义时,会触发怪异模式。

  • 在标准模式下,一个块的总宽度= width + margin(左右) + padding(左右) + border(左右)
  • 在怪异模式下,一个块的总宽度= width + margin(左右)(即width已经包含了padding和border值)

CSS

什么是外边距合并?

外边距合并指的是,当两个垂直外边距相遇时,它们将造成一个外边距。
合并后的外边距的高度等于两个发生合并的外边距的高度中的较大者。
w3school介绍网址: http://www.w3school.com.cn/css/css_margin_collapsing.asp

注意:水平方向上的外边距不会合并,而是会相加
复制代码

如何居中div

  • 水平居中:给div设置一个宽度,而后添加margin:0 auto;属性
div{
 	width:200px;
 	margin:0 auto;
  }
复制代码
  • 让绝对定位的div居中
div {
 	position: absolute;
 	width: 300px;
 	height: 300px;
 	margin: auto;
 	top: 0;
 	left: 0;
 	bottom: 0;
 	right: 0;
 	background-color: pink;	/* 方便看效果 */
 }
复制代码
  • 水平垂直居中一

肯定容器的宽高 宽500 高 300 的层 设置层的外边距java

div {
 	position: relative;		/* 相对定位或绝对定位都可 */
 	width:500px;
 	height:300px;
 	top: 50%;
 	left: 50%;
 	margin: -150px 0 0 -250px;     	/* 外边距为自身宽高的一半 */
 	background-color: pink;	 	/* 方便看效果 */

  }
复制代码
  • 水平垂直居中二

未知容器的宽高,利用 transform 属性node

div {
 	position: absolute;		/* 相对定位或绝对定位都可 */
 	width:500px;
 	height:300px;
 	top: 50%;
 	left: 50%;
 	transform: translate(-50%, -50%);
 	background-color: pink;	 	/* 方便看效果 */

 }

复制代码
  • 水平垂直居中三

利用 flex 布局 实际使用时应考虑兼容性webpack

.container {
 	display: flex;
 	align-items: center; 		/* 垂直居中 */
 	justify-content: center;	/* 水平居中 */

 }
 .container div {
 	width: 100px;
 	height: 100px;
 	background-color: pink;		/* 方便看效果 */
 }  
复制代码

左侧固定,右侧自适应

法一:

复制代码

多列等高布局

来源:codepen.io/yangbo5207/…css3

  1. 视觉等高实现之绝对定位

html代码nginx

<div class="outer">
  <div class="left">
    <div class="equh"></div>
    <div class="left-con">
      <p>left</p>
      <p>left</p>
      <p>left</p>
    </div>
  </div>
  <div class="right">
    <p>right</p>
    <p>right</p>
    <p>right</p>
    <p>right</p>
    <p>right</p>
  </div>
</div>
复制代码

css代码git

.outer {
  width: 960px;
  margin: 0 auto;
  border: 1px solid #000;
  overflow: hidden;
  background-color: green;
  color: #fff;
}
.left {
  width: 200px;
  position: relative;
  float: left;
}
.equh {
  width: 100%;
  height: 999em;
  position: absolute;
  left: 0;
  top: 0;
  border-right: 1px solid #000;
  background-color: orange;
}

.left-con {
  padding: 1em;
  position: relative;
  z-index: 1;
}
.right {
  padding: 1em;
  overflow: hidden;
}

复制代码
  1. 视觉等高实现之padding-bottom与margin-bottom

核心代码

padding-bottom: 9999px;
margin-bottom: -9999px;
复制代码

html代码

<div class="box">
  <div class="sub">
    <p>a</p>
  </div>
  <div class="sub">
    <p>b</p>
    <p>b</p>
  </div>
  <div class="sub">
    <p>c</p>
    <p>c</p>
    <p>c</p>
  </div>
</div>
复制代码

css代码

.box {
  width: 600px;
  overflow: hidden;
  margin: 10px auto;
  border: 1px solid #888;
}
.sub {
  float: left;
  width: 30%;
  margin-right: 3%;
  border: 1px solid orange;
  padding-bottom: 9999px;
  margin-bottom: -9999px;
}
复制代码
  1. 真实等高实现之table-cell

该方案利用了全部单元格高度都相等的特性,不过因为ie6/7不支持该属性,所以略有瑕疵。不过总的来讲仍是很是不错的方案。

html 代码

<div class="box">
  <div class="row">
    <div class="cell">你必定也有过这种感受的。当你心事重重,渴望找一我的聊一聊的时候,那个能够聊的人来了,但是大家却并无聊什么。固然,聊是聊了,但是他聊他的,你也试着开始聊你的,只是到后来,你放弃了……那么,最后的办法就是静下来,啃啮本身的寂寞。或者反过来讲,让寂寞来吞噬你。------罗兰《寂寞的感受》</div>
    <div class="cell">做为一个被基阿异捅过两个大血窟窿的人。告诉后来的基友们一句:一命二运三风水,四积阴功五读书。</div>
    <div class="cell">奔波了一天,收到了无数的生日快乐,享受了电影见面会现场各类形式的祝福和礼物,以及场面宏大的生日快乐歌,感谢<西风烈>,感谢支持个人朋友们!如今机场举长寿面祝大家都永远幸福快乐!</div>
  </div>
</div>
复制代码

css代码

.box {
  width: 600px;
  margin: 40px auto;
  font-size: 12px;
}
.row {
  display: table-row;
  overflow: hidden;
}
.cell {
  display: table-cell;
  width: 30%;
  padding: 1.6%;
  background-color: #f5f5f5;
  // 在IE6/7下使用上一方法,添加一些hack便可,这样就能作到所有兼容了
  *float: left;
  *padding-bottom: 9999px;
  *margin-bottom: -9999px;
}
复制代码
  1. 真实等高实现之弹性盒模型

若不考虑兼容性,此方法最简单

html代码

<div class="box">
  <div class="cell">你必定也有过这种感受的。当你心事重重,渴望找一我的聊一聊的时候,那个能够聊的人来了,但是大家却并无聊什么。固然,聊是聊了,但是他聊他的,你也试着开始聊你的,只是到后来,你放弃了……那么,最后的办法就是静下来,啃啮本身的寂寞。或者反过来讲,让寂寞来吞噬你。------罗兰《寂寞的感受》</div>
  <div class="cell">做为一个被基阿异捅过两个大血窟窿的人。告诉后来的基友们一句:一命二运三风水,四积阴功五读书。</div>
  <div class="cell">奔波了一天,收到了无数的生日快乐,享受了电影见面会现场各类形式的祝福和礼物,以及场面宏大的生日快乐歌,感谢<西风烈>,感谢支持个人朋友们!如今机场举长寿面祝大家都永远幸福快乐!</div>
</div>
复制代码

css代码

.box {
  width: 600px;
  margin: 20px auto;
  display: flex;
}
.cell {
  width: 30%;
  border: 1px solid red;
}
复制代码

总结: 若是须要兼容到ie6/ie7,则使用方法三便可,其中结合了方法二的思路。若是仅仅只是移动端的h5页面的实现,那么绝不犹豫的使用弹性盒模型来实现。简单高效。

position取值

  • static 默认值 没有定位
  • inherit 规定应该从父元素继承position属性的值
  • relative 生成相对定位的元素,相对于其正常位置进行定位
  • absolute 绝对定位 相对于static之外的第一个父元素进行定位
  • fixed 绝对定位 相对于浏览器窗口进行定位

sticky布局

法一:

dom结构

<div class="wrapper">
        <header>header</header>
        <section style="height:300px">内容</section>
    </div>
    <footer>designer by echo hu</footer>
复制代码

css

/*相同dom不一样css*/
第一种样式
footer {
    height: 7em;
    background: #3c3c3c;
}
.wrapper {
    width: 100%;
    min-height: calc(100vh - 7em);
}

第二种样式
html,body{
    height:100%;
}
footer{
    height:7em;
}
.wrapper{
    height:calc(100% - 7em);
}
复制代码

法二:

dom结构

<div class="wrapper">
    <div class="main">
       <div class="content"></div>
    </div>
    <div class="close"></div>
</div>
复制代码

css样式

.wrapper{
    width:100%;
    height:100%;
}
.main{
    min-height:100%;
}
.close{
    width:100%;
    height:32px;
    margin-top:-32px;
}
复制代码

flex布局

what is flex?

flex是Flexible Box的缩写,意为弹性布局。

任何一个容器均可指定为flex布局

.box{
    display:flex;
}
复制代码

行内元素也可使用flex布局

.box{
    display:inline-flex;
}
复制代码

注意:设为flex布局后,子元素的clear,float,vertical-align属性将失效

容器的属性

+ flex-direction
+ flex-wrap
+ flex-flow
+ justify-content
+ align-items
+ align-content
复制代码

flex-direction属性决定主轴的方向

.box{
    flex-direction: row | row-reverse | column | column-reverse
}
复制代码

它有四个值

+ row(默认值):主轴为水平方向,起点在左端
+ row-reverse:主轴为水平方向,起点在右端。
+ column:主轴为垂直方向,起点在上沿。
+ column-reverse:主轴为垂直方向,起点在下沿。
复制代码

flex-wrap属性定义,若是一条轴线排不下,如何换行。默认状况下,项目都排在一条线上

.box{
    flex-wrap: nowrap(不换行) | wrap(换行,第一行在上方) | wrap-reverse(换行,第一行在下方)
}
复制代码

flex-flow属性是flex-directionflex-wrap的简写,默认row nowrap

.box {
  flex-flow: <flex-direction> || <flex-wrap>;
}
复制代码

justify-content属性定义了项目在主轴上的对齐方式。

它有五个值,具体对齐方式与轴的方向有关。下面假设主轴为从左往右。

+ flex-start(默认值):左对齐
+ flex-end:右对齐
+ center:居中
+ space-between:两端对齐,项目之间的间隔都相等
+ space-around:每一个项目两侧的间隔相等。因此,项目之间的间隔比项目与边框的间隔大一倍。
复制代码

align-items属性定义项目在交叉轴上如何对齐 它可能取5个值。具体的对齐方式与交叉轴的方向有关,下面假设交叉轴从上到下。

+ flex-start:交叉轴的起点对齐。
+ flex-end:交叉轴的终点对齐。
+ center:交叉轴的中点对齐。
+ baseline: 项目的第一行文字的基线对齐。
+ stretch(默认值):若是项目未设置高度或设为auto,将占满整个容器的高度。
复制代码

align-content属性定义了多根轴线的对齐方式。若是项目只有一根轴线,该属性不起做用。

该属性可能取6个值。

+ flex-start:与交叉轴的起点对齐。
+ flex-end:与交叉轴的终点对齐。
+ center:与交叉轴的中点对齐。
+ space-between:与交叉轴两端对齐,轴线之间的间隔平均分布。
+ space-around:每根轴线两侧的间隔都相等。因此,轴线之间的间隔比轴线与边框的间隔大一倍。
+ stretch(默认值):轴线占满整个交叉轴。
复制代码

项目的属性

如下6个属性设置在项目上。

+ order 定义项目的排列顺序。数值越小,排列越靠前,默认为0
+ flex-grow 属性定义项目的放大比例,默认为0,即若是存在剩余空间,也不放大。
+ flex-shrink 属性定义了项目的缩小比例,默认为1,即若是空间不足,该项目将缩小
+ flex-basis 属性定义了在分配多余空间以前,项目占据的主轴空间
+ flex 是flex-grow, flex-shrink 和 flex-basis的简写,默认值为0 1 auto
+ align-self 属性容许单个项目有与其余项目不同的对齐方式,可覆盖align-items属性。默认值为auto,表示继承父元素的align-items属性,若是没有父元素,则等同于stretch。
复制代码

display取值,元素默认是什么,内联元素块级元素可变元素有哪些?img是什么?

img是内联元素

display CSS属性指定用于元素的呈现框的类型。在 HTML 中,默认的 display 属性取决于 HTML 规范所描述的行为或浏览器/用户的默认样式表。

默认值是inline

display取值以下:

none	此元素不会被显示。
block	此元素将显示为块级元素,此元素先后会带有换行符。
inline	默认。此元素会被显示为内联元素,元素先后没有换行符。
inline-block	行内块元素。(CSS2.1 新增的值)
list-item	此元素会做为列表显示。
run-in	此元素会根据上下文做为块级元素或内联元素显示。
compact	CSS 中有值 compact,不过因为缺少普遍支持,已经从 CSS2.1 中删除。
marker	CSS 中有值 marker,不过因为缺少普遍支持,已经从 CSS2.1 中删除。
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 属性的值。
复制代码

float:left状况下是怎样的,此时若是超出了宽度范围

该元素从网页的正常流动中移除,尽管仍然保持部分的流动性

css3的transform

CSS transform 属性容许你修改CSS视觉格式模型的坐标空间。使用它,元素能够被转换(translate)、旋转(rotate)、缩放(scale)、倾斜(skew)。

javaScript

什么是闭包?闭包的优缺点


答:闭包是将外部做用域中的局部变量封闭起来的函数对象。被封闭起来的变量与封闭它的函数对象有相同的生命周期。

优势:一个是前面提到的能够读取函数内部的变量,另外一个就是让这些变量的值始终保持在内存中,不会在f1调用后被自动清除。

缺点

  • 因为闭包会使得函数中的变量都被保存在内存中,内存消耗很大,因此不能滥用闭包,不然会形成网页的性能问题,在IE中可能致使内存泄露。解决方法是,在退出函数以前,将不使用的局部变量所有删除。
  • 闭包会在父函数外部,改变父函数内部变量的值。因此,若是你把父函数看成对象(object)使用,把闭包看成它的公用方法(Public Method),把内部变量看成它的私有属性(private value),这时必定要当心,不要随便改变父函数内部变量的值。

输入一个URL后会发生什么?

整体来讲分为如下几个过程:

  • DNS解析

  • TCP链接

  • 发送HTTP请求

  • 服务器处理请求并返回HTTP报文

  • 浏览器解析渲染页面

  • 链接结束

tcp 协议,http协议

hit-alibaba.github.io/interview/b…

tcp协议便是传输控制协议,

http协议:

HTTP构建于TCP/IP协议之上,默认端口号是80 HTTP是无链接无状态的

如何实现一个LazyMan?

题目

实现一个LazyMan,能够按照如下方式调用:
LazyMan(“Hank”)输出: Hi! This is Hank!

LazyMan(“Hank”).sleep(10).eat(“dinner”)输出 Hi! This is Hank! //等待10秒..Wake up after 10 Eat dinner~

LazyMan(“Hank”).eat(“dinner”).eat(“supper”)输出 Hi This is Hank! Eat dinner~ Eat supper~

LazyMan(“Hank”).sleepFirst(5).eat(“supper”)输出 //等待5秒 Wake up after 5 Hi This is Hank! Eat supper 以此类推。
复制代码

实现

  1. 队列
function _LazyMan(name) {
        this.tasks = []
        var self = this
        var fn = (function(n) {
          var name = n
          return function() {
            console.log('Hi! this is ' + name + '!')
            self.next()
          }
        })(name)
        this.tasks.push(fn)
        setTimeout(function() {
          self.next()
        }, 0)
        // 在下一个事件循环启动任务
      }
      /* 事件调度函数 */

      _LazyMan.prototype.next = function() {
        var fn = this.tasks.shift()
        fn && fn()
      }
      _LazyMan.prototype.eat = function(name) {
        var self = this
        var fn = (function(name) {
          return function() {
            console.log('Eat ' + name + ' ~')
            self.next()
          }
        })(name)
        this.tasks.push(fn)
        return this // 实现链式调用
      }
      _LazyMan.prototype.sleep = function(time) {
        var self = this
        var fn = (function(time) {
          return function() {
            setTimeout(function() {
              console.log('Wake up after ' + time + ' s!')
              self.next()
            }, time * 1000)
          }
        })(time)
        this.tasks.push(fn)
        return this
      }
      _LazyMan.prototype.sleepFirst = function(time) {
        var self = this
        var fn = (function(time) {
          return function() {
            setTimeout(function() {
              console.log('Wake up after ' + time + ' s!')
            }, time * 1000)
          }
        })(time)
        this.tasks.unshift(fn)
        return this
      } /* 封装 */
      function LazyMan(name) {
        return new _LazyMan(name)
      }
复制代码
  1. promise
//lazyman里边含有链式调用,那么每个子任务 return this;这个程序支持任务优先顺序,那么就须要两个贯穿全场的Promise对象:第一,普通顺序promise;第二,插入顺序promise,同时插入顺序是阻塞普通顺序的,代码以下:
      function _LazyMan(name) {
        this.orderPromise = this.newPromise() // 定义顺序promise对象
        this.insertPromise = this.newPromise() // 定义插入promise对象
        this.order(function(resolve) {
          console.log(name)
          resolve()
        })
      }
      _LazyMan.prototype = {
        /*实例化promise对象工厂*/

        newPromise: function() {
          return new Promise(function(resolve, reject) {
            resolve()
          })
        },
        order: function(fn) {
          var self = this
          this.orderPromise = this.orderPromise.then(function() {
            return new Promise(function(resolve, reject) {
              //若是有insertPromise,阻塞
              orderPromise.self.fir
                ? self.insertPromise.then(function() {
                    fn(resolve)
                  })
                : fn(resolve)
            })
          })
        },
        insert: function(fn) {
          var self = this
          this.fir = true
          this.insertPromise = this.insertPromise.then(function() {
            return new Promise(function(resolve, reject) {
              fn(resolve)
              self.fir = false
            })
          })
        },
        sleepFirst: function(time) {
          this.insert(function(resolve) {
            setTimeout(function() {
              console.log('wait ' + time + ' s,other logic')
              resolve()
            }, time * 1000)
          })
          return this
        },
        eat: function(something) {
          this.order(function(resolve) {
            console.log(something + ' ~~')
            resolve()
          })
          return this
        },
        sleep: function(time) {
          this.order(function(resolve) {
            setTimeout(function() {
              console.log('sleep ' + time + ' s')
            }, time * 1000)
          })
          return this
        }
      } 
      //接口封装。
      function LazyMan(name) {
        return new _LazyMan(name)
      } 
      //调用测试
      LazyMan('RoryWu')
        .firstTime(1)
        .sleep(2)
        .firstTime(3)
        .eat('dinner')
        .eat('breakfast') // 弹出: // wait 1 s, other logic // wait 3 s, other logic // RoryWu // sleep 2 s // dinner~~ // breakfast~~
复制代码

用JS代码求出页面上一个元素的最终的background-color,不考虑IE浏览器,不考虑元素float状况。

代码实例

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
  <style>
    .button {
    height: 2em;
    border: 0;
    border-radius: .2em;
    background-color: #34538b;
    color: #fff;
    font-size: 12px;
    font-weight: bold;
}
  </style>
</head>
<body>
  <input type="button" id="button" class="button" value="点击我,显示背景色" />
  <script>
    document.getElementById("button").onclick = function() {
    var oStyle =window.getComputedStyle(this, null); // null不是必须
    // 若是考虑IE var oStyle = this.currentStyle? this.currentStyle : window.getComputedStyle(this, null);
    alert(oStyle.getPropertyValue("background-color")); //这里也能够用键值获取,建议用getPropertyValue("background-color")
   };
  </script>
</body>
</html>

复制代码

setTimeout(fn,0)

题目

for (var i = 0; i < 3; i++) {
    setTimeout(function() {
        console.log(i);
    }, 0);
    console.log(i);
}
复制代码

题解

结果是:0 1 2 3 3 3

不少公司面试都爱出这道题,此题考察的知识点仍是蛮多的。

为了防止初学者栽在此问题上,此文稍微分析一下。

都考察了那些知识点呢? 异步、做用域、闭包,你没听错,是闭包。

咱们来简化此题:

setTimeout(function() {
        console.log(1);
}, 0);
console.log(2);
先打印2,后打印1。

由于是setTimeout是异步的。

正确的理解setTimeout的方式(注册事件):

有两个参数,第一个参数是函数,第二参数是时间值。

调用setTimeout时,把函数参数,放到事件队列中。等主程序运行完,再调用。

没啥很差理解的。就像咱们给按钮绑定事件同样:

btn.onclick = function() {
        alert(1);
};
这么写完,会弹出1吗。不会!!只是绑定事件而已!

必须等咱们去触发事件,好比去点击这个按钮,才会弹出1。

setTimeout也是这样的!只是绑定事件,等主程序运行完毕后,再去调用。

setTimeout的时间值是怎么回事呢?

好比:

setTimeout(fn, 2000)
咱们能够理解为2000以后,再放入事件队列中,若是此时队列为空,那么就直接调用fn。若是前面还有其余的事件,那就等待。 所以setTimeout是一个约会历来都不许时的童鞋。

继续看:

setTimeout(function() {
        console.log(i);
}, 0);
var i = 1;
程序会不会报错?

不会!并且还会准确得打印1。

为何?

由于真正去执行console.log(i)这句代码时,var i = 1已经执行完毕了!

因此咱们进行dom操做。能够先绑定事件,而后再去写其余逻辑。

window.onload = function() {
        fn();
}
var fn = function() {
        alert('hello')
};
这么写,彻底是能够的。由于异步! es5中是没有块级做用域的

for (var i = 0; i < 3; i++) {}
console.log(i);
也就说i能够在for循环体外访问到。因此是没有块级做用域。

但此问题在es6里终结了,由于es6,发明了let。

这回咱们再来看看原题。

原题使用了for循环。循环的本质是干吗的?

是为了方便咱们程序员,少写重复代码。

让咱们倒退50年,原题等价于:

var i = 0;
setTimeout(function() {
    console.log(i);
}, 0);
console.log(i);
i++;
setTimeout(function() {
    console.log(i);
}, 0);
console.log(i);
i++;
setTimeout(function() {
    console.log(i);
}, 0);
console.log(i);
i++;
由于setTimeout是注册事件。根据前面的讨论,能够都放在后面。 原题又等价于以下的写法:

var i = 0;
console.log(i);
i++;
console.log(i);
i++;
console.log(i);
i++;
setTimeout(function() {
    console.log(i);
}, 0);
setTimeout(function() {
    console.log(i);
}, 0);
setTimeout(function() {
    console.log(i);
}, 0);
这回你明白了为啥结果是0 1 2 3 3 3了吧。

那个,说它是闭包,又是怎么回事?

为了很好的说明白这个事情,咱们把它放到一个函数中:

var fn = function() {
        for (var i = 0; i < 3; i++) {
                setTimeout(function() {
                        console.log(i);
                }, 0);
                console.log(i);
        }
};
fn();
上面的函数跟咱们常见另外一个例子(div绑定事件)有什么区别:

var fn = function() {
        var divs = document.querySelectorAll('div');
        for (var i = 0; i < 3; i++) {
                divs[i].onclick = function() {
                        alert(i);
                };
        }
};
fn();
点击每一个div都会弹出3。道理是同样的。由于alert(i)中的i是fn做用越中的,于是这是闭包。

《javascript忍者秘籍》书里把一个函数能调用全局变量,也称闭包。

由于做者认为全局环境也能够想象成一个大的顶级函数。 怎么保证能弹出0,1, 2呢。

解决之道:以毒攻毒! 再建立个闭包!!

var fn = function() {
        var divs = document.querySelectorAll('div');
        for (var i = 0; i < 3; i++) {
                divs[i].onclick = (function(i) {
                        return function() {
                                alert(i);
                        };
                })(i);
        }
};
fn();
或者以下的写法:

var fn = function() {
        var divs = document.querySelectorAll('div');
        for (var i = 0; i < 3; i++) {
                (function(i) {
                        divs[i].onclick = function() {
                                alert(i);
                        };
                })(i);
        }
};
fn();
所以原题若是也想setTimeout也弹出0,1,2的话,改为以下:

for (var i = 0; i < 3; i++) {
    setTimeout((function(i) {
        return function() {
            console.log(i);
        };
    })(i), 0);
    console.log(i);
}

复制代码

原型与继承

题目

请用js实现一个类P,包含成员变量a,成员变量b,成员函数sum,sum输出a与b的和,a,b默认值都为0。实现一个类M,M继承自P,在P的基础上增长成员变量c,成员函数sum变成输出a,b,c的和。

题目分析

Js全部的函数都有一个prototype属性,这个属性引用了一个对象,即原型对象,也简称原型。这个函数包括构造函数和普通函数,咱们讲的更可能是构造函数的原型,可是也不可否定普通函数也有原型,实现继承的方法不少,这里使用原型链和构造继承,即组合继承的方式。

function P(a, b) {
    this.a = a || 0;
    this.b = b || 0;
    this.sum = function() {
        return this.a + this.b;
    }
}
 
function M(a, b, c) {
    P.call(this, a, b) //继承P类的成员对象
    this.c = c; //在本身的构造函数中定义的
    this.sum = function() {
        return this.a + this.b + this.c;
    }
}
M.prototype = new P();
var m = new M(2, 2, 2);
M.sum(); //输出6

复制代码

js继承的实现方式

既然要实现继承,那么首先咱们得有一个父类,代码以下:

//定义一个动物类
function Animal(name, eye, skin) {
 
    //属性
    this.name = name || 'Animal';
    this.eye = eye;
    this.skin = skin;
 
    //实例方法
    this.sleep = function() {
        console.log(this.name + '正在睡觉');
    }
}
 
//原型方法
Animal.prototype.eat = function(food) {
    console.log(this.name + '正在吃:' + food);
};

复制代码

下面给你们列出几种继承方式的实现

原型链继承

实现父类代码在(js继承的实现方式中)

核心: 将父类的实例做为子类的原型

function Cat() {}
Cat.prototype = new Animal();
Cat.prototype.name = 'cat';
 
//Test Code
var cat = new Cat();
console.log(cat.name);                     //cat
console.log(cat.eat('fish'));              //cat正在吃:fish
console.log(cat.sleep());                  //cat正在睡觉!
console.log(cat instanceof Animal);        //true
console.log(cat instanceof Cat);           //true
特色:

1. 很是纯粹的继承关系,实例是子类的实例,也是父类的实例

2. 父类新增原型方法/原型属性,子类都能访问到

3. 简单,易于实现

缺点:

1. 要想为子类新增属性和方法,必需要在new Animal()这样的语句以后执行,不能放到构造器中

2. 没法实现多继承

3. 来自原型对象的引用属性是全部实例共享的

4. 建立子类实例时,没法向父类构造函数传参(即没法像这样var cat=new Cat(hair,eye,skin)传参给父类)

推荐指数:★★(三、4两大体命缺陷)
复制代码

构造继承

核心:使用父类的构造函数来加强子类实例,等因而复制父类的实例属性给子类(没用到原型)

function Cat(name) {
    Animal.call(this);
    this.name = name || 'Tom';
}
 
//Test Code
var cat = new Cat();
console.log(cat.name);                 //Tom
//console.log(cat.eat('fish'));        //报错
console.log(cat.sleep());              //Tom正在睡觉!
console.log(cat instanceof Animal);    //false
console.log(cat instanceof Cat);       //true
特色:

1. 解决了1中,子类实例共享父类引用属性的问题

2. 建立子类实例时,能够向父类传递参数(可经过Animal.call(this,name,eye,skin)或者Animal.apply(this,[name,eye,skin])实现)

3. 能够实现多继承(call多个父类对象)

缺点:

1. 实例并非父类的实例,只是子类的实例

2. 只能继承父类的实例属性和方法,不能继承原型属性/方法

3. 没法实现函数复用,每一个子类都有父类实例函数的副本,影响性能

推荐指数:★★(缺点3)
复制代码

实例继承

核心:为父类实例添加新特性,做为子类实例返回

function Cat(name) {
    var instance = new Animal();
    instance.name = name || 'Tom';
    return instance;
}
 
//Test Code
var cat = new Cat();
console.log(cat.name); //Tom
console.log(cat.sleep()); //Tom正在睡觉!
console.log(cat instanceof Animal); //true
console.log(cat instanceof Cat); //false
特色:

不限制调用方式,无论是new 子类()仍是子类(),返回的对象具备相同的效果

缺点:

实例是父类的实例,不是子类的实例

不支持多继承

推荐指数:★★
复制代码

拷贝继承

function Cat(name) {
    var animal = new Animal();
    for (var p in animal) {
        Cat.prototype[p] = animal[p];
    }
    Cat.prototype.name = name || 'Tom';
}
 
//Test Code
var cat = new Cat();
console.log(cat.name); //Tom
console.log(cat.sleep()); //Tom正在睡觉!
console.log(cat instanceof Animal); //false
console.log(cat instanceof Cat); //true
特色:

支持多继承

缺点:

1. 效率较低,内存占用高(由于要拷贝父类的属性)

2. 没法获取父类不可枚举的方法(不可枚举方法,不能使用for in 访问到)

推荐指数:★(缺点1)
复制代码

组合继承

核心:经过调用父类构造,继承父类的属性并保留传参的优势,而后经过将父类实例做为子类原型,实现函数复用

function Cat(name) {
    Animal.call(this);
    this.name = name || 'Tom';
}
Cat.prototype = new Animal();
 
//Test Code
var cat = new Cat();
console.log(cat.name);                 //Tom
console.log(cat.sleep());              //Tom正在睡觉!
console.log(cat instanceof Animal);    //true
console.log(cat instanceof Cat);       //true
特色:

1. 弥补了方式2的缺陷,能够继承实例属性/方法,也能够继承原型属性/方法

2. 既是子类的实例,也是父类的实例

3. 不存在引用属性共享问题

4. 可传参

5. 函数可复用

缺点:

调用了两次父类构造函数,生成了两份实例(子类实例将子类原型上的那份屏蔽了)

推荐指数:★★★★(仅仅多消耗了一点内存)
复制代码

寄生组合继承

核心:经过寄生方式,砍掉父类的实例属性,这样,在调用两次父类的构造的时候,就不会初始化两次实例方法/属性,避免的组合继承的缺点

function Cat(name) {
    Animal.call(this);
    this.name = name || 'Tom';
} (function() {
    // 建立一个没有实例方法的类
    var Super = function() {};
    Super.prototype = Animal.prototype;
    //将实例做为子类的原型
    Cat.prototype = new Super();
})();
 
//Test Code
var cat = new Cat();
console.log(cat.name); //Tom
console.log(cat.sleep()); //Tom正在睡觉!
console.log(cat instanceof Animal); //true
console.log(cat instanceof Cat); //true
特色:

堪称完美

缺点:

实现较为复杂

推荐指数:★★★★(实现复杂,扣掉一颗星)

4.9 附录代码
function Animal (name) {
  // 属性
  this.name = name || 'Animal';
  // 实例方法
  this.sleep = function(){
    console.log(this.name + '正在睡觉!');
  }
  //实例引用属性
  this.features = [];
}
function Cat(name){
}
Cat.prototype = new Animal();
 
var tom = new Cat('Tom');
var kissy = new Cat('Kissy');
 
console.log(tom.name); // "Animal"
console.log(kissy.name); // "Animal"
console.log(tom.features); // []
console.log(kissy.features); // []
 
tom.name = 'Tom-New Name';
tom.features.push('eat');
 
//针对父类实例值类型成员的更改,不影响
console.log(tom.name); // "Tom-New Name"
console.log(kissy.name); // "Animal"
//针对父类实例引用类型成员的更改,会经过影响其余子类实例
console.log(tom.features); // ['eat']
console.log(kissy.features); // ['eat']
缘由分析:

关键点:属性查找过程

执行tom.features.push,首先找tom对象的实例属性(找不到),
那么去原型对象中找,也就是Animal的实例。发现有,那么就直接在这个对象的
features属性中插入值。
在console.log(kissy.features); 的时候。同上,kissy实例上没有,那么去原型上找。
恰好原型上有,就直接返回,可是注意,这个原型对象中features属性值已经变化了。
复制代码

new关键字

假设已经定义了父类Base对象

咱们执行以下代码

var obj = new Base(); 
这样代码的结果是什么,咱们在Javascript引擎中看到的对象模型是:
![](https://img-blog.csdn.net/20180725134719974?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl8zNzU4MDIzNQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)

new操做符具体干了什么呢?其实很简单,就干了三件事情。

var obj = {}; 
obj.__proto__ = Base.prototype; 
Base.call(obj); 

第一行,咱们建立了一个空对象obj

第二行,咱们将这个空对象的__proto__成员指向了Base函数对象prototype成员对象

第三行,咱们将Base函数对象的this指针替换成obj,而后再调用Base函数

注意:new的过程会执行构造函数Base() 再对空对象进行构造
复制代码

如何实现图片懒加载

图片懒加载的原理很简单,就是咱们先设置图片的data-set属性(固然也能够是其余任意的,只要不会发送http请求就好了,做用就是为了存取值)值为其图片路径,因为不是src,因此不会发送http请求。 而后咱们计算出页面scrollTop的高度和浏览器的高度之和, 若是图片举例页面顶端的坐标Y(相对于整个页面,而不是浏览器窗口)小于前二者之和,就说明图片就要显示出来了(合适的时机,固然也能够是其余状况),这时候咱们再将 data-set 属性替换为 src 属性便可。

同源,跨域

推荐阅读 浏览器同源政策及其规避方法
复制代码

js有几种类型值,画内存图

栈:原始数据类型(Undefined,Null,Boolean,Number、String)

堆:引用数据类型(对象、数组和函数)

两种类型的区别是:

存储位置不一样;

原始数据类型直接存储在栈(stack)中的简单数据段,占据空间小、大小固定,属于被频繁使用数据,因此放入栈中存储;

引用数据类型存储在堆(heap)中的对象,占据空间大、大小不固定,若是存储在栈中,将会影响程序运行的性能;引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址。当解释器寻找引用值时,会首先检索其在栈中的地址,取得地址后从堆中得到实体。

![](https://user-gold-cdn.xitu.io/2019/3/20/169991ff8c378649?w=505&h=431&f=png&s=6925)
复制代码

["1", "2", "3"].map(parseInt)

[1, NaN, NaN] 由于 parseInt 须要两个参数 (val, radix), 其中 radix 表示解析时用的基数。 map 传了 3 个 (element, index, array),对应的 radix 不合法致使解析失败。
复制代码

声明提高

var let const

那些操做会形成内存泄漏?

内存泄漏指任何对象在您再也不拥有或须要它以后仍然存在。

垃圾回收器按期扫描对象,并计算引用了每一个对象的其余对象的数量。若是一个对象的引用数量为 0(没有其余对象引用过该对象),或对该对象的唯一引用是循环的,那么该对象的内存便可回收。

setTimeout 的第一个参数使用字符串而非函数的话,会引起内存泄漏。

闭包、控制台日志、循环(在两个对象彼此引用且彼此保留时,就会产生一个循环)
复制代码

关于arguments

1. 定义

因为JavaScript容许函数有不定数目的参数,因此咱们须要一种机制,能够在函数体内部读取全部参数。这就是arguments对象的由来。

arguments对象包含了函数运行时的全部参数,arguments[0]就是第一个参数,arguments[1]就是第二个参数,以此类推。这个对象只有在函数体内部,才可使用。

var f = function(one) {
    console.log(arguments[0]); //1
    console.log(arguments[1]); //2
    console.log(arguments[2]); //3
}
f(1, 2, 3);
arguments对象除了能够读取参数,还能够为参数赋值(严格模式不容许这种用法)

var f = function(a, b) {
    arguments[0] = 3; //对a从新赋值
    arguments[1] = 2; //对b从新赋值
    return a + b;
}
console.log(f(1, 1)); //5
能够经过arguments对象的length属性,判断函数调用时到底带几个参数。

var f = function() {
    return arguments.length;
}
console.log(f(1, 2, 3));               //3
console.log(f(1, 2));                  //2
console.log(f(1));                     //1
console.log(f());                      //0
2. 与数组的关系

须要注意的是,虽然arguments很像数组,但它是一个对象。数组专有的方法(好比slice和forEach),不能在arguments对象上直接使用。

可是,能够经过apply方法,把arguments做为参数传进去,这样就可让arguments使用数组方法了。

// 用于apply方法
 myfunction.apply(obj, arguments). 
// 使用与另外一个数组合并 
Array.prototype.concat.apply([1,2,3], arguments) 
要让arguments对象使用数组方法,真正的解决方法是将arguments转为真正的数组。下面是两种经常使用的转换方法:slice方法和逐一填入新数组。

var args = Array.prototype.slice.call(arguments); 
 
// or
 
var args = []; 
for (var i = 0; i < arguments.length; i++) { 
    args.push(arguments[i]); 
}
3. callee属性

arguments对象带有一个callee属性,返回它所对应的原函数。

var f = function(one) {
    console.log(arguments.callee === f);
}
f(1);
能够经过arguments.callee,达到调用函数自身的目的。这个属性在严格模式里面是禁用的,所以不建议使用。

4. 题目sum(2)(3)

// 写一个 function 让下面两行代码输出的结果都为 5 
console.log(sum(2, 3)); 
console.log(sum(2)(3)); 
说实话,第一眼看到的时候内心是有点虚的(由于第一次看到它)。sum(2)(3),这种形式的代码确实少见。可是第一反应就是链式调用。

链式调用咱们熟悉啊,特别是 jQuery 里面,咱们经常能看到连着写的代码。实现原理就是在方法结束时 return 合适的元素对象。

$('#id').parent().siblings('selector').css({
    color: 'red'
});
这道题考什么呢?认真分析了一下,应该有链式调用,toString,柯里化,数组操做等相关内容。大概这些能够知足需求吧?

如何写代码,脑海中大致上有构思了,可是当时手上仅有笔和纸,思路连不上来啊。还好面前放着一台台式机(嘿嘿嘿,机器上写完再抄回纸上)

个人实现大概是这样的。

var sum = (function() {
    var list = [];
 
    var add = function() {
        // 拼接数组
        var args = Array.prototype.slice.call(arguments);
        list = list.concat(args);
        return add;
    }
    // 覆盖 toString 方法
    add.toString = function() {
        // 计算总和
        var sum = list.reduce(function(pre, next) {
            return pre + next;
        });
        // 清除记录
        list.length = 0;
        return sum;
    }
 
    return add;
})();
 
sum(2, 3);
// 5
sum(2)(3);
// 5
这个方法比较复杂,下面介绍个简便的。

var add = function add() {
    var cache;
    if (arguments.length === 1) {
        cache = arguments[0];
        return function(number) {
            return cache + number;
        }
    } else {
        return arguments[0] + arguments[1];
    }
}
console.log(add(2, 3));
console.log(add(2)(3));

复制代码

写一个js判断全等的方法

//利用JSON.stringify,将两个对象转化为字符串。
字符串相等的话,说明两个对象全等。
let a = {a:0,b:1,c:2};
let b = {a:0,b:1,c:2};
let c = {a:1,b:1,c:2};
let x = JSON.stringify(a) == JSON.stringify(b);
let y = JSON.stringify(a) == JSON.stringify(c);
console.log(x);
console.log(y);
复制代码

遍历对象的方法

var obj={a:'A',b:'B',c:'C'};

1. for ... in 循环
for(key in obj){
    console.log(key);// a,b,c
}

2. Object.keys()
Object.keys(obj);//["a", "b", "c"]
复制代码

防抖和节流

一、防抖

触发高频事件后n秒内函数只会执行一次,若是n秒内高频事件再次被触发,则从新计算时间

  • 思路

每次触发事件时都取消以前的延时调用方法

function debounce(fn) {
      let timeout = null; // 建立一个标记用来存放定时器的返回值
      return function () {
        clearTimeout(timeout); // 每当用户输入的时候把前一个 setTimeout clear 掉
        timeout = setTimeout(() => { // 而后又建立一个新的 setTimeout, 这样就能保证输入字符后的 interval 间隔内若是还有字符输入的话,就不会执行 fn 函数
          fn.apply(this, arguments);
        }, 500);
      };
    }
    function sayHi() {
      console.log('防抖成功');
    }

    var inp = document.getElementById('inp');
    inp.addEventListener('input', debounce(sayHi)); // 防抖
复制代码

二、节流

高频事件触发,但在n秒内只会执行一次,因此节流会稀释函数的执行频率

  • 思路

每次触发事件时都判断当前是否有等待执行的延时函数

function throttle(fn) {
      let canRun = true; // 经过闭包保存一个标记
      return function () {
        if (!canRun) return; // 在函数开头判断标记是否为true,不为truereturn
        canRun = false; // 当即设置为false
        setTimeout(() => { // 将外部传入的函数的执行放在setTimeout中
          fn.apply(this, arguments);
          // 最后在setTimeout执行完毕后再把标记设置为true(关键)表示能够执行下一次循环了。当定时器没有执行的时候标记永远是false,在开头被return掉
          canRun = true;
        }, 500);
      };
    }
    function sayHi(e) {
      console.log(e.target.innerWidth, e.target.innerHeight);
    }
    window.addEventListener('resize', throttle(sayHi));
复制代码
  • 问题

为何要 fn.apply(this, arguments);而不是这样 fn()

答:加上 apply 确保 在 sayHi 函数里的 this 指向的是 input对象(否则就指向 window 了,不是咱们想要的)。 这里的箭头函数依旧是指向 input 对象。

https怎么保证安全的?

什么状况下会碰到跨域问题?有哪些解决方法?

  • 跨域问题是这是浏览器为了安全实施的同源策略致使的,同源策略限制了来自不一样源的document、脚本,同源的意思就是两个URL的域名、协议、端口要彻底相同。
  • script标签jsonp跨域、nginx反向代理、node.js中间件代理跨域、后端在头部信息设置安全域名、后端在服务器上设置cors。

如何判断一个变量是对象仍是数组?

function isObjArr(value){
     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不是数组也不是对象')
      }
}
//ps:千万不能使用typeof来判断对象和数组,由于这两种类型都会返回"object"复制代码

事件循环机制

html事件循环:
一个浏览器环境,只能有一个事件循环,而一个事件循环能够多个任务队列(task queue),每一个任务都有一个任务源(task source)。

相同任务源的任务,只能放到一个任务队列中。

不一样任务源的任务,能够放到不一样任务队列中。

EcmaScript规范中指出:
任务队列(Job queue)是一个先进先出的队列,每个任务队列是有名字的,至于有多少个任务队列,取决于实现。每个实现至少应该包含以上两个任务队列。

结论:EcmaScript的Job queue与HTML的Task queue有殊途同归之妙。它们均可以有好几个,多个任务队列之间的顺序都是不保证的。

例子:
setImmediate(function(){ 
   console.log(1); 
},0); 

setTimeout(function(){ 
   console.log(2); 
},0);

new Promise(function(resolve){ 
    console.log(3); 
    resolve(); 
    console.log(4); 
}).then(function(){
    console.log(5); 
}); 

console.log(6); 

process.nextTick(function(){ 
    console.log(7); 
}); 

console.log(8);

结果:3 4 6 8 7 5 2 1

事件注册顺序以下:
setImmediate - setTimeout - promise.then - process.nextTick

优先级关系:
process.nextTick > promise.then > setTimeout > setImmediate

V8实现中,两个队列各包含不一样的任务:
macrotasks(宏任务): script(总体代码),setTimeout, setInterval, setImmediate, I/O, UI rendering
microtasks(微任务): process.nextTick, Promises, Object.observe, MutationObserver

执行过程以下:
js引擎首先从macrotask queue中取出第一个任务,执行完毕后,将microtask queue中的全部任务取出,按顺序所有执行;而后再从macrotask queue中取下一个,执行完毕后,再次将microtask queue中的所有取出; 循环往复,直到两个queue中的任务都取完。

setTimeout会默认延迟4毫秒(ms)。

问题:
process.nextTick也会放入microtask quque,为何优先级比promise.then高呢?

答:process.nextTick 永远大于promise.then,缘由其实很简单。
在Node中,_tickCallback在每一次执行完TaskQueue中的一个任务后被调用,而这个_tickCallback中实质上干了两件事:
1. nextTickQueue中全部任务执行掉(长度最大1e4,Node版本v6.9.1)
2. 第一步执行完后执行_runMicrotasks函数,执行microtask中的部分(promise.then注册的回调)
因此很明显process.nextTick > promise.then

复制代码

深拷贝和浅拷贝

区别

1.浅拷贝: 将原对象或原数组的引用直接赋给新对象,新数组,新对象/数组只是原对象的一个引用

2.深拷贝: 建立一个新的对象和数组,将原对象的各项属性的“值”(数组的全部元素)拷贝过来,是“值”而不是“引用”

为何要使用深拷贝?

咱们但愿在改变新的数组(对象)的时候,不改变原数组(对象)

深拷贝的要求程度

咱们在使用深拷贝的时候,必定要弄清楚咱们对深拷贝的要求程度:是仅“深”拷贝第一层级的对象属性或数组元素,仍是递归拷贝全部层级的对象属性和数组元素?

怎么检验深拷贝成功

改变任意一个新对象/数组中的属性/元素, 都不改变原对象/数组

只作第一层深拷贝

深拷贝数组(只拷贝第一级数组元素)

  1. 直接遍历
var arr = [1,2,3,4];


function copy(arg){
  
  var newArr = [];
  
  for(var i = 0; i < arr.length; i++) {
    newArr.push(arr[i]);
  }
  
  return newArr;
}

var newArry = copy(arr);
console.log(newArry);
newArry[0] = 10;
console.log(newArry); // [10,2,3,4]
console.log(arr)  // [1,2,3,4]
复制代码
  1. slice()
var arr = [1,2,3,4]
var copyArr = arr.slice();
copyArr[0] = 10;
console.log(copyArr); // [10,2,3,4]
console.log(arr); // [1,2,3,4]

// slice() 方法返回一个从已有的数组中截取一部分元素片断组成的新数组(不改变原来的数组!)
用法:array.slice(start,end) start表示是起始元素的下标, end表示的是终止元素的下标
当slice()不带任何参数的时候,默认返回一个长度和原数组相同的新数组

复制代码
  1. concat()
var arr = [1,2,3,4]
var copyArr = arr.concat();
copyArr[0] = 10;
console.log(copyArr); // [10,2,3,4]
console.log(arr); // [1,2,3,4]

//concat() 方法用于链接两个或多个数组。( 该方法不会改变现有的数组,而仅仅会返回被链接数组的一个副本。)
用法:array.concat(array1,array2,......,arrayN)
由于咱们上面调用concat的时候没有带上参数,因此var copyArray = array.concat();实际上至关于var copyArray = array.concat([]);
也即把返回数组和一个空数组合并后返回
复制代码

深拷贝对象

1.直接遍历

var obj = {
    name: "张三",
    job: "学生"
  }
  
  function copy (obj) {
    let newobj = {}
    for(let item in obj) {
      newobj[item] = obj[item];
    }
    return newobj;
  }
  
  var copyobj = copy(obj)
  copyobj.name = "李四"
  console.log(copyobj) // {name: '李四', job:: '学生'}
  console.log(obj) // {name: '张三', job:: '学生'}

复制代码
  1. ES6的Object.assign
var obj = {
 name: '张三',
 job: '学生'
}

var copyobj = Object.assign({},obj)
copyobj.name = '李四'
console.log(copyobj) // {name: '李四', job:: '学生'}
console.log(obj)    // {name: '张三', job:: '学生'}

Object.assign:用于对象的合并,将源对象(source)的全部可枚举属性,复制到目标对象(target),并返回合并后的target
用法: Object.assign(target, source1, source2);  因此 copyObj = Object.assign({}, obj);  这段代码将会把obj中的一级属性都拷贝到 {}中,而后将其返回赋给copyObj
复制代码
  1. ES6扩展运算符:
var obj = {
  name: '张三',
  job: '学生'
}

var copyobj = {...obj}
copyobj.name = '李四'
console.log(copyobj)
console.log(obj)

扩展运算符(...)用于取出参数对象的全部可遍历属性,拷贝到当前对象之中
复制代码

ajax请求

// 1.XMLHttpRequest对象用于在后台与服务器交换数据   
var xhr = new XMLHttpRequest();
// 2.
xhr.open('GET', url, true);
//3.发送请求
xhr.send();
//4.接收返回
//客户端和服务器端有交互的时候会调用onreadystatechange
xhr.onreadystatechange = function() {
    // readyState == 4说明请求已完成
    if (xhr.readyState == 4 && xhr.status == 200 || xhr.status == 304) { 
        // 从服务器得到数据 
        fn.call(this, xhr.responseText);  
    }
};
复制代码

前端安全性问题

一、xss跨站脚本攻击(原理、如何进行的、防护手段是什么,要说清楚)

二、CSRF跨站请求伪造(如何伪造法?怎么防护?等等都要说清楚)

三、sql脚本注入(注入方式,防护方式)

四、上传漏洞 (防护方式)

你是如何处理前端性能问题的?

减小 HTTP 请求数量

在浏览器与服务器进行通讯时,主要是经过 HTTP 进行通讯。浏览器与服务器须要通过三次握手,每次握手须要花费大量时间。并且不一样浏览器对资源文件并发请求数量有限(不一样浏览器容许并发数),一旦 HTTP 请求数量达到必定数量,资源请求就存在等待状态,这是很致命的,所以减小 HTTP 的请求数量能够很大程度上对网站性能进行优化。

  • CSS Sprites:国内俗称 CSS 精灵,这是将多张图片合并成一张图片达到减小 HTTP 请求的一种解决方案,能够经过 CSS background 属性来访问图片内容。这种方案同时还能够减小图片总字节数。
  • 合并 CSS 和 JS 文件:如今前端有不少工程化打包工具,如:grunt、gulp、webpack等。为了减小 HTTP 请求数量,能够经过这些工具再发布前将多个 CSS 或者 多个 JS 合并成一个文件。
  • 采用 lazyLoad:俗称懒加载,能够控制网页上的内容在一开始无需加载,不须要发请求,等到用户操做真正须要的时候当即加载出内容。这样就控制了网页资源一次性请求数量。

控制资源文件加载优先级

浏览器在加载 HTML 内容时,是将 HTML 内容从上至下依次解析,解析到 link 或者 script 标签就会加载 href 或者 src 对应连接内容,为了第一时间展现页面给用户,就须要将 CSS 提早加载,不要受 JS 加载影响。 通常状况下都是 CSS 在头部,JS 在底部。

利用浏览器缓存

浏览器缓存是将网络资源存储在本地,等待下次请求该资源时,若是资源已经存在就不须要到服务器从新请求该资源,直接在本地读取该资源。

减小重排(Reflow)

基本原理:重排是 DOM 的变化影响到了元素的几何属性(宽和高),浏览器会从新计算元素的几何属性,会使渲染树中受到影响的部分失效,浏览器会验证 DOM 树上的全部其它结点的 visibility 属性,这也是 Reflow 低效的缘由。若是 Reflow 的过于频繁,CPU 使用率就会急剧上升。 减小 Reflow,若是须要在 DOM 操做时添加样式,尽可能使用 增长 class 属性,而不是经过 style 操做样式。

减小 DOM 操做

图标使用 IconFont 替换

算法

写一个冒泡算法

思路:
    a)比较两个相邻的元素,若是后一个比前一个大,则交换位置

    b) 第一轮的时候最后一个元素应该是最大的一个

    c) 按照第一步的方法进行两个相邻的元素的比较,因为最后一个元素已是最大的了,因此最后一个元素不用比较。
代码:
    
    function sort(element){
        for(var i = 0;i<element.length-1;i++) {
            for(var j = 0;j<element.length-i-1;j++){
                if(element[j]>element[j+1]){
                    //把大的数字放到后面
                    var swap = element[j];
                    element[j] = element[j+1];
                    element[j+1] = swap;
                }
            }
        }
    }
    var element = [3,5,1,2,7,8,4,5,3,4];
    sort(element);
复制代码

写一个快速排序

"快速排序"的思想很简单,整个排序过程只须要三步:

(1)在数据集之中,选择一个元素做为"基准"(pivot)。

(2)全部小于"基准"的元素,都移到"基准"的左边;全部大于"基准"的元素,都移到"基准"的右边。

(3)对"基准"左边和右边的两个子集,不断重复第一步和第二步,直到全部子集只剩下一个元素为止。
复制代码
function quickSort(arr) {
  if(arr.length < 2) {
    return arr;
  } else {
    const pivot = arr[0]; // 基准值
    const pivotArr = []; // 同样大的放中间
    const lowArr= []; // 小的放左边
    const hightArr = []; // 大的放右边
    arr.forEach(current => {
      if(current === pivot) pivotArr.push(current);
      else if(current > pivot) hightArr.push(current);
      else lowArr.push(current);
    })
    return quickSort(lowArr).concat(pivotArr).concat(quickSort(hightArr));
  }
}
复制代码

移动端适配

插件:amfe-flexible + postcss-px2rem

amfe-flexible:自动根据不一样设备改变data-dpr的值,这样就能够根据不一样的data-dpr设置字体大小不变,仅放大相应倍数。

postcss-px2rem:打包的时候把项目里面的px统一转换成rem,转换的基准值根据配置设置的(.postcssrc.js) /由于我是以750px(iphone6)宽度为基准,因此remUnit为37.5/

通过试验结果:

postcss-px2rem:只负责把项目里面的px按照基准值转换成rem,并不负责根节点动态font-size的计算。 例如,代码里面有个高度固定:180px, 基准值是:37.5, 那最后界面上的rem=180/37.5=4.8rem 无论换不一样客户端手机,不一样分辨率,界面上都是固定4.8rem【rem的值是固定的,根据根节点的font-size不一样,在界面显示的px也不一样】,界面上显示的px = 16(没有设置font-size的话默认是16px)* 4.8rem = 76.8px

相关文章
相关标签/搜索