2021前端提前批笔面试信息汇总

Shopee

笔试(24选择+1算法)

  1. css创建新的合成层

  2. 正则(3道选择)

  3. Number.Max_Safe_Integer === Math.pow(2,53)-1
    安全(Safe)在本文中的提到的意思是指能够准确地表示整数和正确地比较整数。比如

    Math.pow(2,64)=== Math.pow(2,64)+1 //true
    

    因为2的64次方大于最大安全值,所以无法正确比较

  4. CSS3选择器 :nth-child(n) 选择器匹配属于其父元素的第 N 个子元素,不论元素的类型。

  5. Substring和slice的用法
    console.log(‘fucku_letherman’.slice(2,-2));//cku_letherm
    console.log(‘fucku_letherman’.substring(2,-2));//fu

    1. substring()

    substring(start, stop)原则上参数不能为负数,若强行传递负数,在执行时会被当成0处理

    另外,如果参数 start 与 stop 相等,那么该方法返回的就是一个空串(即长度为 0 的字符串)。如果 start 比 stop 大,那么该方法在提取子串之前会先交换这两个参数

    1. substr()

    substr(start, length)参数 start 如果是负数,那么该参数声明从字符串的尾部开始算起的位置。也就是说,-1 指字符串中最后一个字符,-2 指倒数第二个字符,以此类推;

    参数 length 原则上也不该为负数,若强行传递负数,会被当成0处理,那么该方法返回的就是一个空串(即长度为 0 的字符串)。、

    1. slice(start,end)都可以是负数 start的下标一定要在end下标左侧,否则返回空
  6. x=[0,1,2,3] x.lengh= 2 x[1]+x[2] = ?
    首先:x的长度可以改变,x.length=2改变后 x=[0,1]
    那么:x[2] = undefined
    而:undefined + 1 = NaN + 1 = NaN

  7. max-width、min-width、width

.maxwidth{
    width:100px;
    min-width: 120px;
    max-width: 80px;
}

问maxwidth元素的width是多少,答案为120px
min-width>max-width时,元素最终的宽度显示min-width的值

  1. x.reverse() x本身也会反转!

技术一面 简单粗暴两道算法 挂


  1. 将类数组字符串转化为数组
    .eval()全搞定。。我服了,看完答案再看吭哧吭哧写了半个多钟头的我宛如傻逼
    《eval() 函数可计算某个字符串,并执行其中的的 JavaScript 代码。我们可以借助它来将字符串还原成数组》
const str1 = '[1,2,3]'
const str2 = '[1,2,4,"5","a"]'
const str3 = "[1,[2,22],3]"
const str4 = "[1,[2,[22,4],5],6]"
const obj1 = '{"a":1,"b":2}'
const obj2 = {
    a:1,
    b:2
}
console.log(eval(str1)); //[1,2,3]
console.log(eval(str2)); //[1,2,4,"5","a"]
console.log(eval(str3)); //[1,[2,22],3]
console.log(eval(str4)); //[1,[2,[22,4],5],6]
console.log(JSON.stringify(obj2)); //'{"a":1,"b":2}'
console.log(JSON.parse(obj1)); //obj2
console.log(JSON.parse(obj1) === obj2); //false
console.log(JSON.stringify(obj2) === obj1); //true
  1. 商品搜索路径图求宽和深

    输入如下:
    const sourceData = [
    [“bag”, “purse”],
    [“purse”, “hand purse”],
    [“bag”, “backpack”],
    [“purse”, “purse wallet”],
    [“purse wallet”, “coin wallet”],
    [“purse wallet”, “man purse”],
    [“shoe”, “nike shoe”],
    ];

    根据输入建立一个如下图的sankey diagram(类似电商的商品搜索路径图)

在这里插入图片描述
要求实现一个函数返回该图的width(最长路径)和height(路径总数)。如上图的width = 4, height = 5。

const sourceData = [
["bag", "purse"],
["purse", "hand purse"],
["bag", "backpack"],
["purse", "purse wallet"],
["purse wallet", "coin wallet"],
["purse wallet", "man purse"],
["shoe", "nike shoe"],
];




