我自己总结的在一些面试中常问的前端的知识点,希望有帮助。

1.forEach, map, filter, some

1.forEach(item, index)

  • forEach是针对数组的每个元素,而且会改变原数组,没有返回值。
  • 不能终止或跳出forEach循环
  • 使用箭头函数,this指向window

2.map(item, index)

  • map不会修改原始数组,返回新的数组

3.filter(item, index)

  • 不改变原数组,返回新的数组

2.进程线程协程

  • 线程属于进程,线程共享进程的内存地址空间,线程几乎不占用系统资源。通信问题,进程相当于一个容器,而线程是运行在容器里面,因此对于容器内的东西,线程是共享的,因此线程之间的通信可以通过全局变量进行通信,但由此带来例如多个线程读取同一个地址变量的时候带来不可预期的后果,这时候引入了锁。多线程不安全,当一个线程崩溃了,导致整个进程也会崩溃,即其他线程也挂了,但多进程不会,一个进程挂了,其他进程依然正常运行。进程是系统分配资源的最小单位,线程是cpu调度的最小单位。
  • 系统由一个个进程组成,一般情况下,包含文本区域,数据区域和堆栈。因此进程的创建和销毁都是相对于系统资源,是一种比较昂贵的操作。进程是抢占式的争夺cpu运行自身,而cpu单核的情况下同一时间智能执行一个进程的代码。但是多进程的实现则是通过cpu的快速切换不同进程,使得看上去就像多个进程同时在进行。而且由于进程间是隔离的,各自拥有自己的内存资源,因此相对于线程比较安全,所以不同进程之间的数据智能通过ipc进行通信共享。
  • 协程是属于线程的。协程程序 是在线程里面跑的,因此协程又称为微线程。协程没有线程的上下文切换。协程的调度切换是程序员手动切换的,更加灵活
  • 进程之间切换代价大,线程之间切换代价小。

3.meta标签

  • name: name属性主要用于描述网页,比如网页的关键词,叙述等。与之对应的属性值为content,content的内容是对name填入类型的具体描述。<meta name="参数" content="具体的描述">
  • kewords: 告诉搜索引擎你的关键字
  • description: 网站描述的内容
  • viewport(移动端视口),这个属性主要用于移动端网页,距离: <meta name="vieport" content="width=device-width,intital-scale=1">
  • robots(定义搜索引擎爬虫的索引方式),robots用来告诉哪些页面需要索引,哪些不需要索引。content的参数有all,none,index,noindex,follow,nofollow,举例<meta name="robots" content="none">
  • author,用于标明网页作者 <meta name="author" content="ggg">
  • copyright: 表明版权信息,<meta name="copyright" content="gg">
    • revisit-after,如果页面不是经常更新,为了减轻搜索引擎爬虫对服务器带来的压力,可以设置一个爬虫的访问时间。如果访问时间过短,爬虫将按照定义的时间来访问。<meta name="revisit-after" content="7days">
  • render(双核浏览器渲染方式),用于指定双核浏览器以何种方式渲染页面。
  • 前面主要都是name,content的属性,现在是http-equiv,相当于http文件头的作用,包含了以下
  • 语法格式<meta http-equiv="参数"" content="具体描述">
  • content-Type(设定网页的字符集) ,<meta charset= "utf-8">
  • X-UA-Compatible(浏览器采取何种版本渲染当爱情按页面),<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">//制定ie和chrome都以最新版本渲染当前页面。
  • ***-control(指定请求和响应遵循的缓存机制),<meta http-equiv="chache-control" content="no-***">
    • no-chche: 先发送请求,与服务器确认该资源是否被更改,如果没有被更改,则使用缓存。
    • no-store: 不允许缓存,每次都要去服务器请求,下载完整的响应
    • public: 缓存所有的响应,但并非必须项,因为max-age可以做到效果。
    • private: 只为单个用户缓存,因此不允许任何中继进行缓存,例如cdn不允许缓存private的响应。
    • max-age: 表示从当前请起开始,该响应在多久内被缓存,而不去服务器请求资源。
    • expires(网页到期时间,过期后网页必须到服务器上重新传输),<meta http-equiv="expires" content="unday 26 October 2016 01:00 GMT">
    • refresh(自动刷新并指向某一页面),网页将在设定的时间内,自动刷新并掉向设定的网址。<meta http-equiv="refresh" content="2; URK=http://www.xsss.com">//意思为2s之后转向我的博客
    • Set-Cookie(cookie设定):如果网页过期,那么这个网页在本地的cookies也会被自动删除。<meta http-equiv="Set-Cookie" content="name, date"> //格式 例子<meta http-equiv="Set-Cookie" content="User=Lxxyx; path=/; expires=Sunday, 10-Jan-16 10:00:00 GMT">

4.垃圾回收

5.闭包

6.实现一个倒计时的函数,setTimeout和setInterval分别实现

