前端面试题分享

674 阅读4分钟

富途笔试

// 代码填空
function showmoney(){
      return this.money; //此处为填空内容
    }
    var personA = new Object();
    var personB = new Object();
    personA.money = 100;
    personB.money = 150;
    personA.showmoney = showmoney;
    personB.showmoney = showmoney;
    console.log(personA.showmoney());
    console.log(personB.showmoney());
 // 代码填空
    function obj(name){
      if(name){
        return {name: name}
      }
    }
    obj.prototype.name = "name2";
    var a = obj("name1");
    var b = new obj;
    console.log(a.name);
    console.log(b.name);
var obj = {
    age: 18,
    foo: function(func){
        func();
        arguments[0]();
    }
};
var age = 10;
function temp(){
    console.log(this.age);
}
obj.foo(temp);
// 这段CSS代码实现的效果是什么?(三角形)
width: 0;
  height: 0;
  border-top: 40px solid transparent;
  border-left: 40px solid transparent;
  border-right: 40px solid transparent;
  border-bottom: 40px solid #ff0000;
new Promise((resolve, reject) => {
    reject();
}).then(function(){
    console.log('success');
}, function(){
    console.log('fail');
}).catch(() => {
    console.log('catch');
});
// fail

BIGO笔试题

// 求字符串的序列号。 'A' -> 1, 'B' -> 2, ……,'AA' -> 27.
let fn = (str) => {
            let res = 0;
            for(let i = 0; i < str.length; i++){
                res += (str.charCodeAt(i) - 'A'.charCodeAt(0)+ 1) * Math.pow(26, str.length - i - 1);
            }
            return res;
        }
 // 反过来,给出序列,求字符串
 function fn(number){
            let start = 'A'.charCodeAt(0);
            let res = '';
            let shang = 0;
            let mod = 0;
            while(Math.floor(number / 26) > 0 || (number % 26 !== 0)){
                shang = Math.floor(number / 26);
                mod = number % 26;
                // console.log(mod);
                if(mod === 0){
                    res = 'Z' + res;
                    shang--;
                }else {
                    res = String.fromCharCode(mod+start-1) + res;
                }
                number = shang;
            }
            return res;
        }

判断是否是数组的方法有哪些?

// 目前能想到的是下面五种

let arr = [1,2,3];
console.log(Object.prototype.toString.call(arr).indexOf('Array') !== -1);
console.log(arr instanceof Array);
console.log(Array.isArray(arr));
console.log(Array.prototype.isPrototypeOf(arr));
console.log(arr.constructor.toString().indexOf('Array') !== -1);

腾讯笔试题

//压缩算法
//小Q想要给他的朋友发送一个神秘字符串,但是他发现字符串的过于长了,于是小Q发明了一种压
缩算法对字符串中重复的部分进行了压缩,对于字符串中连续的m个相同字符串S将会压缩为
[m|S](m为一个整数且1<=m<=100),例如字符串ABCABCABC将会被压缩为[3|ABC],现在小Q的
同学收到了小Q发送过来的字符串,你能帮助他进行解压缩么。
//我是利用栈来解这道题。
let fn = (s) => {
     let stack = '';
     let index = 0;
     while(index < s.length){
       if(s[index] !== ']'){
           stack += s[index];
           index++;
       }else{
        let temp = '';
        while(stack[stack.length-1] !== '['){
            temp = stack[stack.length-1]+temp;
            stack = stack.substring(0,stack.length-1);
        }
        stack = stack.substring(0,stack.length-1);
        let num = parseInt(temp);
        let str = '';
        let index1 = temp.indexOf('|');
        temp = temp.substring(index1+1);
        for(let i = 0; i < num; i++){
            str += temp;
        }
        stack += str;
        index++;
       }
     }
      return stack;
}

腾讯笔试题

//小Q在周末的时候和他的小伙伴来到大城市逛街,一条步行街上有很多高楼,共有n座高楼排成一行。
小Q从第一栋一直走到了最后一栋,小Q从来都没有见到这么多的楼,所以他想知道他在每栋楼的位
置处能看到多少栋楼呢?(当前面的楼的高度大于等于后面的楼时,后面的楼将被挡住)
let fn = (arr,n) => {
            let s = [];
            let ans = [];
            for(let i = 0; i < n; i++){
                ans[i] = 1;
                ans[i] += s.length;
                while(s.length && s[s.length-1]<=arr[i]){
                    s.pop();
                }
                s.push(arr[i]);
            }
            s = [];
            for(let i = n-1; i >= 0; i--){
                ans[i] += s.length;
                while(s.length && s[s.length-1]<=arr[i]){
                    s.pop();
                }
                s.push(arr[i]);
            }
            ans = ans.join(' ');
            return ans;
        }