const getDimension = (data)=>{
    
    //定义树节点
    function Treenode(val) {
        this.val = val
        this.left = this.right = null
    }

    //map记录整体结构,方便树的构建
    const map = new Map()
    for(let item of data){
        if(map.has(item[0])){
            map.get(item[0]).push(item[1])
        }else{
            map.set(item[0],[item[1]])
        }
    }

    //根据map构建树
    const get_tree = (node) =>{
        if(map.has(node.val)){
            let arr = map.get(node.val)
            map.delete(node.val)
            node.left = new Treenode(arr[0])
            get_tree(node.left)
            if(arr[1])
            {
                node.right = new Treenode(arr[1])
                get_tree(node.right)
            }
        }
    }
    
    
    //回溯计算最大深度
    const back_track = (node,dep)=>{
        if(node ===null) return dep-1
        if(node.left === null) {
            console.log(depth);
            depth++
            return dep
        }
        else return Math.max(back_track(node.left,dep+1),back_track(node.right,dep+1))
    }
    

    
    let depth = 0
    let width = 0


    //循环遍历所有key
    while(map.size !== 0){
        console.log(map);
        let mapkey_arr = [...map.keys()]
        const root = new Treenode(mapkey_arr[0])
        get_tree(root)
        console.log(root);
        let current_width = back_track(root,1) 
        width = current_width>width ? current_width: width
    }


    return [width,depth]

    



}

console.log(getDimension(sourceData)) //[4,5]



同花顺

笔试(30道题,选择+简答+代码,时间略紧)


技术一面

  1. 除了try、catch外捕获异常的方法
  2. var、let、const的区别
  3. 箭头函数?sort中的回调函数的this指向
  4. 密码传输加密方法
  5. 滚轴回到顶部怎么做

京东

技术一面

  1. 原型链
Object.prototype.test = 123 
let a = ""
console.log(a.test) // 123

a.proto === String.prototype
String.proto === Function.prototype
Function.prototype.proto == Object.prototype

  1. v-computed

    if (a>0) return b+c 
    

    a不变时,该计算属性会重新渲染吗

  2. vue有双向绑定了,为什么还需要虚拟DOM

技术二面

  1. git的fetch和pull的区别
    总的来说 git pull约等于 git fetch + git merge
    git fetch会将数据拉取到本地仓库,并不会自动合并,gitpull是从远程获取最新版本并merge到本地,同时git pull会让本地苦衷master的commitID改变。

  2. git如何删除之前的commit
    • 先git log查看提交日志
    • git rebase -i HEAD~1(对最近一次commit进行rebase)或git rebase -i 9fbf10(commit id)
    • 设置操作指令drop

  3. 分别用递归和迭代实现斐波那契数列

  1. 事件循环

字节 小何健康

技术一面

  1. script异步加载的方式
  2. flex:1的含义
  3. flex-bias
  4. align-content
  5. position:sticky
  6. tcp如何保证可靠传输
  7. 算法:链表反转
