面试题(11)之 大厂外包面试题


写在前面:

一年没有面试了,约了一个外包面试,去大厂,就当我去检测我这1年的成果了。

1 变量提升

var a = 1
function a() {
  return 2
}
console.info(a) // 1
console.info(typeof a) // number

2 异步

for(var i = 0; i < 3; i++) {
  setTimeout(function() {
    console.info(i)
  });
}
// 3 3 3

3 随机排序

实现一个方法,将有序的数组变为乱序

// 解法一
function getRandomArr(arr) {
  let len = arr.length
  let randomIndex = Math.floor(Math.random() * len)
  let temp
  while(len >= 0) {
    temp = arr[randomIndex]
    arr.splice(randomIndex, 1)
    arr.push(temp)
    len--
    randomIndex = Math.floor(Math.random() * len)
  }
  return arr
}
// 解法二
function getRandomArr(arr) {
  /* 每次循环时都要与第i项互换位置 */
  for (var i = 0; i < arr.length; i++) {
    var j = parseInt(Math.random() * arr.length)
    /* 将所获取的数和第i个数互换位置 */
    var temp = arr[i]
    arr[i] = arr[j]
    arr[j] = temp
  }
  return arr
}
// 解法三
function getRandomArr(arr) {
  arr.sort(() => {
    return (0.5-Math.random())
  })
  return arr
}

4 绑定DOM事件

实现一个绑定DOM事件的js函数,可兼容多种浏览器

4.1 方法一


4.2 方法二

function addEvent(ele, type, func) {
    if(ele.addEventListener()) {
        // Chrome
        ele.addEventListener(type, func)
    } else {
        // IE浏览器
        ele.attachEvent('on' + type, func)
    }
}

5 问题:减少页面首次请求加载的方式有哪些

前端优化清单(一):之首屏优化

  1. 首屏最小化

    首屏HTML尽量小,控制DOM节点数、请求数、外链数

  2. 元素优化

    优化落在首屏内的元素性能和结构,包括基础页、元素请求、图片、JS、是否调用第三方内容、层次机构等。

  3. 页面静态化

    首屏页包含了页面基础页时间(第一次请求),以屏内的元素总的DNS解析时间,建立连接时间,SSL握手时间,发出请求时间,重定向时间,内容下载时间等。

  4. 基础页优化 以静态页面的形式存放,用户相关数据依赖Ajax,比如登录信息。用户默认显示未登录状态,异步获取到用户数据后更新。

  5. 首屏广告优化 重点减少广告JS的下载次数,减少状态上报次数,避免iframe。同时处理脚本放在页面底部,修改广告的载入顺序,避免影响页面显示。

  6. 首屏按需加载 隐藏tab页,用了异步加载的方式,只有当用户正在要看这块内容的时候才去拉取。

  7. 单独合并素材 将代发布的源文件进行压缩合并,减少文件数量,授权请求最少原则。

  8. 统计代码优化 针对用户行为统计代码如(CNZZ,百度统计等),进行去除冗余,统一放到首屏后加载。

6 如何避免出现XSS漏洞

  1. 输入过滤。永远不要相信用户的输入,对用户输入的数据做一定的过滤。如输入的数据是否符合预期的格式,比如日期格式,Email格式,电话号码格式等等。这样可以初步对XSS漏洞进行防御。上面的措施只在web端做了限制,攻击者通抓包工具如Fiddler还是可以绕过前端输入的限制,修改请求注入攻击脚本。因此,后台服务器需要在接收到用户输入的数据后,对特殊危险字符进行过滤或者转义处理,然后再存储到数据库中。

  2. 输出编码。服务器端输出到浏览器的数据,可以使用系统的安全函数来进行编码或转义来防范XSS攻击。在PHP中,有htmlentities()和htmlspecialchars()两个函数可以满足安全要求。相应的JavaScript的编码方式可以使用JavascriptEncode。

  3. 安全编码。开发需尽量避免Web客户端文档重写、重定向或其他敏感操作,同时要避免使用客户端数据,这些操作需尽量在服务器端使用动态页面来实现。

  4. HttpOnly Cookie。预防XSS攻击窃取用户cookie最有效的防御手段。Web应用程序在设置cookie时,将其属性设为HttpOnly,就可以避免该网页的cookie被客户端恶意JavaScript窃取,保护用户cookie信息。

  5. WAF(Web Application Firewall),Web应用防火墙,主要的功能是防范诸如网页木马、XSS以及CSRF等常见的Web漏洞攻击。由第三方公司开发,在企业环境中深受欢迎。