CVTE二面

访问对象属性时,方括号和点的区别:主要是方括号可以用变量来遍历属性,如果属性名用的是关键字或者保留字,或者带空格,也可以用方括号来遍历。

HTTP请求的方法中,OPTIONS、TRACE、CONNECT是HTTP1.1才支持的。
//乱序输出一个数组
function random(arr){
    let len = arr.length;
    //let arr1 = [];
    for(let i = 0; i < arr.length; i++){
      let randomNum = Math.floor(Math.random()*len);
      //arr1.push(arr[randomNum]);
      [arr[randomNum],arr[i]] = [arr[i],arr[randomNum]];
     }
     return arr;
  }
//将一个数组顺时针旋转九十度打印出来
//思路一
var rotate = function(matrix) {
    for(let i = 0; i < matrix.length; i++){
        for(let j = i + 1; j < matrix.length; j++){
            [matrix[i][j], matrix[j][i]] = [matrix[j][i], matrix[i][j]]
        }
        matrix[i].reverse();
    }
    return matrix;
};
//思路二
var rotate = function(matrix) {
    let XLen = matrix.length;
    for(let i = 0; i < XLen; i++){
      for(let j = XLen-1; j >= 0; j--){
        matrix[i].push(matrix[j][i])
      }
    }
    for(let i = 0; i < XLen; i++){
        matrix[i].splice(0,XLen)
    }
};

拼多多一面面试题

console.log('start')
 setTimeout(function(){
   console.log('time')
 })
 Promise.resolve().then(
   console.log(1)
 )
 console.log('end')
//考察Symbol.for()和Symbol的区别。
let a = Symbol.for(1) === Symbol.for(1) 
   let b = Symbol(1) === Symbol(1) 
   console.log(a);
   console.log(b);

提取URL中的参数

 let str = 'www.taobaao?a=1&b=2';
    function f(str){
      let str1 = str.slice(str.indexOf('?')+1);
      let arr = str1.split('&');
      let obj = {};
      for(let i = 0; i < arr.length; i++){
        let args = arr[i].split('=');
        obj[args[0]] = args[1]
      }
      return obj
    }

shopee一面面试题

var A = function() {};
A.prototype.n = 1;
var b = new A();
A.prototype = {
  n: 2,
  m: 3
}
var c = new A();

console.log(b.n);
console.log(b.m);

console.log(c.n);
console.log(c.m);

XSS攻击防御中CSP是谁来设置的。

是浏览器设置的,浏览器发出命令,服务器执行

CSP开启方式有两种。 juejin.cn/post/684490…

  • 设置 HTTP Header 中的 Content-Security-Policy
  • 设置 meta 标签的方式

shopee二面

1. 实现一个观察者模式 Observer 类。$on 注册监听事件,$emit 广播事件,$off 取消事件监听,注意 $off 可以取消监听指定的 handler 或所有指定事件。(隔了好几个月,终于写出一版啦)

const bus = new Observer();

const handler = function(name) { console.log(`hello ${name}`); };

bus.$on('customEvent', handler);

bus.$on('customEvent', handler.bind(this));

bus.$emit('customEvent', 'shopee');

bus.$off('customEvent', handler);

bus.$emit('customEvent', 'team');

// output:

// hello shopee

// hello shopee

// hello team
class Observer{
      constructor(){
        this.topics = {}
      }
      $on(topic, func){
        if(!this.topics.hasOwnProperty(topic)){
          this.topics[topic] = [];
        }
        this.topics[topic].push(func);
      }
      $emit(topic, info){
        if(!this.topics.hasOwnProperty(topic)){return;}
        this.topics[topic].forEach(func => {
          func(info);
        })
      }
      $off(topic, func){
        let funcIndex = -1;
        this.topics[topic].forEach((item, index) => {
          if(item === func){
            funcIndex = index;
          }
        })
        if(funcIndex > -1){
           this.topics[topic].splice(funcIndex,1);
        }
      }
    };
    const handler = function(name){
      console.log(`hello, ${name}`);
    }
    const bus = new Observer();
    bus.$on('cunstomEvent', handler);
    bus.$on('cunstomEvent', handler.bind(this));
    bus.$emit('cunstomEvent', 'shopee');
    bus.$off('cunstomEvent', handler);
    bus.$emit('cunstomEvent', 'team');