var reverseList = function(head) {
    var list = head;
    var p = list;
    var q= null;
    
    while(p.next !== null) {
        q = p.next;
        p.next = q.next;
        q.next = list;
        list = q;     
    }
    return list;
};


  1. 变量提升和函数提升的先后问题
    结论:函数优先级高于变量提升,但遇到变量赋值时,会覆盖同名函数声明

    
    console.log(bar);  // f bar() { console.log(123) }
    console.log(bar()); // undefined
    var bar = 456;
    function bar() {
        console.log(123); // 123
    }
    console.log(bar); // 456
    bar = 789;
    console.log(bar); // 789
    console.log(bar()) // bar is not a function
    
    

    相当于

    // 函数提升,函数提升优先级高于变量提升
    var bar = function() {
        console.log(123)
    };
    // 变量提升,变量提升不会覆盖(同名)函数提升,只有变量再次赋值时,才会被覆盖
    var bar;
    console.log(bar);
    console.log(bar());
    // 变量赋值,覆盖同名函数字面量
    bar = 456;
    console.log(bar);
    // 再次赋值
    bar = 789
    console.log(bar);
    console.log(bar());
    
    
  2. SPA
    单页Web应用(single page web application,SPA): SPA 是一种特殊的 Web 应用,是加载单个 HTML 页面并在用户与应用程序交互时动态更新该页面的。它将所有的活动局限于一个 Web 页面中,仅在该 Web 页面初始化时加载相应的 HTML 、 JavaScript 、 CSS 。一旦页面加载完成, SPA 不会因为用户的操作而进行页面的重新加载或跳转,而是利用 JavaScript 动态的变换 HTML(采用的是 div 切换显示和隐藏),从而实现UI与用户的交互。
    特点:

    • MVVM开发模式,前后端各司其职
    • ajax:数据通过ajax同步
    • 路由:在单页面下通过变化url地址来实现多页面效果

  3. 路由模式,为什么history需要后端支持


  1. css的加载会不会阻塞页面渲染
    会,css的加载参与css规则树的构建,而render tree又需要css规则树,所以会阻塞
    例外:media query声明的css不阻塞渲染

技术二面

  1. 移动端前端适配方案
  2. rem和em区别
    • em是相对长度单位,相对于当前对象内文本的字体尺寸。如果当前对行内字体尺寸未被认为设置,则相对于浏览器的默认字体尺寸,会继承父集元素的字体大小。
      • 所有未经调整的浏览器默认:1em = 16px
      • 为简化,在body选择器中声明font-size = 62.5%,使em变为16*62.5% = 10px,方便计算
    • rem是css新增的相对单位,他与em的区别在于他相对的是html跟元素
    • 补充:rpx,微信小程序尺寸单位,规定:屏幕宽750rpx,具体机型具体值
  3. vw、vh、css倍率
  4. cache-control
  5. 防抖实现
  6. 垂直居中,水平右对齐
  7. xss攻击
  8. 前端性能优化
  9. 二分查找
  10. http 2.0

字节 新业务