7 CSS 如何实现div上下左右居中

未布局前的样式:

    .fa {
      width: 300px;
      height: 300px;
      background-color: #f5f5f5;
    }
    .son {
      width: 100px;
      height: 100px;
      background-color: #979191;
    }

  <div class="fa">
    <div class="son">div>
  div>

7.1 标准流居中

/* 前提:已知父子div的宽高 */
.fa {
    overflow: hidden; /* BFC */
}
.son {
    margin: 100px auto;
}

7.3 定位 + margin

.fa {
    position: relative;
}
.son {
    position: absolute;
    left: 50%;
    top: 50%;
    margin-left: -50px;
    margin-top: -50px;
}

7.4 flex

.fa {
    display: flex;
    justify-content: center;
    align-items: center;
}

7.5 grid

.fa {
    display: grid;
    grid-template-columns: 33.3% 33.3% 33.3%;
    grid-template-rows: 33.3% 33.3% 33.3%;
}
.son {
    /* 开始于第2条行网格线,结束于第3条行网格线 */
    grid-column: 2/3;
    /* 开始于第2条列网格线,结束于第3条列网格线 */
    grid-row: 2/3;
}

8 判断二维空间中的一个点是否在线段上

    // 实现一个函数,判断二维空间中的一个点是否在线段上
    // 思路:该点分别到这两点的距离 是否等于 这俩点距离之和
    const pointA = { x: 1, y: 4 }
    const pointB = { x: 4, y: 1 }
    let onePoint = { x: 2, y: 3 }
    let otherPoint = { x: 3, y: 1 }
    function isInLine(pointA, pointB, target) {
      let distanceA = distance(pointA, target)
      let distanceB = distance(pointB, target)
      let distanceAB = distance(pointA, pointB)
      return distanceA + distanceB === distanceAB ? 'true': 'false'
    }

    function distance(first, second) {
      let num = Math.pow((first.x - second.x), 2) + Math.pow((first.y - second.y), 2)
      return Math.round(Math.sqrt(num))
    }
    console.log(isInLine(pointA, pointB, onePoint)) // 'true'
    console.log(isInLine(pointA, pointB, otherPoint)) // 'false'

9 树形结构

当时面试官问我保存的str1存在那里,现在才知道,存在原型

有一个树形结构:

var data = {
  key1: 'str1',
  key2: {
    key3: 'str3',
    key4: 'str4',
    key5: {
      ket6: 'str6'
    }
  }
}

实现一个方法getKeys(data, str),获取字符串 str 在 data 中所有的上级节点名称,例如:

getKeys(data, 'str1') 返回 'key1'

getKeys(data, 'str3') 返回 'key2 key3'

getKeys(data, 'str6') 返回 'key2 key5 key6'

以下解法有问题,但是思路很好

解法一

var data = {
  key1: 'str1',
  key2: {
    key3: 'str3',
    key4: 'str4',
    key5: {
      key6: 'str6',
      key7: {
        key8: 'str8'
      }
    }
    // ...
  }
}

function getKeys(data, str) {
  for(let key in data) {
    if(typeof data[key] == 'string' && data[key] == str) {
      this.keyName ? this.keyName += key: this.keyName = key
      return this.keyName
    } else if(typeof data[key] == 'object') {
      // keyName += key
      // keyName += ' '
      this.keyName ? this.keyName += key: this.keyName = key
      this.keyName += ' '
      return getKeys(data[key], str)
    }
  }
}

getKeys.prototype.keyName = ''

console.info(getKeys(data, 'str8'))

解法二

function  getKeys(data,str){
  var result=[];
  function recursion(data,str){
      for(var key in data){
          if(data[key] == str){
              result.push(key);
              return result;
          }
          if(typeof data[key] == 'object'){
              result.push(key);
              return recursion(data[key],str)
          }
      }
  }
  recursion(data,str);
}

10.原型 和 类

实现一个类,语法可以是es5 / es6 / es7

调用代码可以输出:item1-1 item2-2 item3-3

调用代码如下:

var priorityQueue = new PriorityQueue();
priorityQueue.add('item1', 1);
priorityQueue.add('item3', 3);
priorityQueue.add('item2', 2);
priorityQueue.print();
priorityQueue.clear();

 答案