2. 实现 JS 函数式编程中的 compose 函数(可接收多个 function 用于组合,执行顺序从右到左,前函数的执行结果作为后函数的入参)
function compose(){
}
const add2 = num => num+2;
const fn1 = compose(add2);
console.log(fn1(3)); //执行后,打印 5

const sum = (a,b) => a+b;
const fn2 = compose(add2, sum);
console.log(fn2(3,2)); //执行后,打印 7

function compose(){
  let funcs = Array.from(arguments);
    return funcs.reduce(function(a,b){
      return function(...args){
        return a(b(...args))
      }
    })
}

网易互联网一面

const shape = {
  radius: 10,
  diameter() {
    return this;
  },
  perimeter: () => {return this}
};
const temp = shape.diameter;

console.log(shape.perimeter());
console.log(shape.diameter());
console.log(temp());

百度一二三面

JSONP返回的数据格式是什么?

JSONP的本质是执行一段脚本。在前端定义好函数方法,后端服务器会调用这个方法,并传入参数,然后通过script或者img的src引入后端创建的脚本来加载这个方法。所以返回的其实是一个函数。

jpg和png有什么区别?

图片格式分三类。

  • 无压缩。例:BPM
  • 无损压缩。例:png
  • 有损压缩。例:jpg

具体来说:

  • gif: 无损压缩,支持透明和动画。缺点: 只能存8位颜色索引,不适用于色彩复杂,细节丰富的图片。
  • jpg: 有损的基于直接色的图片格式。适合色彩丰富,有渐变色的图片。但是jpg不适合做icon, logo。因为相比png-8和gif,在文件大小上没有优势。
  • png-8采用无损压缩,相比gif,对透明度的支持更好,同等质量下,尺寸更小。缺点:不支持动画。如果没有动画需,建议png-8替代gif。
  • png-24:无损压缩。质量堪比bpm,但尺寸比bpm小,比jpg,gif和png-8大。支持透明。支持丰富色彩但大小比jpg大得多,约是jpg的5倍。

页面之间通信

面试官提到postMessage。实现窗口间通信。

React 和Vue的区别。

  • vue支持数据双向绑定,react支持单项数据流。
  • 监听数据实现变化的原理不用。Vue 通过 getter/setter 以及一些函数的劫持,能精确知道数据变化,不需要特别的优化就能达到很好的性能,React 默认是通过比较引用的方式进行的,如果不优化(PureComponent/shouldComponentUpdate)可能导致大量不必要的VDOM的重新渲染。
  • React是在组件JS代码中,通过原生JS实现模板中的常见语法,比如插值,条件,循环等,都是通过JS语法实现的,Vue是在和组件JS代码分离的单独的模板中,通过指令来实现的,比如条件语句就需要 v-if 来实现。

美团一面

for...in, for...of, forEach的区别.

forEach不可以使用过return或者break来终止循环。

for...in循环的是可枚举对象(包括原型上的)的,for...of遍历的是不包括原型上的。

遍历数组时,for...in遍历属性名,for...of遍历属性值。for...of不能用来直接遍历对象,可以用Object.keys()或者Object.values()来遍历对象。

单冒号和双冒号的区别

单冒号表示伪类,双冒号表示伪元素

京东一面

position: sticky说一下

粘性定位是relative和fixed的混合。具体说来,在目标区域以内,sticky会让元素在页面滚动时如同在正常流中,当滚动到特定位置时,就会固定在屏幕上,如同fixed。指定top,left,right,bottom四个阈值其中之一,粘性定位才会生效。元素并不脱离文档流。

sticky的作用域:相对于离它最近的具有滚动框的父级元素的位置。

forEach和map的区别?

  • forEach没有return, map有返回值。
  • forEach改变原数组, map不改变原数组,会为返回值分配内存空间。
  • 共同点:既可遍历数组,也可遍历对象。

选择器类型及优先级

  • !important > 内联样式1000 >id选择器100>类选择器|伪类选择器10>标签选择器|伪元素选择器1>通用选择器0

如何取消事件冒泡

event.stopPropagation()或者ie下event.cancelBubble = truebtn.onclick = function(event){
    event.stopPropagation();
}

e.target 和 e.currentTarget区别?

e.target是事件触发的真正元素,e.currentTarget是注册事件处理程序的元素。

如何阻止特定事件的默认行为?

obj.onclick = function(event){
                  event.preventDefault()
              }

只有cancel属性设为true的事件,才可以使用preventDefault()来取消事件的默认行为。