技术一面

  • 微信小程序相关

    • 小程序生命周期
    • onLanuch和onLoad的区别
    • rpx

  • css相关

    • 盒子模型 W3C(标准)和 IE的区别:
      box-sizing:border-box开启IE计算
      默认是content-box(W3C)

    • 如何获取元素高度
      document.getElementById() or document.getElementByClassName()
      .clientHeight =》content+padding的高度
      .offsetHeight =》算上border的高度

      如果要只算content的高度 那么就需要声明
      docuement.getElementById().style.height
      但此时只能取到内联属性height
      即:

      <div  class="content-box border-style padding-style margin-style" style="height:50px">
      // "50px"
      

      如果要求不使用内联属性,则要使用
      getComputedStyle(document.getElementsById().height
      此时就是css经渲染计算之后的结果,可以得到纯content的高度

    • flex:1的意思
      flex:1是flex:1 1 0的简写(实际上是 flex:1 1 任意数字+任意长度单位)
      依次为——
      flex-grow:1默认为0,存在剩余空间也不放大
      flex-shrink:1默认为1,空间不够时缩小
      flex-basis:给上面两个属性分配多余空间前,计算项目是否有多余空间,默认为auto,即项目本身大小

      • flex-basis详细解释:

        flex-basis 指定了 flex 元素在主轴方向上的初始大小,如果不使用 box-sizing 改变盒模型的话,那么这个属性就决定了 flex 元素的内容盒(content-box)的尺寸。

        首先,flex-item的宽度由自身尺寸 、flex-basis、flex-grow/flex-shrink 共同决定
        其次,不做声明时,flex-basis的默认值是auto,完全根据自身尺寸渲染,自身尺寸渲染优先级如下:
        min-width >= max-width >width >content size
        而在声明时,flex-basis的优先级大于width,同时设置两者则width不起作用;
        只设置width时会生效,是因为basis尺寸按照自身尺寸来算,自身尺寸又取决于width。两者的区别体现在当内容超过限定宽度时是否会超出边界,flex-basis的设置会按最小宽度限时,但width不会,它会让字符溢出。
        综上可得出结论:

          width:100px + flex-basis:auto => 元素自身100px
          content + flex-basis:100px => max(content,flex-bais) =>元素自身大于等于100px
        
    • BFC?如何变成BFC
      Block Formatting Context 块级格式上下文,独立渲染区域,处于BFC内部的元素与外部元素定位互不影响。
      触发条件:
      - float不为none
      - overflow 不为visible
      - display: table-cell、table-caption、inline-block、flex, inline-flex 块容器
      - position 不为relative或static 中的任一个
      - 根元素


    • margin塌陷现象

      1. 垂直并列,以两盒最大外边距为准
      2. 嵌套关系,父级元素塌陷
        父子都设置了同方向的margin,如子:margin-top:20px,父:margin-top:50px,两个属性取最大值,显示为父元素的margin,即父元素距离上边的元素,子元素紧贴父元素;此时只给子元素设置margin-top:50px也是同样的效果。



    • 下方html中sec元素的高度为?

     <style>
        html,*{
          padding: 0;margin: 0;
        }
        #sec{
          background: #f00;
        }
        .child{
          height: 100px;
          margin-top: 10px;
          background: yellow;
        }
      </style>
    </head>
    <body>
      <section id="sec">
        <article class="child">
        </article>
      </section>
    </body>
    

    sec元素高度为100px,父子嵌套发生了margin塌陷,如果要实现父元素110px,则要求父元素为bfc
    如:

      border: 1px solid transparent;
      padding: 10px;
      overflow:hidden;
      position: fixed;
      display: flex;
      display:table;
      /* 以上任一即可,总之就是让父元素变成bfc */
    
  • js相关

    • 如何判断基本类型和引用类型

      1. typeof
        number、string、undefined、boolean、function、symbol都可以直接判断出来
      2. 区分对象和数组
        (1) isArray (2).length (3).contructor() (4).tostring()
    • 引用类型深拷贝(对象中有函数的情况如何)
      最简单的api:JSON.parse(JSON.stringify())
      但它无法解决三种情况:

      • 循环引用
      • 无法拷贝特殊对象,诸如RegExp,Date,Set,Map
      • 无法拷贝函数

      针对以上情况的解决办法:

      • 创建一个Map。记录下已经拷贝过的对象,如果说已经拷贝过,那直接返回它行了。
      • 针对不同类型,做不同的特殊处理。核心:
        const ctor = target.constructor
        newobj = new ctor()
        即重新构造该结构
      • 函数分箭头函数和普通函数,箭头函数不是任何类的实例,每次调用都是不一样的引用,普通函数都是Function的实例,所以分情况处理

      最终版代码:

      //获得对象类型
      const getType = obj => Object.prototype.toString.call(obj)
      
      //判断是否为非空对象
      const isObject = target => (typeof target === 'object' || typeof target === 'function') && target !==null
      if(map.get(obj)){
          return obj
      }
      
      // 需要额外处理的结构
      const canTraverse = {
          '[object Map]': true,
          '[object Set]': true,
          '[object Array]': true,
          '[object Object]': true,
          '[object Arguments]': true,
          };
      
      // 全类型变量对应变量
      const mapTag = '[object Map]';
      const setTag = '[object Set]';
      const boolTag = '[object Boolean]';
      const numberTag = '[object Number]';
      const stringTag = '[object String]';
      const symbolTag = '[object Symbol]';
      const dateTag = '[object Date]';
      const errorTag = '[object Error]';
      const regexpTag = '[object RegExp]';
      const funcTag = '[object Function]';
      
      // RegExp的处理
      const handleRegExp = (target) =>{
      const {source , flags} = target
      return new target.constuctor(source,flags)
      }
      
          // 函数的处理
      const handleFunc = (func) => {
          //箭头函数直接返回,每个引用都是新的地址
          if(!func.prototype) return func
          const bodyReg = /(?<={)(.|\n)+(?=})/
          const paramsReg = /(?<=\().+(?=\))/
          const functionString = func.toString()
          const param = paramsReg.exec(functionString)
          const body = bodyReg.exec(functionString)
          if(!body) return null
          if(param){
              const paramArr = param[0].split(',');
              return new Function(...paramArr,body[0])
          }else{
              return new Function(body[0])
          }
      }
      //无法遍历的变量处理
      const handleNotTraverse = (target,tag) =>{
          //取它的构造函数
          const Ctor = target.constuctor
          switch(tag) {
              case boolTag:
                  return new Object(Boolean.prototype.valueOf.call(target));
              case numberTag:
                  return new Object(Number.prototype.valueOf.call(target));
              case stringTag:
                  return new Object(String.prototype.valueOf.call(target));
              case symbolTag:
                  return new Object(Symbol.prototype.valueOf.call(target));
              case errorTag: 
              case dateTag:
                  return new Ctor(target);
              case regexpTag:
                  return handleRegExp(target);
              case funcTag:
              return handleFunc(target);
          default:
              return new Ctor(target);
          }
      }
      
      
      const deepClone = (obj , map = new WeakMap())=>{
          //若不是引用类型,直接return
          if(!isObject(obj)) return obj
          //取出具体类型 【object xxxx】
          let type = getType(obj)
          let newobj 
      
          //处理非循环对象
          if (!canTraverse[type]) {
              return handleNotTraverse(obj,type)
          }else{
              let ctor = obj.constuctor
              newobj = new ctor()
          }
      if(map.get(obj)){
          return obj
      }
      map.set(obj,true)
      //处理map
      if(type === mapTag){
          target.forEach((item,key)=>{
              newobj.set(deepClone(key,map),deepClone(item,map))
          })
      }
      
      //处理set
      if(type === setTag){
          target.forEach(item=>{
              newobj.add(deepClone(item,map))
          })
      }
      
      //处理数组和对象
      for(let item in obj){
          if(typeof item ==='object'){
              map.set(obj,true)
              newobj[item] = deepClone(item)
          }else{
              newobj[item] = obj[item]
          }
      }
      return newobj
      }
      
      

    补充:WeakMap类,与Map类似,但WeakMap
    1. 只接受对象作为key
    2. key所用对象都是弱引用,只要对象的其他引用被删除,垃圾回收机制就会释放该对象占用的内存,从而避免内存泄漏。
    3. 没有size属性
    4. 没clear()方法
    5. 不能遍历


  • es6相关

    • 执行顺序题
    const list = [1, 2, 3]
    const square = num => {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve(num * num)
        }, 1000)
      })
    }
    
    function run() {
      list.forEach(async x=> {
    
    	console.log(x)
    
        const res = await square(x)
        console.log(res)
      })
    }
    run()
    

    结果:先输出123,1s后输出149
    延伸:如何在不修改square的情况下,每过1秒输出一个数字

    	async function run() {
        for(let x of list){
            console.log(await square(x));
        }
    }
    run()
    

    这里主要考虑forEach和for循环的差别,forEach是对每项执行同一个回调函数,而for循环则是顺序执行,遇到await会暂停后边的遍历,如:

    list = [1,2,3]
    const run1 = () =>{
        list.forEach(async(i)=>{
            await new Promise(res=>{
                setTimeout(()=>{
                    res(1)
                },1000)
            })
            console.log(i);
        })
    }
    
    const run2 = async() =>{
        for(let i = 0 ; i<list.length ; i++){
            console.log(list[i]);
            await new Promise(res=>{
                setTimeout(()=>{
                    res()
                },1000)
            })
        }
    }
    
    run1() // 1秒后一起输出123
    run2() // 1 。。。1s后输出 2 。。。1s后输出 3
    

+ 网络相关 + xss攻击和csrf攻击 + tcp如何保证可靠传输 + tcp重传机制 + 协商缓存和强缓存 + cookies如何只让请求携带 而不让浏览器获取 + 算法 + 顺时针便利二维数组 顺时针遍历二维数组 [[1,2,3], [4,5,6], [7,8,9]] 1 2 3 6 9 8 7 4 5 + 二叉树层序遍历
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值