function fn(num) {
    for (let i = num; i>=0; i--) {
        setTimeout(function(){
            console.log(i)
        }, (num-i)*1000)
    }

fn(5), 5 ,4, 3, 2, 1//间隔1s输出一次。
function fn2(num) {
  for (var i = 0;i < num; i++) {
    (function(i) {
      setTimeout(function() {
        console.log(i)
      }, (num-i)*1000)
    })(i)
  }
}

function fn(num) {
    var timer = setInterval(function() {
        if (num >= 0) {
            console.log(num);
            num --
        }  else {
            clearInterval(timer)
        }
    }, 1000)
}

7.继承

1.原型继承
function parent() {
    this.name = 'parent';
    this.say = function() {
        console.log('this is parent say')
    }
}
parent.prototype.eat = function() {
    console.log('parent eat food')
}
function child() {
    this.name = 'child'
}
child.prototype = new parent()
var c = new child()
console.dir(c)
这样会把父类的公有和私有方法都继承过来
2.call继承
function child() {
    this.name = 'child';
    parent.call(this)
}
这样只会继承父类的私有方法,不会继承公有方法(比如prototype上面的方法)
3.冒充对象继承,使用for in 遍历父类的属性,公有方法可以通过hasOwnProperty()过滤
function child() {
    var p = new parent();
    //for in 遍历原型链
    for (var attr in p) {
        this.attr = p.attr
    }
    //如果不要原型链上面的
    for (var attr in p) {
        if (p.hasOwnProperty(attr)) {
            this.attr = p.attr
        }
    }
}

8.实现sleep函数

9.NaN(not a number)

  • typeof NaN // 'Number'
  • 什么时候返回NaN
    1. 无穷大除以无穷大,Infinity/Infinity
    2. 给任意负数做开方运算, Math.sqrt(-4)
    3. 算术运算符与不是数字或者无法转化为数字的操作数一起使用, 'a'-1
    4. 字符串解析为数字,parseFloat('a')
    5. isNaN,会先尝试把这个参数转化为数值,对转化的结果判断是否为NaN

10.js的浮点数的精度问题

  • js所有的数值包括整数和小数都只有一种类型,Number。使用64位固定长度表示。

    1. 符号位S: 第一位是正负数符号位(sign),0代表正数,1代表负数
    2. 指数位E: 中间的11位存储指数(exponent),用来表示次方数
    3. 尾数位M: 最后的52位是尾数(mantissa),超出的部分自动进一舍零。
  • 0.1+0.2的计算,首先十进制的0.1和0.2先被转化为二进制,由于浮点数用二进制表示是无穷的:因浮点数小数位而截断的二进制数字再转华为十进制,就成了0.3000000004,在进行运算产生误差。

  • 解决方法
    1.toFixed()
    2.toPrecision(12),会转化为字符串,在用parseFloat解析。

  1. 左边100px,右边自适应。

    <style>
    html, body {
      height: 100%;
    }
    .wrap {
      height: 100%;
      position: relative;
    }
    .left {
      height: 100%;
      width: 100px;
      background: red;
      position: absolute;
    }
    .right {
      height: 100%;
      margin-left: 100px;
      width: 100%;
      background: pink;
      position: absolute;
    }
    </style>
    </head>
    <body>
    <div class="wrap">
    <div class="left"></div>
    <div class="right"></div>
    </div>
    </body>
    flex版本
    .wrap {
    display: flex;
    height: 100%;
    }
    .left {
    width: 100px;
    height: 100%;
    }
    .right {
    flex: 1;
    height: 100%
    }
    float版本
    .wrap {
    height: 100%
    }
    .left {
    float: left;
    width: 100px;
    height: 100%
    }
    .right {
    margin-left: 100px;
    width: auto;
    height: 100%;
    }
  2. http是无状态的协议,怎么记录登录状态?

    • cookie:cookie是第一次web端输入登录信息,在server端生成并保存cookie,后通过response的setCookie方法,把登录信息放在响应头中。浏览器得到形影后,如果有cookie,会把cookie存放在本地,下次请求把cookie放在request的header中。后台可以根据cookie有没有登录信息,或者信息是否超时进行下一步操作。
    • session:session典型使用场景购物车,session基于cookie实现,第一次创建session的时候,服务端会在http协议中告诉客户端,需要在cookie的里面记录一个session_id,每次请求把这个会话的id发送给服务端,服务端便知道自己是谁。session保存在服务端,有一个唯一标识。服务端识别特定的用户,使用cookie,第一次创建session的时候,服务端会在http协议中告诉客户端,需要在cookie记录session_id,以后每次请求把这个会话的id发送到服务会话跟踪。
    • token:常用在接口校验,是服务端生成一串字符串,作为客户端请求的标识,用户第一次登陆后,服务器生成一个token并将token返回客户端,以后客户端只需要带着token请求数据,无需用户名密码。
    • token具体:客户端使用用户名和密码请求登录。服务端收到请求,验证用户名和密码。验证成功后,服务端会生成一个token,然后把这个token发送给客户端。客户端收到token后把它存储起来,可以放在cookie或者Local Storage(本地存储)里。客户端每次向服务端发送请求的时候都需要带上服务端发给的token。服务端收到请求,然后去验证客户端请求里面带着token,如果验证成功,就向客户端返回请求的数据。

13.深拷贝的递归实现

利用JSON.parse和JSON.stringify
例1.
var source = {name: 'source', child: {name: 'child'}}
var target = JSON.parse(JSON.stringify(source))
target.name = "target"
console.log(source.name) //source
console.log(target.name) // target
例2.
var source = {name: function() {console.log(111)},child: {name: 'child'}}
var target = JSON.parse(JSON.stringify(source))
console.log(target.name) // undefined
例3.
var source = {name: function() {console.log(1)}, child: new RegExp('e')}
var target = JSON.parse(JSON.stringify(source))
console.log(target.name) //undefined
console.log(target.child) // object

JSON.parse(JSON.stringify(xx)),满足基本的深拷贝需求,而且能够处理JSON格式能够处理的数据,但是对于正则,函数类型无法进行深拷贝。

//递归实现深拷贝
function deepCopy(source) {
  if (!source || typeof source !== 'object') {
    throw new Error ('incorrect arguments')
  }
  var targetObj = source.constructor === Array? []: {}
  for (var key in source) {
    if (source.hasOwnProperty(key)) {
      if (source[key] && typeof source[key] === 'object') {
        targetObj[key] = source[key].constructor === Array ? [] : {}
        targetObj[key] = deepCopy(source[key])
      } else {
        targetObj[key] = source[key]
      }
    }
  }
  return targetObj
}

14.前端优化

  • 降低请求量: 合并资源,减少http请求,gzip压缩文件,懒加载
  • 加快请求速度: cdn预解析,减少域名数,并行加载,cdn分发
  • 缓存: http协议缓存请求,离线缓存localStorage
  • 渲染: js/css优化,加载顺序,服务端渲染。

15.原型:

  • var obj3 = new Foo();

  • ①当使用new去调用的时候,函数会作为构造器去调用②this会指向一个对象(这里是obj3),而这个对象的原型会指向构造器的prototype属性(这里是Foo.prototype)
    15.防抖和节流
    1.防抖:在定时器的时间范围内再次触发则重新计时。

    一段模仿ajax的防抖实现:
    
    防抖的实现: <input type="text" id="debounce">
    
    function ajax(content) {
     console.log("Ajax request" + content)
    }
    function debounce(func, delay) {
     return function(args) {
       let that = this;
       let_args = args
       clearTimeout(fun.id)
       fun.id = setTimeout(function() {
         func.call(that, _args)  
       }. delay)
     }
    }
    let inputb = document.getElementById("debounce");
    let debounceAjax = debounce(ajax, 2000)
    inputb.addEventListener('keyup', function(e) {
     debounceAjax(e.target.val)  
    })
    「函数防抖」应用的场景是搜索框输入实时触发搜索,或者是 window 的 resize,
    这时如果你一直输入,或者一直resize,那我就一直不执行函数,是没有问题的,要的就是这个效果。
    //防抖
    function debounce(func, delay) {
     var timer;
     return function() {
       var _this = this;
       var args = arguments;
       if (timer) {
         clearTimeout
       }
       timer = setTimeout(function() {
         func.apply(_this, args)
         }, delay)
     }
    }

    2.节流: 如果在定时器的时间范围内再次触发,不予理睬,等待当前定时器完成,才能启动下一个定时器。

    function throttle(func, delay) {
     var timer;
     return function() {
       var _this = this;
       var args = arguments;
       if (timer) {
         return
       }
       timer = setTimeout(function() {
         func.apply(_this, args);
         timer = null
         }, delay)
     }
    } 

16.箭头函数需要注意的地方

  • 箭头函数的this沿着函数作用域链往上找。
  • 箭头函数没有arguments,取到的arguments为父作用域的。
    function foo() {
    return () => {
     console.log(arguments[0])
    }
    foo(1,2)(3,4) //1,如果不是箭头函数为function则为3
    }
    //传递参数
    function foo() {
    return (...args) => {
     console.log(args)
    }
    }
    foo(1, 2)(3, 4) //输出[3, 4]
  • 返回对象使用()包裹
    let func = (value, num) => ({total: value*num})

17.什么是排序的稳定性:

  • 定义: 两个相等的数在排序后,相对位置不变。
  • 好处: 从一个键上面开始排序,然后从另一个键上开始排序,第一个键排序的结果可以为第二个键牌组所用。
  • 稳定: 基数排序,冒泡排序,插入排序,归并排序。不稳定: 堆排序,快速排序,希尔排序,直接选择排序。

18.ajax

var xmlhttp = new XMLHttpRequest;
xmlhttp.onreadystatechange = function() {
  if (xmlhttp.readState == 4 and xmlhttp.status == 200) {
    document.getElementById('div').innerHTML = xmlhttp.responseText;
  }
}
xmlhttp.open('GET', 'url', true)
xmlhttp.send()

19.websocket:

  • websocket必须浏览器发起,请求头如下

    GET ws://localhost:3000/ws/chat HTTP/1.1
    Host: localhost
    Upgrade: websocket
    Connection: Upgrade
    Origin: http://localhost:3000
    Sec-WebSocket-Key: client-random-string
    Sec-WebSocket-Version: 13

    与http的不同:

    • GET的请求地址以ws开头
    • 请求头的Upgrade:websocket和connection: websocket
    • sec-websocket-key: 用于标识这个连接
    • sec-websocket-version: 指定socket的版本
  • 服务器接收请求返回相应:

    HTTP/1.1 101 Switching Protocols
    Upgrade: websocket
    Connection: Upgrade
    Sec-WebSocket-Accept: server-random-string

20.数组去重:

  • 使用set,Array.from是es6的方法,把具有长度的类数组对象解析为数组
    arr = new Set([1,1,2,3,4,5,4])
    Array.from(arr) //[1,2,3,4]
  • [].prototype.slice.call(arguments),一般对arguments使用。
  • 扩展运算符。
    function add (a,b,c,d,e) {
    console.log(arguments, typeof arguments) // arguments[1,2,3,4,5], object
    let arr = [...arguments] //转化为数组  
    }

21.一道使用promise实现红灯亮3s,绿灯2s,黄灯1s

var red = function() {
  console.log('red')
}
var green = function() {
  console.log('green')
}
var yellow = function() {
  console.log('yellow')
}

var tic = function(timmer, cb) {
  return new Promise((rs, re) => {
      cb();
      rs();
    })
}
//当这里要不停的循环的话,不可以用while true 因为这里主线成相当于一直进行,settimeout不起作用
var step = function() {
  tic(3000, red)
  .then(() => tic(2000, green))
  .then(() => tic(1000, yellow))
  .then(() => step())
}

22.web语义化的好处

  • web语义化是指通过html标记页面包含的信息,包含了html标签的语义化和css命名的语义化html标签的语义化:通过使用包含语义的标签恰当地表示文档的结构。css命名的语义化指:为html标签添加有意义的clss,id,来补充未表达的语义。
  • 语义化的优点:
    1.去掉样式后,页面结构清晰
    2.盲人使用读屏器更好的阅读
    3.搜索引擎更好的理解页面,有利于维护
    4.使团队项目的可持续运作一级维护。

23.http的请求方式

  • get: 请求服务的某个资源。
  • head: 与get类似,但服务器在响应中返回首部,不返回实体的主体部分
  • put: 让服务器用请求的主体部分来创建一个由所请求的url命名一致的文档。或者如果这个url存在的话,就用请求的主体部分代替它。
  • post: 向服务器输入数据。
  • trace: 在目的服务器发起一个回环诊断,最后一站的服务器会弹回一个trace响应并在响应主体中携带它收到的原始请求报文。trace主要用于诊断,用于验证请求是否如愿穿过了请求/响应链。
  • delete: 从服务器删除指定资源。

23.格式化上下文BFC

  • 创建规则

    1.根元素
    2.浮动元素(float不为None)
    3.绝对定位元素(position取值为absoulte或fixed)
    4.display为inline-block,table-cell, table-caption,flex,inline-flex之一
    5.overflow部位visible的元素。

  • 作用:
    1.可以包含浮动元素
    2.不被浮动的元素覆盖
    3.组织父子元素的margin折叠

24.水平居中思路:

  • 常规居中一个inline元素,为父元素设置text-align: center
  • 如果为block元素,为元素设置宽度,设置margin为auto
  • 如果为浮动元素。1.为元素设置宽度。2.postion:relative。3.浮动方向偏移量设置为50%。4.浮动方向的margin为元素的宽度的一半*-1。
  • 如果为绝对定位。1.为元素设置宽度。2.left: 0;right: 0,margin: 0 auto.

25.各种可视区域的宽度

  • offsetWidth/offsetHeight: content + padding + border
  • clientWidth/clientHeight: content + paddding
  • scrollWidth/scrollHeight: content + padding + 溢出的尺寸

26.回顾继承,以及各种比较

function shape() {}
function rect() {}
//方法一
rect.prototype = new shape()
//方法二
rect.prototype = shape.prototype
//方法三
rect.prototype = Object.create(shape.prototype)
rect.prototype.area = function() {
  do something
}
  • 方法一

    1.优点: 正确设置了原型链的继承。父类实例的属性得到继承,原型链查找效率提高,也能为一些属性提供合理的默认的值。

    2.缺点: 父类实例属性为引用类型,不恰当的修改则会导致子类被修改。创建父类实例作为子类的原型时,可能无法确定构造函数需要而合理的参数,这样提供的参数继承给子类无意义,当子类需要这而参数应该在构造函数中初始化和设置。

    3.总结:继承应该是继承方法而不是属性,为子类设置父类实例属性应该是通过在子类构造函数调用父类构造函数进行初始化。

  • 方法二

    1.优点: 正确的设置了原型链的继承

    2.缺点: 父类的构造函数原型于子类相同,修改子类原型会修改父类。

  • 方法三

    1.优点: 正确设置原型链且避免了法2的缺点。

    2.缺点: es5注意兼容性。

    3.牵扯到部分object.create(),说一下区别吧,object.create创建了一个空对象,但是空对象的构造原型指向obj,访问c.a相当于obj.a。重新设置b.a那么优先级更高。

    var obj = {a: 1}
    b = obj
    c = Object.create(obj),这里c是一个空对象。
    console.log(b.a) //1
    console.log(c.a) //1
    b.a = 1111
    console.log(obj.a) //1111
    console.log(c.a) //1
    c.a = 2
    console.log(c.a)

4.改进: 所有方法都应该在子类的构造函数中调用父类函数实现实例的初始化

 function rect() {
  shape.call(this)
 }

用新创建的对象代替紫烈的默认原型,设置rect.prototype.constructor = rect,保证一致性。

27.Promise.all()和Promise.race()

  • Promise.all(),参数是一个数组,每个数组里面是Promise对象,当数组所有的promise对象都fullfilled,然后返回每个pormise的resolve的数据。
  • Promise.race(),参数也是一个数组,每个数组是Promise对象,当有一个Promise对象resolve了,然后便执行,返回第一个resolve的数据。

28.symbol:

  • 主要防止了键名的冲突,两个symbol不相等,包括==和===。
  • symbol不可以和其他类型的值进行运算。但是可以转换为布尔值(默认true)。
  • 调用toString方法,返回symbol对象。
  • 无法被for in. for of 比那里,也不会被Object.keys()返回。

29.js加载的defer和async

  • 首先无defer和async,浏览器会加载并执行指定的脚本,意思是不等待后续载入的文档元素,读到就加载执行。
  • async:加载和渲染文档的并行执行(js文件和渲染)。
  • defer:加载文档和下载js文件并行,执行需要等到渲染完毕。

30.vue双向绑定的原理

  • vue采用数据监听和发布者-订阅模式。通过Object.defineProperty()来劫持各个属性的setter和getter,当数据变动时候发布消息给订阅者,触发相应回调。
  • 1.需要observer递归的遍历对象,包括对象的对象,给对象的某个值赋值或者改变,触发setter,那么监听到了数据的变化。
  • 2.complie解析各个v-的操作指令,将模板的变量替换成数据,初始化页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦有数据变动,接收通知,更新视图。
  • 3.watcher是observer和complie的桥梁,首先自身实例化向属性订阅器dep中添加自身,其次自身有一个update方法,在属性变动时,dep.notice()通知,调用自身的update方法,触发complie的回调。

31.vue的生命周期

  • 主要8个阶段,创建前/后,载入前/后,更新前/后,销毁前/后。
  • 创建前后: 在beforeCreated阶段,vue实例的挂载元素el还没有。
  • 载入前后: 在beforeMount阶段,vue实例的$el和data都初始化了,但还是挂载之前的虚拟dom的节点。data的message还未替换。在mounted阶段,vue实例挂载完成,data.message成功渲染。
  • data变化后,触发beforeupdate和update方法。
  • 执行destory方法后,对data的改变不会再触发周期函数,说明此时vue实例已经解除了事件监听和dom的绑定,但是dom的结构依然存在。

32.前端路由,由于spa页面,前端路由的核心,改变视图的同时不会向后端发出请求。

  • 1.hash: 即地址栏url的#符号,例如http://www.abc.com/#/hello,hash的值为#hello,特点在于: hash虽然会出现在url中,但是不会被包括在http请求中,对后端无影响,因此改变hash不会重新加载页面。
  • 2.history: 利用了html5的pushState()repalceState()方法,这两个方法应用于与浏览器的历史记录栈,在当前的back,forward,go的基础上,提供了对历史记录进行修改的功能。只是对他们执行修改时,改变了当前的url,但是浏览器不会立即向后端发送请求。

33.生命周期题目:

  • 什么是vue的生命周期: vue实例从创建到销毁的过程就是生命周期。也就是从开始创建,初始化数据,编译模板,挂载dom,渲染更新,渲染卸载。
  • vue生命周期的作用是什么?生命周期有多个事件的钩子,在控制整个vue实例的过程中形成更好的逻辑。
  • 第一次加载页面触发那几个钩子?beforeCreate,created,beforeMount,mount。dom渲染在mount部分完成。
  • 简述生命周期具体使用的场景
    • beforeCreate:此处增加loading时间,在加载实例时候触发。
    • created: 初始化完成的事件写在这里,如果在这里结束loading事件,异步请求也适合在这里调用。
    • mounted: 挂载元素,获取dom节点update,如果对数据统一处理,这里写函数
    • beforeDestory: 可以做确认停止事件确认框nextTick,更新数据后确认操作dom

34.为什么监听对数组不起作用:

  • Object.defineProperty() 的问题主要有三个:
    • 不能监听数组的变化
    • 必须遍历对象的每个属性
    • 必须深层遍历嵌套的对象

35.实现数组的flat和带深度的flat

lat flat = function(arr) {
  let res = [];
  let flatMap = function(arr) {
    arr.map((item, index, array) => {
      if (Object.prototype.toString.call(item).slice(8,-1) === 'Array') {
        flatMap(item)
      } else {
        res.push(item)
      }
    })
  }
  flatMap(arr);
  return res
}

//带有深度的flat实现
let flat = function(arr, depth) {
  let res = []
  let depthArg = depth || 1
  let depthNum = 0
  let flatMap = function(arr) {
    arr.map((item, index, array) => {
      if (Object.prototype.toString.call(item).slice(8,-1) === 'Array') {
        if (depthNum < depthArg) {
          depthNum ++;
          flatMap(item)
        } else {
          res.push(item)
        }
      } else {
        res.push(item)
        if (index === arr.length - 1) {
          depthNum = 0
        }
      }
    })
  }
  flatMap(arr)
  return res
}

35.js实现大数相加

function addBigNum(a, b) {
  var res = ""
  var tmp = 0
  var a = a.toString().split("")
  var b = b.toString().split("")
  while (a.length || b.length || tmp) {
    tmp += ~~(a.pop()) + ~~(b.pop())
    res = (tmp % 10) + res
    tmp = tmp > 9
  }
  return res
}

36.求两个数组的交集,并集,差集。

 let a = new Set([1,2,3,4])
 let b = new Set([3,4,5,6])
 //...a会把集合a转化为数组
 //并集
 let union = new Set([...a, ...b])
 //交集
 let intersection = new Set([...a].filter(x=>b.has(x)))
 //差集
 let diff = new Set([...a].filter(x => !b.has(x)))

 Array.from(set)
  1. css的background:包括了border以内的部分,不含margin。

  2. 滑动窗口协议:维持发送方接收方缓冲区,缓冲区是用来解决网络数据之间不可靠的问题。比如丢包,重复包,出错,乱序。

    • 如何保证次序:发一个确认一个,吞吐量非常低。
    • 如何提高吞吐量: 可以连续发几个包一起确认吗?
    • 最优解: 我们能否发送了第一个包第二个包,收到第一个确认再发第三个包,而不是等待第二个包确认再发第三个包

39.前端模块化的应用: 模块化的开发可以提高代码的复用率,方便代码进行管理,通常就是一个文件就是一个模块,有各自的作用域,只向外暴露特定的变量和函数。目前流行的js模块化规范有common.js,amd,cmd,es6的模块系统。

  • common.js

    //例如定义一个math.js模块
    var basicNum = 0
    function add(a,b) {
     return a+b
    }
    module.exports = {
     add: add,
     basicNum: basicNum
    }
    
    //引用自定义的模块,参数包含路径可省略.js
    var math = require('./math')
    math.add(2,5)

    common.js用同步的方式加载模块。在浏览器端,合理的方式用异步加载。

  • es6 module

    es6在语言曾的标准上实现了模块功能。模块主要由两个命令构成,export和import。export规定模块对外接口,import输出其他模块的功能。es6的模块不是对象,import命令命令会被js引擎静态解析,编译时引入模块代码,而不是在代码运行时加载。

    //定义模块math.js
    var basicNum = 0;
    var add = function(a,b) {
     return a + b
    }
    export {basicNum, add}
    
    //引用
    import {basicNum, add} from './math'
    function test(ele) {
     ele.textContent = add(99, busicNum)
    }

40.手写实现promise.all()

function promiseAll(promises) {
  return new Promise((resolve, reject) => {
    if (!Array.isArray(promises)) {
      return reject(new TypeError("arguments must be an array"))
    }
    var resolveCounter = 0
    var promiseNum = promises.length
    var resolveValues = new Array(promiseNum).fill(null)
    for (var i=0; i<promiseNum; i++) {
      (function(i) {
        Promise.resolve(promises[i].then((value) => {
          resolveCounter ++
          resolveValues[i] = value
          if (resolveCounter == promiseNum) {
            return resolve(resolveValues)
          }
        }),function(res) {
          return reject(reason)
        })
      })(i)
    }
  })
}

41.为什么vue的data返回的函数呢?

  • 比如说我们有个component,可以看出两个实例引用同一个对象,修改一个属性的时候,另一个实例也会跟着修改。
    var component = function() {}
    mycomponent.prototype.data = {
     a: 1,
     b: 2
    }
    //例如上面是一个虚拟组件的构造,真实的组件构造器
    var component1 = new Component()
    var component2 = new Component()
    component1.data.a === component2.data.a //true
    component.data.b = 5;
    component.data.b //5
    处理方法
    var mycomponent = function() {
    this.data = this.data()
    }
    mycomponent.prototype.data = function() {
    return {
     a: 1,
     b: 2
    }
    }
    这样子每个属性都是独立的,不会再相互影响了。

42.块级元素和行内元素的区别。

  • 块级元素
    • 总是在新行上开始
    • 高度,行高以及外边距,内边距均是可以控制
    • 宽度默认为容器的100%,除非设定一个宽度
    • 可以容纳其他块元素和内联元素
  • 内联元素的特点:
    • 和其他的元素都在同一行
    • 高度,行高以及外边距,内边距都不可以改变
    • 肯度就是文字或者图片的宽度
    • 内联元素只能容纳文本或者其他内联元素

43.浏览器的怪异模式和混标准模式,混杂模式严格模式

  • 所谓标准模式,浏览器按照w3c标准解析执行代码。
  • 怪异模式: 使用浏览器自己的方法解析执行代码,由于不同浏览器的解析执行方法不一样,称为怪异模式。
  • 严格模式: 以浏览器支持的最高标准运行
  • 混杂模式: 页面以宽松的向后兼容的方式显示。模拟老式浏览器的行为防止站点无法工作,doctype不存在或者不正确会使文档以混杂模式呈现。

44.伪元素和伪类

  • 伪类用于已有的元素处于某种状态,为其添加对应的样式。状态根据用户的行为而动态变化。例如悬停:hover,虽然和普通的css想死,但是处于dom树无法描述的状态下才可以为元素添加样式,称为伪类
  • 伪元素是创建一些不在文档树中的元素,并为其添加样式。通过:before赖在一个元素前添加文本,并为这些文本添加样式,虽然用户可以看到文本,但是文本不在文档树中。
  • css3规定,伪类用:,而伪元素使用::

45.session_id过期的的设置?sessin_id是dict的形式,如果过多咋办?session的共享

  • session_id过期时间在服务器端设置。
  • 通过分发,ip_hash,或者专门做个中间件去读取sessiond.

46.promise,reject?后面还可以执行吗

  • promise 的 then 方法里面可以继续返回一个新的 promise 对象, 下一个 then 方法的参数是上一个 promise 对象的 resolve 参数
  • catch 方法的参数是其之前某个 promise 对象的 rejecte 参数
  • 一旦某个 then 方法里面的 promise 状态改变为了 rejected,则promise 方法连会跳过后面的 then 直接执行 catch,catch 方法里面依旧可以返回一个新的 promise 对象

47.spa的首屏优化

  • 缩小js文件体积。
  • 加载顺序,首屏渲染速度除了受js文件大小的影响,还有html的解析实际,为了提早完成document的加载,最好吧没有用到的其他文件的下载往后推或者异步下载(不要阻止document的加载),为其添加defer属性。
  • 服务器的304和max-age
  • dns预解析
  • 图片懒加载

48.白屏问题

  • 白屏的根本原因是浏览器在渲染的时候没有请求或者请求时间过长造成
  • 浏览器对于图片和css,在加载时会冰箱架在,把js放在顶部也有可能造成白屏。
  • 白屏的原因主要是css的样式被置于底部,新窗口打开,刷新的时候,会出现白屏。或者是import引入的文件会等到页面加载完毕再被加载,可能出现白屏。

49.pwa(progressive web app)

  • pwa中文名叫做渐进式网页应用。pwa讲web和app个各个优势融合在一起:渐进式,可相应,可离线,实现类似app的交互,及时更新,安全,可以被搜搜引擎检索,可推送,可安装,可连接。
  • native app的缺陷
    • 由于天生封闭的基因,内容无法被索引。
    • 用户的大部分时间被app占据,对站点来说,应用分发的性价比也越来越不划算
    • 使用之前需要下载较大的安装包
  • web虽然有开放的基因,但有时页面卡顿,体验不好
    • 离线时用户无法使用
    • 无法接受推送消息
    • 移动端没有一级入口
  • pwa的特点
    • 渐进式: 适用于选用热河浏览器的所有用户,因为他是以渐进式增强作为核心宗旨来开发。
    • 自适应: 适用于任何机型。
    • 连接无关性: 能够借助服务工作线程在离线或在低质量的网络状况下工作。
    • 类似用用: 由于在app shell模型基础上进行开发,因此具有应用风格的交互和导航。
    • 持续更新: 在服务工作线程更新进程的作用下时刻保持最新状态。
    • 安全: 通过https请求。
    • 可发现: w3c清单和服务工作线程主页作用域能够让搜索引擎找到他们,从而将其识别为应用。
    • 可再互动: 通过推送通知之类的功能简化了再互动。
    • 可安装:用户可免去使用应用商店的麻烦。
    • 可链接: 通过网址轻松分享,无需发杂的安装。

50.mainifest的特点:<html lang="en" manifest="index.manifest">

  • 离线liulan: 用户可以再离线状态下浏览网页内容

  • 更快的速度: 因为数据被存储在本地,所以速度快

  • 减轻服务器的负载: 浏览器只会下载服务器上发生改变的资源。

  • mainfets文件构造:基本格式分为3段 ***,network,fallback,其中network和fallback为可选项

    • ***(必须): 标识出哪些文件需要缓存,可以为绝对路径或者相对路径.
      a.css
      http://a.com/a.css
    • network(可选):这一部分是绕过缓存直接读取文件。
      NETWORK:
      login.asp //login.asp永远不会被缓存,且离线不可用

    • //代表所有文件都需要互联网连接
      ```
    • fallback:指定了一个后背页面,当资源无法访问时候,浏览器会使用该页面
      FALLBACK:
      /html5/ /404.html //当无法建立连接,使用404代替/html5目录中的所有文件
  • 如何更新缓存?

    • 更新manifest文件。
    • 通过js操作(window.applicationCache.update())
    • 清除浏览器缓存。
      • 注意事项
      • 不同的浏览器对缓存容量限制或许不同,某些为5m
      • 对于manifest文件,内部列举的某一个文件不可下载,整个更新过程将失败,网页将使用老的缓存,
      • manifes的html要和manifest的文件同源
      • 其他页面如果没有设置manifest属性,请求的资源如果也在缓存中也从缓存中访问。
      • 当manifest文件发生改变,资源请求本身也会触发更新。

51.单点登录:

  • 单点登录: 一个账号多个系统同时登录登出。这里的多系统就是指每个系统有自己的域名。
  • 实现单点登录:
    • 共享session: 相比单系统登录,sso需要一个独立的认证中心,只有认证中心可以接受用户的用户名密码。其他系统不提供登录入口,只接受认证中心提供的授权。间接授权通过令牌实现。sso认证中心验证用户的用户名密码没问题,创建授权令牌,在接下来的跳转过程中,授权令牌作为参数发送给各个子系统,子系统拿到令牌得到了授权,创建了局部回话。局部回话等的方式和单系统同。
    • 共享cookie: (淘汰)首先保证一级域名一致,设置其domain为主域名。缺陷亦明显,首先主域名统一,其次,应用群各系统使用的技术(至少web服务器)相同,不然cookie的key值不同无法维持会话。
    52.tcp握手挥手详细

53.http2首部压缩

54.session_id的共享详细,中间件如何做?

  • 需要一个sso授权中心,所有的session登录入口都有sso统一授权
  • 先访问a.com,第一次访问重定向至sso,无token,那么返回a.com的登录界面
  • a登录,那么重定向至sso,验证账号密码没问题,生成token返回a网站,带有token
  • 登录b,先重定向至sso,返现带有token,那么有效,需登录b直接操作。
  • sso是一个全局回话,每个站点为一个据不回话,全局回话存在,局部回话不一定存在,局部回话存在,全局回话一定存在。
  • 注销。在一个子系统注销,所有子系统回话都会注销。根据用户与系统建立的回话向sso发起注销,令牌有效,销毁全局回话,同时取出所有用此令牌的地址,sso向所有的注册系统发起注销请求,销毁据不回话。

55.document.querySelectAll("*")

56.http的请求具体。

57.https详细。

1.客户端发送https请求。
2.服务端的配置,要有一套自己的数字证书,可以自己制作,也可以向组织申请,区别就是自己颁发的证书需要客户端验证通过,才可以继续访问,而是用受信任的公司申请证书不会弹出提示页面。这套证书是一对公钥和私钥。
3.传送证书,就是传送公钥,包含了敏感信息,证书的颁发机构,过期时间。
4.客户端解析证书,这部分工作由客户端的ssl来完成,首先验证公钥是否有效,比如颁发机构,过期时间。如果异常,弹出警告,告知证书有问题。如果没问题,生成一个随机值,证书对随机值进行加密。
5.传送加密信息,这部分传送的是证书加密的随机值,以后客户端就可以通过这个随机值来进行加密解密
6.服务端解密信息,服务端利用私钥解密,得到了客户端传递的随机值,内容由该随机值进行对称加密。将信息和私钥通过随机值加密。

58.tcp和udp区别

  • TCP是面向连接的,udp是无连接的即发送数据前不需要先建立链接。
  • TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保证可靠交付。并且因为tcp可靠,面向连接,不会丢失数据因此适合大数据量的交换。
  • TCP是面向字节流,UDP面向报文,并且网络出现拥塞不会使得发送速率降低(因此会出现丢包,对实时的应用比如IP电话和视频会议等)。
  • TCP只能是1对1的,UDP支持1对1,1对多。
  • TCP的首部较大为20字节,而UDP只有8字节。
  • TCP是面向连接的可靠性传输,而UDP是不可靠的。

59.js一个题目

['1','2','3'].map(parseInt()) // [1, NaN, NaN]
map有三个参数,item,index, array
parseint两个参数,item,和进制
相当于['1','2','3'].map(function(item, index, array) {
  return parseInt(item, index)  
})

60.webworker的作用,就是为js创造多线程的环境,允许主线程创建wordker线程,将一些任务分配给后者运行。在主线程运行同时,worker进程也在后台运行,二者互不干扰,等到worker完成计算任务,再把结果返回给主线程。

  • 同源限制:分配各worker线程运行的脚本文件,必须与主线程脚本文件同源。

  • dom限制: worker线程所在的全局对象,与主线程不一样,无法读取主线程所在网页的dom对象,也无法使用document,window,parent这些对象。但是worker线程可以问navaigator和location对象。

  • 通信联系: worker线程和主线程不在同一个上下文环境,他们无法直接通信,必须通过消息完成。

  • 脚本限制: worker线程不能执行alert()方法和confirm()犯法,但可以使用xmlhttprequest发出ajax请求。

  • 文件限制: worker线程无法读取本地文件,即无法打开本机file://

  • 基本用法(主线程):

    • 主线程采用new命令 var worker = new Worker('worker.js')
    • 主线程调用worker.postMessage(),向worker发送消息。
    • 主线程通过worker.onmessage指定监听函数,接受子线程发回来的消息。
  • 基本用法(worker线程):

    • worker线程内部需要一个监听函数,监听message事件。self表示子线程自身。
      self.addEventListener('message' , function(e)  {
      self.postMessage("you said" + e.data)
      })

61.实现String.trim()方法:

String.prototype.trim = function() {
  return this.replace(/(^\s*)|(\s*$)/g, '')
}

62.跨域

  • jsonp: 单纯的get一些数据,局限性大,使用script的src属性来实现跨域。
  • nginx反向***: 利用nginx的proxy_pass,会把所有的请求***到那个域名。
  • cors:
    • Access-Control-Allow-Origin: foo.example //子域乃至整个域名或所有域名是否允许访问。
    • Access-Control-Allow-Methods: POST,GET,HEADER,允许哪些行为方法。
    • Access-Control-Allow-Headers: X-PINGOTHER,CONTENT-TYPE//允许的头部字段
    • Access-Control-Max-Age: 86000//expire time
  • 跨域信息,你如cookie,使用nginx的proxy_pass,先拦截,在重写,后反带。

63.promise.finally实现

Promise.prototype.finally = function(callback) {
  let p = this.constructor
  p.then(
    value => p.resolve(callback.then(() => value)),
    reason => p.resolve(callback.then(() => {throw new Error(reson)}))
    )
}

64.http的请求报文:请求行,请求头,请求体。

  • 请求行: 访问的方法+协议+访问的url
  • 请求头: 比如accept,content-type,user-agent这类键值对
  • 请求提:post的表单的内容

65.注意var a = b = 0 相当于 b = 0, var a = b,b成了全局变量。应该var a,b, a=b=0这样子

66.css哪些元素可以给子元素继承

  • 可继承的: font-size, font-weight, line-height, color, cursor
  • 不可继承: 一般会改变盒子模型的不会被继承,display,margin,border,padding,height等
  • 行内元素: input, sapn, a, img, display:inline
  • 会级元素: p,div,header,footer,aside,article,ul,display:block
  • 空元素: br ,hr

67.js的dom操作

<ul>
  <li>111</li>
  <li>222</li>
  <li>333</li>
  <li>444</li>
</ul>

移除333,并添加3.5
var ulcontent = document.querySelector('ul')
var licontent = ulcontent.getElementsByTanName("li")
child_3 = licontent[2]
ulcontent.remove(child_3)
var child_4 = ulconten[3]
var newchild = document.createElement('li')
newchild.innerHTML = 3.5
newchild.setAttribute('class', 'mm')
newchild.style.fontSize = '20px'
ulcontent.insertBefore(newchild, child_4)

//节点后面插入
function inserAfter(newElement, targetElement) {
  var parent = targetElement.parentNode;
  if (parent.lastChild === targetElement) {
    parent.appendChild(newElement)
  } else  {
    parent.insertBefore(newElement, targetElemnt.nextSibling)
  }

}

68.实现一个bind

function.prototype.emulatebind = function(context) {
  var self= this
  return function() {
    return self.apply(context)
  }
}

69.vuex:是转为vue.js开发的状态管理模式。它采用集中式的存储管理应用所有的组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。

  • 当遇到多个组件共享状态时,单项数据流的简洁性很容易被破坏。

    • 多个视图依赖于同一状态。传统法对于多层嵌套的组件将会非常繁琐,并且对于兄弟组件的状态传递无能为力。
    • 来自不同视图的行为需要变更同一状态。常采用父子组件直接引用或者通过事件变更和同步状态的多分拷贝。脆弱,代码无法维护。
  • vuex的使用:

    • state

      //注入到全局组件
      const app = new Vue({
       el: '#app',
       store,
       component: {Counter},
       template:`
         <div class="app">
           <dounter></counter>
         </div>
       `  
      })
      //在根实例中注册store选项,该store会注入到跟组件的所有子组件中,
      //通过this.$store访问
      const Counter = {
       template: `<div> {{count}}</div>`,
       computed: {
         count() {
           return this.$store.state.count
         }
       }
      }
  • Getter:例如我们需要从store的state中拿出一些属性进行去重,如果多个组件用到此属性,要么复制这个函数,要么抽取一个共享函数导入。不理想。vuex允许我们在store中定义geter(可理解为store的计算属性),getter的值会根据依赖被缓存起来,只有值发生了改变次啊会被重新计算。

    const store = new Vuex.Store({
     state: {
       todos: [
         {id: 1, text: '...', done: true},
         {id: 2, text: '...', done: false}
       ]
     },
     getters: {
       doneTodos: state => {
         return state.todos.filter(todo => todo.done)
       }
     }
    })
  • mutation:mutation中的store状态是响应式的,当变更状态,监视状态的组件也会自动更新。

    • 注意事项:最好提前子啊store初始化好所需要的属性。
    • 当需要在对象上添加新的属性,你应该Vue.set(obj, 'newProp', 123)
  • action:类似于mutation,不同

    • action提交的是mutation,而不是直接变更状态

    • action可以包含任意的异步操作

      const store = new Vuex.Store({
       state: {
         count: 0
       },
       mutations: {
         increment(state) {
           state.count++
         }
       },
       actions: {
         increment(context) {
           context.commit('increment')
         }
       }
      })
    • 分发action,柚木mutation分发是同步的(在根组件注册,子组件this.$store.state.count调用)

      actions: {
       incrementAsync({commit}) {
         setTimeout(() => {
           commit('increment')
           },1000)
       }
      }
    • 由于使用单一状态树,应用状态很大时,store会很复杂,分割

      const moduleA = {
       state: { ... },
       mutations: { ... },
       actions: { ... },
       getters: { ... }
      }
      
      const moduleB = {
       state: { ... },
       mutations: { ... },
       actions: { ... }
      }
      
      const store = new Vuex.Store({
       modules: {
         a: moduleA,
         b: moduleB
       }
      })
      store.state.a // -> moduleA 的状态
      store.state.b // -> moduleB 的状态

70.vue异步执行dom的更新

  • 只要观察到数据的变化,Vue将开启一个队列,并缓冲在同一事件循环中发生的所有数据改变。
  • 如果同一个watcher被多次触发,只会被推入队列中一次。这在缓冲是去除重复数据对于避免不必要的计算和dom操作非常重要。
  • 然后,在下一个时间循环的tick中,vue刷新队列,并执行(已经去重)工作,vue在内不会尝试对异步队列使用原声的Promise.then和MessageChannel,如果环境不支持,采用setTimteout(fn,0)代替。
  • 为了在数据变化之后等待vue更新dom,可以子啊数据变化后使用vue.nextTick(callback)这样回调在dom更新完毕便会调用。

71.vue,虚拟dom的算法的理解。

  • 使用js对象来表示dom树的结构,然后用这个树来构建一个真的dom树,插入到文档中。
  • 当状态变更时,重新构造一个新的对象树,然后新树和旧树比较,记录两棵树的差异。
  • 把2中的差异应用到1的dom树中,视图更新。
  • 深度优先遍历,每遍历到一个节点就把该节点和新的树进行对比。有差异的话记录到一个对象中。

72.svg和canvas的区别

  • svg绘制的每一个图形的元素都是独立的dom节点,能够方便的绑定时间或者用来修改,而canvas输出的是一整幅画布。
  • svg输出的是矢量图,后期可以修改参数来自由缩放大小,不会失真。而canvas输出标量画布,放啊会失真。

73.prototype是函数才有的属性,proto是每个对象的属性。

74.http2的首部压缩,关于图片的加载多路复用,1.二进制传输2.多路复用3.header压缩4.服务端推送。

  • 在http1中我们使用文本形式传输header,在header携带cookie的情况下,可能每次都要重复传输几百到几千的字节。为了减少消耗提升性能。http2采取了首部压缩。
  • http在客户端和服务端使用首部表来跟踪和存储之前发送的键值对。对于相同的数据,不再通过每次请求和响应发送。
  • 首部表在http2的链接存续期内始终UC你在,有客户端和服务器端渐进更新
  • 每个新的首部键值要么追加到表的末尾,要么替换表的值。

75.https详细:

  • 客户端先向服务器发出加密通信的请求,称为clientHello阶段,这一步客户端主要向服务端提供以下信息。
    • 支持的协议版本,如TLS1.0版。
    • 一个客户端生成的随机数,稍后用于生成对话秘钥。
    • 支持的加密方法,例如rsa公钥加密。
    • 支持的压缩方法。
  • 服务器回应(severHello):服务器收到客户端请求后,向客户端发出回应,叫做serverHello请求。
    • 确认加密通信的协议的版本,如果浏览器和服务器的版本不一致,服务器关闭加密通信。
    • 一个服务端生成的随机数,稍后用于生成对话秘钥。
    • 确认加密方法,例如rsa公钥加密。
    • 服务器证书。
  • 客户端回应
    • 客户端收到服务器回应后,首先验证服务器证书,如果证书不是可信机构颁布,或者证书的域名与实际域名不一致,或者过期,都会向访问者弹出警告,让其选择是否继续通信。如果没问题,客户端会从证书取出服务器的公钥,然后向服务端发送三个信息。
    • 1.一个随机数,该随机数用于服务器公钥加密,防止被窃听。
    • 2.编码改变通知,表示随后的信息都将用双方商定的加密方法和秘钥发送。
    • 3.客户端握手结束通知,表示客户端握手阶段已经结束。这一项同时也是前面发送的所有内容的hash值,听来供服务器校验。
  • 服务器的最后回应:服务端收到客户端的第三个随机数pre-master key之后,计算本次会话所用的会话秘钥。然后向客户端发送下面信息。
    • 编码改变通知,表示随后的信息都僵硬双方商定的加密方法和秘钥发送。
    • 服务器握手结束通知,表示服务器握手阶段已经结束,这一行也是前面发送的所有内容的hash值,供客户端校验。

76.e.currentTarget为绑定事件的元素,e.target为真正触发事件的元素。对于事件监听,一般使用e.target.nodeName.toUpperCase() === 'LI'进行判断。

77.cdn:内容分发网络

  • 最简单的CDN网络由一个DNS服务器和几台缓存服务器组成。
  • 当用户点击网站页面上的内容URL,经过本地DNS系统解析,DNS系统会最终将域名的解析权交给CNAME指向的CDN专用DNS服务器。
  • CDN的DNS服务器将CDN的全局负载均衡设备IP地址返回用户。用户向CDN的全局负载均衡设备发起内容URL访问请求。CDN全局负载均衡设备根据用户IP地址,以及用户请求的内容URL,选择一台用户所属区域的区域负载均衡设备,告诉用户向这台设备发起请求。区域负载均衡设备会为用户选择一台合适的缓存服务器提供服务,选择的依据包括:根据用户IP地址,判断哪一台服务器距用户最近;根据用户所请求的URL中携带的内容名称,判断哪一台服务器上有用户所需内容;查询各个服务器当前的负载情况,判断哪一台服务器尚有服务能力。基于以上这些条件的综合分析之后,区域负载均衡设备会向全局负载均衡设备返回一台缓存服务器的IP地址。
  • 全局负载均衡设备把服务器的IP地址返回给用户。用户向缓存服务器发起请求,缓存服务器响应用户请求,将用户所需内容传送到用户终端。如果这台缓存服务器上并没有用户想要的内容,而区域均衡设备依然将它分配给了用户,那么这台服务器就要向它的上一级缓存服务器请求内容,直至追溯到网站的源服务器将内容拉到本地。

78.es6的类

  • 默认严格模式:

    • 严格模式的优点

      • 消除js语法的不合理,不严谨,减少怪异之处
      • 消除代码的不安全的地方
      • 提高编译器效率,增加运行速度
      • 为未来版本的js做好铺垫。
    • 全局变量必须显式的声明 v=1报错,var v = 1

    • 禁止this指向全局对象,严格模式下,this为undeined

    • 禁用with,创建eval作用域

    • 正常模式,对于对象的只读属性如果赋值,默认失败。严格模式下,会报错

    • 对象的键值名不可以重复,函数不可以有重名的参数。

    • 不允许在代码内部写一个函数。

  • 不存在变量提升

    new Foo() //reference error
    class Foo(){}
  • name属性

  • 静态方法:

    class Foo{
     static classMethod() {
       return 'hello'
     }
    }
    Foo.classMethod(); //hello
    var foo = new Foo();
    foo.classMethod();//TypeError: foo.classMethod is not a function
    
    //但是如果静态方法包含this关键字,这个this指向的是类而不是实例。
    class Foo {
     static bar() {
       this.baz() //这里的this指向的foo类,而不是foo的实例,等同调用了Foo.baz()
       //除此外可以看见静态放啊和非静态方法重名。
     }
     static baz() {
       console.log('hello')
     }
     baz() {
       console.log('world')
     }
    }
  • 静态属性: 静态属性指的是class本身的属性,即class.propName,而非定义在实例对象上的属性。

    calss Foo {
    
    }
    Foo.prop = 1;
    Foo.prop //1

79.es6的继承

  • class可以通过extends方法实现继承,比起es5的修改原型链的方法清晰非那根便。

    class Point {
    
    }
    class ColorPoint extends Point {
    
    }
    //上面定义一个ColorPoint类,该类通过extends关键字,
    继承了Point所有的属性和方法
    class Point {
      constructor(x, y) {
        this.x = x;
        this.y = y;
      }
    }
    class ColorPoint extends Point {
      constructor(x, y, color) {
        super(x, y) //调用父类的constructor,柔则this不能用
        this.color = color
      }
    }
var a = function() {
  return new Promise((resolve, reject) => {
    reject(e)
    })
}
b = a().then().catch(e) {
  console.log(e)
  return new Promise((resolve, reject) => {
    resolve(res)
    })
}

71.line-height: 150%是根据父元素的字体大小计算出行高,并且子元素依然沿用这个计算后的行高。而1.5是根据元素自己的字体大小*1.5来计算行高,1.5em同150%.

72.parseInt(3, 2), NaN,第二个参数如果不是0一定要大于第一个参数,否则为NaN,但是注意要在2-36之间

parseInt(3, 2) // NaN
parseInt(3, 3) // NaN
parseInt(3,4)  // 3

73.linek和@import

  • link引入css,在页面引入加载,@import页面完成加载。
  • line属于xhtml标签,无兼容性问题,@import属于css标签,低版本浏览器不支持。
  • link支持用js控制dom改变样式,@import不支持。

74.vue中key的作用

  • 当使用v-for正在更新已经渲染过的元素列表,默认采用就地复用的策略,如果数据项的顺序被改变,vue将不会移动dom元素来匹配数据项的顺序,而是简单的复用每个元素,并且确保他在特定的索引下显示已经被渲染过的元素,key的主要作用是为了高效的更新虚拟dom。
  • 使用key,会基于key的变化重新排列元素顺序,并且会移除key不存在的元素。

75.a标签的四种状态

  • link(默认): 正常状态
  • hover: 鼠标放上去的时候(但不点击)
  • active: 点击的时候(鼠标还未松开)
  • visited: 点击之后的样式

76.前端优化:

  • 减少请求数量:合并资源,图片处理: 使用雪碧图,base64格式嵌入到html代码中
  • 减少重定向: 当页面发生重定向,就会延迟好着整个html文档的传输,在html代码到达之前页面中不会呈现任何东西,也没有任何组件会被下载,降低了用户体验。
  • 使用缓存: 使用***-control或者expires
  • 比便使用空的src和href,a标签的空的href,会重定向到当前的页面地址。
  • form设置空的method,会提交表单到当前地址。
  • 资源压缩: gzip
  • 优化网络连接: 使用cdn
  • 减少重绘和回流,避免使用css表达式,元素适当设置min-height和min-width,避免动态再入触发回流。给图片设置尺寸。

77.js优化
78.vue的nexttick
79.手写call,apply,bind

1.call
Function.prototype.mycall = function(context) {
  context.fn = this;
  let args = [..arguments].slice(1);
  let result = context.fn(...args);
  delete context.fn;
  return result
}
2.apply
Function.prototype.myapply = function(context) {
  context.fn = this;
  let args = [...arguments].slice(1);
  let result = context.fn(args);
  delete context.fn;
  return result;
}
3.bind
Function.prototype.mybind = function(context) {
  let self = this;
  let args = [...arguments].slice(1)
  return function() {
    return self.apply(context, args)
  }
}
#笔试题目##前端工程师#
全部评论
顺便给俺自己求个offer
点赞 回复 分享
发布于 2019-09-04 11:57
感谢,祝楼主早日拿offer
点赞 回复 分享
发布于 2019-09-04 14:28
厉害了,感谢分享
点赞 回复 分享
发布于 2019-09-04 15:41
forEach不一定改变原数组吧,如果不是在原数组上操作就不会
点赞 回复 分享
发布于 2019-09-04 20:49
点赞 回复 分享
发布于 2019-09-05 17:17
小小更新一下。老早了,
点赞 回复 分享
发布于 2019-11-14 17:43

相关推荐

码农索隆:我寻思你这么激动,拿到offer了呢
点赞 评论 收藏
分享
黑皮白袜臭脚体育生:春节刚过就开卷吗?哈基馆,你这家伙......
点赞 评论 收藏
分享
评论
25
118
分享

创作者周榜

更多
正在热议
更多
牛客网
牛客企业服务