不同页面的localStorage可以共享吗?

同一浏览器的相同域名和端口的不同页面之间可以共享相同的localStorage(同域名下共享),但是不同页面之间无法共享sessionStorage的信息。

localStorage的值类型为string,也遵循同源策略。

字节跳动一面

//考察解构赋值
 var a = x => x;
var b = x => {return x;};
var c = x => ({x});

console.log(a(1));
console.log(b(1));
console.log(c(1));
//注意空对象是两个不同的对象,set结构认为 NaN === NaN
let set = new Set([1,1,2,2,{},{},NaN,NaN]);
   console.log(set.size);
//是同时打出还是每隔一秒打一次?输出是什么?如何修改为每秒打印一次?
for (var i = 0; i < 3; i++) {
  setTimeout(() => {
    console.log(i);
  }, 5000);
}
var a = function () { this.b =3; }
var c = new a();
a.prototype.b = 9;
var b = 7;
a();

console.log(b)
console.log(c.b)
window.name = 'ByteDance';

function Foo () {
  this.name = 'bar';
}

Foo.prototype.getName = function(){
  console.log(this);
  return this.name + 1;
}

let foo = new Foo();
let getName = foo.getName;

console.log(getName());  
console.log(foo.getName());   
console.log(getName.call(Foo));  
算法题
删除字符串中出现次数 >= 2 次的相邻字符
输入:"abbbaca"
输出:"ca"
解释:"abbbaca" => "aaca" => "ca"
 var removeDuplicates = function(S) {
let stack= [];
let index = 0;

while(index < S.length){
    if(stack.length === 0 || stack[stack.length-1] !== S.charAt(index)){
        stack.push(S.charAt(index));
        index++;
    }else{
      while(stack[stack.length-1] === S.charAt(index)){
        index++;
    }
    if(stack[stack.length-1] !== S.charAt(index)){
      stack.pop();
    }
    }
}
let str = stack.join('');
return str
};
console.log(removeDuplicates('abbbacaccca')) //c
//
实现一个函数: 数字格式化问题:1234567890 --> 1,234,567,890
function formatCash(num) {
    let str = num.toString();
    let newStr = '';
    for(let i = str.length-1; i >= 0; i--){
        if(i%3===0 && i !== str.length -1){
            newStr = str.charAt(i) + "," + newStr;
        }else{
            newStr = str.charAt(i) + newStr;
        }
    }
    return newStr;
}
给定一个升序整形数组[0,1,2,4,5,7,13,15,16],
找出其中连续出现的数字区间为如下:["0->2", "4->5", "7", "13", "15->16"]
function summaryRanges(arr) {
    let newArr = [];
    let start = arr[0];
    let index = 1;
    let flag = false;
    while(index < arr.length){
        if(arr[index-1]+1 !== arr[index]){
            flag = true;
        }else{
          index++;
        }
        if(flag){
               if(start === arr[index-1]){
                 newArr.push(start.toString());
                 start = arr[index];
                 index++;
                 }else{
                newArr.push(start + '->' + arr[index-1]);
                start = arr[index];
                index++;
                 }
            }
    }
    return newArr;
}
斜45度打印二维矩阵
描述信息:对于一般的m * n矩阵a,第一条45度斜边:a0,第二条45度斜边:a0, a1
………
最后一条45度斜边:am - 1
例如:
input = [[ 1, 2, 3, 4, 5],
         [ 6, 7, 8, 9, 10],
         [11, 12, 13, 14, 15]]
output = 1, 2, 6, 3, 7, 11, 4, 8, 12, 5, 9, 13, 10, 14, 15

function printdialog(arr){
    let rows = arr.length,
        cols = arr[0].length,
        res = [];
        for(let i = 0; i < cols; i++){
          let row = 0,
              col = i;
              while(row >= 0 && row < rows && col >= 0 && col < cols){
                res.push(arr[row][col]);
                row++;
                col--;
              }
        }
        for(let j = 1; j < rows; j++){
          let row = j,
              col = cols - 1;
              while(row >= 1 && row < rows && col >= 0 && col < cols){
                res.push(arr[row][col]);
                row++;
                col--;
              }
        }
        return res;
  }
请实现 DOM2JSON 一个函数,可以把一个DOM节点输出JSON的格式,例如下面的例子

function DOM2JSON(root) {
  // 请实现这个函数
}


输入:
<div>
  <span>  
    <a></a>
  </span>
  <span>
    <a></a>
    <a></a>
  </span>
</div>

输出:
{
  tag: 'DIV',
  children: [
    {
      tag: 'SPAN',
      children: [
        { tag: 'A', children: [] }
      ]
    },
    {
      tag: 'SPAN',
      children: [
        { tag: 'A', children: [] },
        { tag: 'A', children: [] }
      ]
    }
  ]
}
两人在一个圆桌上『交替』放置圆形的棋子,棋子是有无穷多个。
要求棋子不能有重叠,也不能超出圆桌。
如果有一方不能再放置棋子,认为是输了。
问题:如果是先手,要用什么策略可以保证一定能赢?
Symbol数据类型的作用

独一无二,保证不与其他变量名产生冲突。

如何判断页面加载完毕?

1.用document.onreadystatechange = dosomething来监听状态的改变 document.readyState == 'complete'

2.window.onload = function(){}

3.vue中,mounted:{ this.$nextTick(()=>{"确保Dom异步加载完毕"}) }

页面加载readtState的五个状态:

0:Uninitialized未初始化

1:Loading载入

2:Loaded载入完成

3:Interactive交互,正在解析响应内容

4:Complete完成,响应内容解析完成,可以在客户端调用了

严格模式和非严格模式有什么区别?

严格模式下编写代码,更严谨规范,更安全,提高编译效率,提高运行速度,为未来新版本的JavaScript做准备。

开启严格模式,是在脚本或者函数的顶部加上字符串"use strict".

严格模式下,不能使用保留字作为变量名。

全局上下文this不再指向window,而是指向undefined.

字节二面

HTTPS和HTTP2的区别?

HTTP2采用新的二进制格式,多路复用,头部压缩,服务端推送。

省略号的实现(单行和多行)

//单行
{
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
//多行
{
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 3;
    overflow: hidden;
}

事件捕获和冒泡有兼容性问题吗?

IE8及以下不支持事件流。

GET和POST区别。

1.从缓存角度:GET请求会被浏览器缓存,而POST请求默认不会。
2.从编码角度:GET只能进行URL编码,只能接收 ASCII 字符,而 POST 没有限制。
3.从参数角度,GET请求参数放在URL中,不安全,POST放在请求体中,更适合传输敏感信息。
4.从TCP的角度,GET 请求会把请求报文一次性发出去,而 POST 会分为两个 TCP 数据包,
首先发header 部分,如果服务器响应 100(continue), 然后发 body 部分。
(火狐浏览器除外,它的 POST 请求只发一个 TCP 包)

如果要自己实现一个JSONP跨域,需要设置哪些API?

// 实现不算难
// 需要的API: document.createElement(), document.body.appendChild(), 
             document.body.removeChild(), promise

const jsonp = ({url, params, callbackName}) => {
        const generateUrl = () => {
          let dataStr = '';
          for(let key in params){
            dataStr += `${key}=${params[key]}&`;
          }
          dataStr += `${callback}=${callbackName}`;
          return `${url}?${dataStr}`;
        }
        return new Promise((resolve, reject) => {
          let scriptElement = document.createElement('script');
          scriptElement.src = generateUrl();
          document.body.appendChild(scriptElement);
          window[callbackName] = (data) => {
            resolve(data);
            document.body.removeChild(scriptElement);
          }
        })
      }
      jsonp({
        url: 'http://localhost:3000',
        params: {
          a: 1,
          b: 2
        },
        callbackName: 'xxx'
      }).then((data) => {
        console.log(data);
      })

// JSONP跨域的缺点
// 1.不安全,如果请求的资源中有恶意代码,没办法追究。
// 2.需要提供JSONP接口
// 3.只支持GET请求
// JSONP跨域的优点
// 兼容性好,CORS跨域不支持IE低版本浏览器

哪些事件不能冒泡?

  • UI事件load, unload, resize, error
  • 焦点事件:blur, focus
  • 鼠标事件:mouseleave, mouseenter

发微信是属于TCP还是UDP?

TCP。

对元素设置margin-left,margin-top为负值,与设置margin-right,margin-bottom为负值时有何不同?

前两个是相对于自身而言。后两个是相对于其他元素而言。

京东二面

路由的导航守卫有哪些?

  • 全局前置守卫
  • 全局解析守卫
  • 全局后置钩子
  • 路由独享的守卫
  • 组件内的守卫

出现白屏的原因有哪些,怎么定位问题?

面试官讲到,先打开控制台,查看HTML,CSS部分有没有问题,再看资源有没有获取到,然后还可以检查babel转义是否正确。(大概记了下,没有记全)