前言

两个月前,本以为我暑期实习的路程现已到站了,其时现已拿了同程的offer了,自己还特地写了一篇求职的文章来记载和同享其时的面经哈哈。

2023年一位大三学生的一些中大厂的面试题同享(包括干货同享) – 掘金 ()

玩了两个月之后,发现身边的人好像在陆陆续续地接到了大厂的面试以及又想到其时面同程的时分,自己之前预备的手写和算法好像还没用武之地,就也想投一投简历试一试,横竖有个保底的offer,成果怎样样不在乎了。终究真的让我意外的拿了网易的offer了哈哈

记载

快手:两次一面挂

腾讯:二面挂

蔚来:一面offer

网易:二面offer

字节: 一面挂

小红书: 二面拒(由于其时网易意向了)

得物: 一面挂(电话面的以后一概不面了,便是刷KPI)

快手

5.29一面

常见的git操作

git branch 查看本地一切分支
git status 查看当时状况
git commit 提交
git branch -a 查看一切的分支
git branch -r 查看长途一切分支
git commit -am "init" 提交而且加注释
git remote add origin git@192.168.1.119:ndshow
git push origin master 将文件给推到服务器上
git remote show origin 显现长途库 origin 里的资源
git push origin master:develop
git push origin master:hb-dev 将本地库与服务器上的库进行相关
git checkout --track origin/dev 切换到长途 dev 分支
git branch -D master develop 删去本地库 develop
git checkout -b dev 树立一个新的本地分支 dev
git merge origin/dev 将分支 dev 与当时分支进行兼并
git checkout dev 切换到本地 dev 分支
git remote show 查看长途库
git add .
git rm 文件名(包括途径) 从 git 中删去指定文件
git clone git://github.com/schacon/grit.git 从服务器大将代码给拉下来
git config --list 看一切用户
git ls-files 看现已被提交的
git rm [file name] 删去一个文件
git commit -a 提交当时 repos 的一切的改动
git add [file name] 增加一个文件到 git index
git commit -v 当你用-v 参数的时分能够看 commit 的差异
git commit -m "This is the message describing the commit" 增加 commit 信息
git commit -a -a 是代表 add,把一切的 change 加到 git index 里然后再 commit
git commit -a -v 一般提交指令
git log 看你 commit 的日志
git diff 查看没有暂存的更新
git rm a.a 移除文件(从暂存区和作业区中删去)
git rm --cached a.a 移除文件(只从暂存区中删去)
git commit -m "remove" 移除文件(从 Git 中删去)
git rm -f a.a 强行移除修正后文件(从暂存区和作业区中删去)
git diff --cached 或 $ git diff --staged 查看没有提交的更新
git stash push 将文件给 push 到一个暂时空间中
git stash pop 将文件从暂时空间 pop 下来
git rebase 是Git中用于将一个分支的修正运用到另一个分支上的指令。

当然光了解git根本操作不行,你最好还得预备解释一下什么是git,分为哪几个区

git抵触

  • 假如在长途的某一个文件内容发生修正了,而本地没有进行 pull 拉取,就会导致本地的分支落后,当修正完结之后 push 到长途的时分,就会发生抵触

处理

  1. 先将本地修正存储起来
$ git stash
  1. 暂存了本地修正之后,就能够 pull 了
$ git pull
  1. 复原暂存的内容
  $ git stash pop
  //  git stash pop
  1. 再提交并push到长途即可

根本数据类型

- 存在着7种原始值
        - boolean
        - null
        - undefined
        - number
        - string
        - Symbol
        - Bigint
        // BigInt 类型运用 n 作为后缀来表明,例如 123456789012345678901234567890n 表明一个 30 位的大整数。

类型检测办法

- typeof 是否能正确判别类型?  => 简略数据
    - 关于原始类型来说,除了``null``都能够调用typeof显现正确的类型
    ```
    typeof 1 // 'number'
    typeof '1' // 'string'
    typeof undefined // 'undefined'
    typeof true // 'boolean'
    typeof Symbol() // 'symbol'
    typeof null // object
    ```
    - 关于引证数据类型,除了``函数``之外,都会显现object
    ```
    typeof [] // 'object'
    typeof {} // 'object'
    typeof console.log // 'function'
    ```
    - 关于NaN也不行
    typeof NaN -> number
    因而采用typeof判别方针数据类型是不适宜的
    - 判别不了null的原因
        在 JavaScript 开端的完结中,JavaScript 中的值是由一个表明类型的标签和实际数据值表明的。方针的类型标签是 0。由于 null 代表的是空指针(大多数平台下值为 0x00),因而,null 的类型标签是 0typeof null 也因而回来 "object"。
- instanceof
    原理是依据原型链的查询,只需处于原型链中,判别永远为true
    > ``实例方针`` instanceof  ``结构函数``  
    ```
    const Person = function() {}
    const p1 = new Person()
    p1 instanceof Person // true
    var str1 = 'hello world'
    str1 instanceof String // false
    var str2 = new String('hello world')
    str2 instanceof String // true
    ```
    缺点:
        不能检测根本数据类型
        原型链或许被修正,导致检测成果不精确
        只需能在原型链上找到结构函数,就回来 true,所以类型或许不精确
- Object.prototype.toString.call()  => 引证类型  内置的子类 Date Regexp 
    Object.prototype.toString.call(num),  // '[object Number]'
    Object.prototype.toString.call(str),  // '[object String]'
    Object.prototype.toString.call(bool),  // '[object Boolean]'
    Object.prototype.toString.call(arr),  // '[object Array]'
    Object.prototype.toString.call(obj),  // '[object Object]'
    Object.prototype.toString.call(func),  // '[object Function]'
    Object.prototype.toString.call(und),  // '[object Undefined]'
    Object.prototype.toString.call(nul),  // '[object Null]'
    Object.prototype.toString.call(date),  // '[object Date]'
    Object.prototype.toString.call(reg),  // '[object RegExp]'
    Object.prototype.toString.call(error)  // '[object Error]'

原型链

记住这张图即可

一名前端双非学生的大厂面试之旅(腾讯,字节,快手,网易,百度)

数组常见的办法

1. 操作(增修正查)
    - 增:push  unshift  splice concat
    - 删:pop  shift  splice  slice
    - 改: splice
    - 查: indexof  includes  find
2. 排序
    - sort()
    - reverse()
3. 转换
    - join()  数组转字符串
4. 迭代
    - forEach()
    - filter
    - map
    - some
    - every

围绕增修正查的思路去答即可

介绍一下promise

// 首要能够介绍promise的发生
  Promise 是异步编程的一种新的处理方案,比以往经过回调函数和事情来处理异步操作愈加强大。
// 其次便是promise的根本运用
  Promise 是一个结构函数,咱们能够用它来生成 Promise 实例,而且该结构函数承受一个函数作为参数
// 特点
Promise的三种状况:
pending :进行中,表明 Promise 还在履行阶段,没有履行完结。
fulfilled:成功状况,表明 Promise 成功履行完结。
rejected:回绝状况,表明 Promise 履行被回绝,也便是失利。
Promise 的状况,只或许是其中一种状况,从进行中变为成功或失利状况之后,状况就固定了,不会再发生改动。

另外你这儿能够再介绍一下promsie有哪些办法

介绍一下react hook

  • React Hooks的几个常用钩子
    1. useState() 状况钩子
    2. useContext() 同享状况钩子
    3. useReducer() action钩子
    4. useEffect() 副效果钩子
    5. useCallback() 缓存了函数自身
    6. useMemo() 缓存了函数的回来值

useCallback 和 useMemo的差异

前者缓存的是函数自身,后者是缓存的函数成果

promise的办法

  • promsie的办法

    • catch办法

      catch是用于指定发生过错的回调函数。

    new Promise((resolve, reject) => {
        reject('失利');
    }).catch(error => {
        console.log(error); // 失利
    });
    
    • Promise的finally办法

    finally办法用于指定不论Promis方针终究状况怎样,都会履行的操作。

    new Promise((resolve, reject) => {
        resolve();
    }).then(res => {
        console.log('success');
    }).catch(error => {
        console.log('error');
    }).finally(() =>{
        console.log('finally');
    })
    
    • Promise的all办法

      Promise.all办法用于将多个Promise实例,包装成一个新的Promise实例。在all办法中能够传递多个Promise方针,当一切的Promise方针状况都回来fufilled,才会回来fulfilled,否则回来rejected。

    const promise1 = new Promise((resolve, reject) => {
        resolve();
    })
    onst promise2 = new Promise((resolve, reject) => {
         resolve();
    })
    const promise3 = new Promise((resolve, reject) => {
        resolve();
    })
    const promiseAll = Promise.all([promise1, promise2, promise3]).then(res => {
    console.log('all');
    })
    
    • Promise的race办法

      Promise.race办法相同是将多个Promise实例,包装成一个新的Promise实例。能够传递多个Promise方针作为参数,假如实例红有一个实例首要改动状况,那么race的状况就会跟着改动。

    const promise1 = new Promise((resolve, reject) => {
        reject();
    })
    const promise2 = new Promise((resolve, reject) => {
        resolve();
    })
    const promise3 = new Promise((resolve, reject) => {
        reject();
    })
    const promiseRace = Promise.race([promise1, promise2, promise3]).then(res => {
        console.log('race then');
    }).catch(error => {
        console.log('race catch');
    })
    
    • Promise的any办法

      要参数实例有一个变成 fulfilled 状况,包装实例就会变成 fulfilled 状况;假如一切参数实例都变成rejected状况,包装实例就会变成rejected状况。

    const p = Promise.any([p1, p2, p3]);
    
    • Promise.allSettled()

    承受多个Promise方针 数组办法传递参数,一切的Promise都敲定状况时就回来成功成果,无论成果是fulfilled还是rejected都会在then获取

手写一个promise.all

const promiseAll = (array) => {
    if (!Array.isArray(array)) {
        throw new Error('要传入数组')
    }
    return new Promise((resolve, reject) => {
        let result = [];
        let count = 0;
        array.forEach((item, index) => {
            if (item instanceof Promise) {
                item.then(res => {
                    result[index] = res
                    count++;
                    if (count == array.length) {
                        return resolve(result)
                    }
                },
                    err => reject(err))
            }
            else {
                result[index] = item
                count++;
                if (count == array.length) {
                    return resolve(result)
                }
            }
        })
    })
}
let p1 = new Promise((res, err) => {
    setTimeout(() => {
        res(100)
    }, 3000)
})
let p2 = new Promise((res, err) => {
    setTimeout(() => {
        res(200)
    }, 2000)
})
let p3 = new Promise((res, err) => {
    setTimeout(() => {
        res(300)
    }, 5000)
})
promiseAll([p1, p2, p3]).then(res => console.log(res), err => console.log(err))

有爱好的朋友能够参阅我的这篇文章

别看了,进来一同手写一个Promise(all,race)吧 – 掘金 ()

输入url到浏览器烘托的进程

八股经典中的经典,开端吟唱~

在不考虑用户输入查找关键字的状况:

  • 用户输入 url 并回车

  • 浏览器(进程)检测 url,拼装协议,构成完整的 url发送给网络进程。

  • 网络进程接纳到 url 恳求后查看本地缓存是否缓存了该恳求资源,假如有则将该资源回来给浏览器进程

  • 假如没有,网络进程向 web 服务器建议 http 恳求

    1. 进行 DNS 解析域名(url地址的别名),获取服务器 ip 地址,端口(进程的位置) 先到本地域名服务器 =》 根域名服务器 =》 尖端域名服务器

      例如,www.wikipedia.org是一个域名,和IP地址208.80.152.2相对应。DNS就像是一个主动的电话号码簿,咱们能够直接拨打wikipedia的姓名来代替电话号码(IP地址)

    2. 运用 ip 地址和服务器树立 tcp 衔接 三次握手:
      1. 树立握手恳求
      2. 服务器向客户端做应对
      3. 客户端确认自己承受到了应对
    3. 服务器呼应后,网络进程接纳呼应头和呼应信息,并解析呼应内容 四次挥手:
      1. 客户端向服务端建议断开衔接的恳求
      2. 服务端收到关闭的恳求,把未发完的数据发送完
      3. 服务端向客户端发送开释衔接恳求
      4. 客户端收到开释衔接恳求,断开衔接
  • 网络进程解析呼应流程;

    1. 查看状况码,假如是 301/302,则需求重定向,从 呼应头中的Location 主动中读取地址,从头进行第三步,假如是 200,则继续处理恳求。

    2. 200 呼应处理: 查看呼应类型 Content-Type,假如是字节省类型,则将该恳求提交给下载办理器,该导航流程结束,不再进行后续的烘托,假如是 html 则通知浏览器进程预备进行烘托。

  • 进入烘托流程

    烘托页面首要做的事:

  • 将浏览器无法直接了解和运用的HTML,转换为浏览器能够了解的结构–DOM 树。

  • 把 CSS 转换为浏览器能够了解的结构–styleSheets,并转换样式表中的特点值,使其规范化,核算出 DOM 树中每个节点的详细样式(依据继承规矩和层叠规矩)。

  • 确认DOM 元素的几许位置信息–布局树,遍历 DOM 树中的一切可见节点,加入到布局树(display:none不包括),并核算布局树节点的坐标位置。

  • 假如页面有杂乱的效果,如常见的页面翻滚,或许运用 z 轴排序等,为了愈加便利地完结这些效果,烘托引擎还需求为特定的节点生成专用的图层,并生成一棵对应的图层树(LayerTree)。

  • 图层制作,把一个图层的制作拆分红许多小的制作指令,然后再把这些指令依照次序组成一个待制作列表(联想自己画画)。

  • tiles:将图层转换成图块。

  • 光栅化:经过进程完结图块转换成位图。

  • display:浏览器进程拿到DrawQuad信息生成页面显现。

介绍变量进步以及let const var 的差异

  • 什么是变量进步

通俗来说,变量进步是指在 JavaScript 代码履行进程中,JavaScript 引擎把变量的声明部分和函数的声明部分进步到代码最初的行为。变量被进步后,会给变量设置默许值为 undefined。

  • let,const 和 var 的差异

    • var 声明的变量会挂载在 window 上,而 letconst 声明的变量不会

    • var 声明变量存在变量进步,letconst 不存在变量进步

    • letconst 声明形成块级效果域

      
      if(1){
      var a = 100;
      let b = 10;
      }
      console.log(a); // 100
      console.log(b)  // 报错:b is not defined  ===> 找不到b这个变量
      -------------------------------------------------------------
      if(1){
      var a = 100;
      const c = 1;
      }
      console.log(a); // 100
      console.log(c)  // 报错:c is not defined  ===> 找不到c这个变量
      
    • 暂时性死区 ,凡是在声明变量之前运用变量就会报错

       if (true) {
         // 死区开端
         lzp = 'lut'; //  ReferenceError
         console.log(lzp); //  ReferenceError
         // 开端声明变量,死区结束
         let lzp; 
         console.log(lzp); // undefined
         lzp = 520;
         console.log(lzp); // 520
       }
      
    • const 变量不能修正指针(栈中的内存),可是能够修正值,比方咱们界说一个方针,咱们能够修正方针里边的值。但用 const 界说简略数据类型,值不能修正。

小结

其时面试的时分,在手写promise.all这儿预备不充分翻了车,得到面试官的评价是:你基础感觉不错,可是又好像没那么好。。。。

两天后就感谢信了。。。

6.9一面

没错,换了个部分我又来了

与寒假的实习有关

  • 实习的项目

  • tailwind的优点

  • Zustand的优点

  • redux 和 Zustand的差异及其底层原理

  • 介绍一下websocket协议

    HTML5 开端供给的一种浏览器服务器进行全双工通讯的网络技术,归于运用层协议。它依据 TCP 传输协议,并复用 HTTP 的握手通道。

    websocket 使得客户端和服务器之间的数据交换变得愈加简略,答应服务端主意向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需求完结一次握手,两者之间就直接能够创立持久性的衔接,并进行双向数据传输。

  • 项目里边的懒加载怎样完结的

  • 介绍egg.js

Koa的原理

Koa是一个依据Node.js的Web结构,它的核心思维是“中间件”(middleware)。Koa的中间件机制能够将一组处理恳求和呼应的函数依照次序依次履行,每个中间件函数都能够对恳求和呼应进行处理,并能够挑选将处理成果传递给下一个中间件

这儿的说法很显然是满意面试官的,这儿还需求自己后边去看一下koa的源码

移动端适配怎样做

  • rem + 媒体查询
  • rem + flexble.js
  • vh + vw
  • 运用媒体查询来针对不同屏幕尺度设置不同的flex特点值,然后改动弹性项目的宽度和高度。
@media screen and (max-width: 768px) {
  .item {
    flex-basis: 50%; /* 宽度占有一半 */
  }
}
@media screen and (max-width: 480px) {
  .item {
    flex-basis: 100%; /* 宽度占有整个容器 */
  }
}

怎样完结判别一个元素是否在可视区中

  • 运用常见特点

    1.window.innerHeight 是浏览器可视区的高度;

    2.document.body.scrollTop || document.documentElement.scrollTop 是浏览器翻滚的过的间隔;

    3.imgs.offsetTop 是元素顶部间隔文档顶部的高度(包括翻滚条的间隔);

    4.内容到达显现区域的:img.offsetTop < window.innerHeight + document.body.scrollTop;

  • 运用api getBoundingClientRect

假如一个元素在视窗之内的话,那么它必定满意下面四个条件:

top 大于等于 0
left 大于等于 0
bottom 小于等于视窗高度
right 小于等于视窗宽度
function isInViewPort(element) {
  const viewWidth = window.innerWidth || document.documentElement.clientWidth;
  const viewHeight = window.innerHeight || document.documentElement.clientHeight;
  const {
    top,
    right,
    bottom,
    left,
  } = element.getBoundingClientRect();
  return (
    top >= 0 &&
    left >= 0 &&
    right <= viewWidth &&
    bottom <= viewHeight
  );
}

介绍一下git,以及常见的git操作

上面讲过了,略~

git抵触

git的场景:运用 git 发生抵触的条件:假如在长途的某一个文件内容发生修正了,而本地没有进行 pull 拉取,就会导致本地的分支落后,当修正完结之后 push 到长途的时分,就会发生抵触怎样处理?

也和上面相同~

git rebase

git rebase是Git版别操控系统中一个非常常用的指令,首要用于将一个分支的修正运用到另一个分支上。详细来说,它能够将一个分支上的提交记载“重演”在另一个分支上,然后使两个分支的提交记载愈加明晰、简洁。

效果域的种类

  • 块级效果域
  • 全局效果域
  • 函数效果域

口撕promise完结

能够参阅这篇文章

别看了,进来一同手写一个promise吧 – 掘金 ()

代码题1

一名前端双非学生的大厂面试之旅(腾讯,字节,快手,网易,百度)

也是经典题了,这儿面试官大约这几个问题:

  • 这儿的代码输出是什么

    6 6 6 6 6

  • 怎样改成让它打印1,2,3,4,5?

    1. let
    2. 用自履行函数
     for (var i = 1; i <= 5; i++) {
         (function (i) {
             setTimeout(function () {
                 console.log(i);
            }, i * 1000);
         })(i);
     }
    

代码题2,3

有点不记得了,大约是一题eventloop的题和一道算法题

小结

本以为这一面能够过的,由于就连我最头疼的一个算法题都OK了,没想到终究还是挂了,或许是之前一两个小的地方答太快了答错了?

腾讯

一面

介绍闭包,闭包能处理什么问题

闭包

在 js 履行引擎中,一个函数被履行完毕后该函数的履行上下文就会被垃圾收回,可是,当一个函数内部的函数回来出来履行,那么内部函数对外部函数中的变量存在引证时,引证的这些变量的调集称之为闭包,这些调集不会随外部函数的履行上下文的收回而消失。

简略来说,便是父函数嵌套子函数,子函数内部引证了父函数的变量,引证的这些变量调集称之为闭包

处理的问题(运用场景)

  • 成果缓存

    假如函数调用处理耗时,咱们能够将成果在内存中缓存起来,下次履行时,若存在内存中,则直接回来,进步履行功率。

    let cacheObj = function(){
    let cache = {} // 缓存方针
    return {
        search:function(key){
        if(key in cache){
            // 存在缓存中,直接回来
            return cache[key]
        }
        // 耗时的函数处理
        let result = dealFn(key)
        // 更新缓存成果
        cache[key] = result
        return result
        }
    }
    }
    let cacheBox = cache()
    cacheBox.search(1)
    
  • 防抖节省中

  • 模块化

参阅文章

let const 差异

const为什么让数据不行变

在JavaScript中,变量的值能够随时被修正,因而在编写大型运用程序时,假如没有对变量赋值进行约束,或许会导致代码的可保护性和可读性变差。而经过运用const关键字声明常量。

移动端适配

同上

手写flexible.js 或许说规划它有什么思路吗

  • 大致原理

    flexible.js用来处理移动端各种设备兼容问题。也便是怎样处理移动端尺度很多的问题,咱们的规划稿是固定,怎样办,假如规划稿是弹性的能够随意缩放该多好,想想,有办法了,就像本来你在一张大的纸上面了一副画,现在让你在小的纸上在画一次要怎样画,便是一切东西都等比例画小,假如要画到更大的纸上也是一个道理,等比画大,对不对。

    现在咱们把规划稿分红10等份,规划稿 A = W/10,咱们把设备可视区域也便是咱们的各种移动端设备的这个画布也分红10份,并赋值给根元素的fontSize,咱们都知道rem是依据根元素字体大小核算的,所以咱们的1rem也便是设备可视区域/10,现在规划稿上有一块区域宽B,那它是不是等比放到设备可视区域的宽度为 B/A rem。再烦琐一下,B在规划稿上占B/A份,那在设备可视区域上也要占B/A份对不对,所以宽是B/A rem

// 首要是一个当即履行函数,履行时传入的参数是window和document
(function flexible (window, document) {
  var docEl = document.documentElement  // 回来文档的root元素
  var dpr = window.devicePixelRatio || 1 // 获取设备的dpr,即当时设置下物理像素与虚拟像素的比值
  // adjust body font size 设置默许字体大小,默许的字体大小继承自body
  function setBodyFontSize () {
    if (document.body) {
      document.body.style.fontSize = (12 * dpr) + 'px'
    }
    else {
      document.addEventListener('DOMContentLoaded', setBodyFontSize)
    }
  }
  setBodyFontSize();
  // set 1rem = viewWidth / 10
  function setRemUnit () {
    var rem = docEl.clientWidth / 10
    docEl.style.fontSize = rem + 'px'
  }
  setRemUnit()
  // reset rem unit on page resize
  window.addEventListener('resize', setRemUnit)
  window.addEventListener('pageshow', function (e) {
    if (e.persisted) {
      setRemUnit()
    }
  })
  // detect 0.5px supports  检测是否支撑0.5像素,处理1px在高清屏多像素问题,需求css的合作。
  if (dpr >= 2) {
    var fakeBody = document.createElement('body')
    var testElement = document.createElement('div')
    testElement.style.border = '.5px solid transparent'
    fakeBody.appendChild(testElement)
    docEl.appendChild(fakeBody)
    if (testElement.offsetHeight === 1) {
      docEl.classList.add('hairlines')
    }
    docEl.removeChild(fakeBody)
  }
}(window, document))

什么是设备像素比

  • 逻辑(视觉)像素

    浏览器内的一切长度都是以CSS像素为单位的,CSS像素的单位是px,px是一个相对单位,相对的是物理像素(device pixel),其相对性体现在在同一个设备上或在不同设备之间每1个px所代表的物理像素是能够改变的 页面缩放比为1,css中1px = 1 物理像素

  • 物理像素

    设备像素(物理像素),望文生义,显现屏是由一个个物理像素点组成的,经过操控每个像素点的色彩,使屏幕显现出不同的图像,屏幕从工厂出来那天起,它上面的物理像素点就固定不变了,单位pt。

  • 设备像素比(dpr 描绘的是未缩放状况下,物理像素逻辑像素的初始比例关系) 以 iPhone XS 为例,当写 CSS 代码时,针关于单位 px,其宽度为 414px & 896px,也便是说当赋予一个 DIV元素宽度为 414px,这个 DIV 就会填满手机的宽度;

而假如有一把尺子来实际测量这部手机的物理像素,实际为 1242*2688 物理像素;经过核算可知,1242/414=3,也便是说,在单边上,一个逻辑像素=3个物理像素,就说这个屏幕的像素密度为 3,也便是常说的 3 倍屏。

dpr = 1 : 1,css 1px = 1物理像素
dpr = 2 : 1,css 1px = (2 * 2)个物理像素
dpr = 3: 1,css 1px = (3 * 3) 个物理像素

介绍ES6

多围绕一下es6简略聊

let const
promise
箭头函数
class类
 S6 的 class 能够看作仅仅一个语法糖,它的绝大部分功用,ES5 都能够做到,新的 class 写法仅仅让方针原型的写法愈加明晰、更像面向方针编程的语法罢了。
 - 传统办法
 ```
 function Point(x, y) {
 this.x = x;
 this.y = y;
 }
 Point.prototype.toString = function () {
 return '(' + this.x + ', ' + this.y + ')';
 };
 var p = new Point(1, 2);
 ```
 - class 办法
   ```
   class Point {
   constructor(x, y) {
       this.x = x;
       this.y = y;
   }
   toString() {
       return '(' + this.x + ', ' + this.y + ')';
   }
   }
   ```
  • 模板字符串
     在 es6 之前,假如咱们要拼接字符串,则需求像这样:
     var name = 'kris'
     var age = 24
     var info = 'My name is ' + this.name + ', I am ' + this.age
     可是在 es6 之后,咱们只需求写成以下办法
     const name = 'kris'
     const age = 24
     const info = `My name is ${name}, I am ${age}`
Set,Map 方针
  • Set是一种叫调集的数据结构,是由一堆无序的,相相关的,且不重复的内存结构组成的。

    • S6 供给了新的数据结构 Set,类似于数组,可是成员的值都是仅有的,没有重复的值。Set 自身是一个结构函数,用来生成 Set 数据结构。
    • Set 完结数组去重
    const numbers = [2,3,4,4,2,3,3,4,4,5,5,6,6,7,5,32,3,4,5]
    console.log([...new Set(numbers)])
    // [2, 3, 4, 5, 6, 7, 32]
    

    Map 是一组键值对的结构

    // 初始化Map
    let map = new Map();
    // 增加key和value值
    map.set('Amy','女')
    // 是否存在key
    map.has('Amy') // true
    // 依据key获取value
    map.get('Amy') // 女
    
翻开运算符
    数组兼并
    let ary1 = [1, 2, 3];
    let ary2 = [4, 5, 6];
    let ary3 = [...ary1,...ary2];// [1, 2, 3, 4, 5, 6];
Symbol

ES6 引进了一种新的原始数据类型 Symbol,表明仅有的值。

  • 运用场景
    1. 运用Symbol来作为方针特点名(key)
    let obj = {
      abc: 123,
      "hello": "world"
    }
    obj["abc"] // 123
    obj["hello"] // 'world'
    而现在,Symbol可相同用于方针特点的界说和拜访:
    const PROP_NAME = Symbol()
    const PROP_AGE = Symbol()
    let obj = {
    [PROP_NAME]: "一斤代码"
    }
    obj[PROP_AGE] = 18
    obj[PROP_NAME] // '一斤代码'
    obj[PROP_AGE] // 18
    
    1. 代替const
    const TYPE_AUDIO = 'AUDIO'
    const TYPE_VIDEO = 'VIDEO'
    const TYPE_IMAGE = 'IMAGE'
    
Promise

promise处理什么问题

介绍回调异步函数的发展历程

回调函数 => promise

async await

  1. 函数前面运用 async 润饰
  2. 函数内部,promise 操作运用 await 润饰
async function wait(time){
    await sleep2(time);
    fun();
}
wait(3000)

怎样运用async await完结兼并恳求

这儿没答上来

防抖节省

能够参阅我的这篇文章

✅✅包教包会——手写防抖节省 – 掘金 ()

url输入到页面烘托

上面现已提过

https的优点

能够从http的缺点回答

  • HTTP 存在的问题
    1. 或许被偷听

      1. HTTP 自身不具备加密的功用,HTTP 报文运用明文办法发送
      2. 由于互联网是由联通世界各个地方的网络设施组成,一切发送和接纳经过某些设备的数据都或许被截获或窥探。(例如大家都熟悉的抓包工具:Wireshark)
    2. 认证问题

      1. 无法确认你发送到的服务器便是真实的方针服务器(或许是服务器伪装的)
      2. 无法确认回来的客户端是否是依照真实目的接纳的客户端(或许是伪装的客户端)
      3. 无法确认正在通讯的对方是否具备拜访权限,Web 服务器上某些重要的信息,只想发给特定用户即便是无意义的恳求也会照单全收。无法阻挠海量恳求下的 DoS 进犯(Denial of Service,回绝服务进犯)。
    3. 或许被篡改

      恳求或呼应在传输途中,遭进犯者阻拦并篡改内容的进犯被称为中间人进犯

还有https的特点

  • 什么是 HTTPS

    运用层 超文本传输安全协议(英语:Hypertext Transfer Protocol Secure,缩写:HTTPS,常称为 HTTP over TLS,HTTP over SSL 或 HTTP Secure)是一种经过核算机网络进行安全通讯的传输协议。HTTPS经由HTTP进行通讯,但运用SSL/TLS来加密数据包。HTTPS 开发的首要目的,是供给对网站服务器的身份认证,保护交换数据的隐私与完整性。

  • TLS/SSL 协议

    HTTPS 协议的首要功用根本都依托于 TLS/SSL 协议,TLS/SSL 的功用完结首要依托于三类根本算法:散列函数 、对称加密和非对称加密,其运用非对称加密完结身份认证和密钥协商,对称加密算法采用协商的密钥对数据加密,依据散列函数验证信息的完整性。

    对建议 HTTP 恳求的数据进行加密操作和对接纳到 HTTP 的内容进行解密操作

  • 对称加密:对称加密是指加密和解密都运用的是相同的密钥。

    故密钥也简略被黑客破解

  • 非对称加密

    非对称加密算法有 A、B 两把密钥,假如你用 A 密钥来加密,那么只能运用 B 密钥来解密;反过来,假如你要 B 密钥来加密,那么只能用 A 密钥来解密。

    在 HTTPS 中,服务器会将其中的一个密钥经过明文的办法发送给浏览器,咱们把这个密钥称为公钥,服务器自己留下的那个密钥称为私钥。望文生义,公钥是每个人都能获取到的,而私钥只有服务器才干知道,不对任何人揭露。下图是运用非对称加密改造的 HTTPS 协议:

  • 增加数字证书

    经过对称和非对称混合办法,咱们完美地完结了数据的加密传输。不过这种办法依然存在着问题,比方我要翻开极客时刻的官网,可是黑客经过 DNS 绑架将极客时刻官网的 IP 地址替换成了黑客的 IP 地址,这样我拜访的其实是黑客的服务器了,黑客就能够在自己的服务器上完结公钥和私钥,而对浏览器来说,它彻底不知道现在拜访的是个黑客的站点。所以咱们还需求服务器向浏览器供给证明“我便是我”,那怎样证明呢?

    由第三方的权威机构进行证明 关于浏览器来说,数字证书有两个效果:一个是经过数字证书向浏览器证明服务器的身份,另一个是数字证书里边包括了服务器公钥

服务器回来的证书里边有哪些内容

这儿感觉有点硬扣数字证书里的字段啥的了

react hook介绍

前面也介绍过

有没有看过usestate源码

本来看过,但不太熟

useEffect介绍

  • useEffect函数的效果便是为了react函数组件供给副效果处理的

  • 常见的副效果

    1. 数据恳求ajax发送
    2. 手动修正dom
    3. localstorage操作
  • 依托项

    1. 增加空数组

    组件只在初次烘托时履行一次

    useEffect(() => {
        console.log('11111')
    },[])
    
    1. 增加特定依托项

    副效果函数在初次烘托时履行,在依托项发生改变时从头履行

        class Example extends React.Component {
        // 等价于
        import React, { useState, useEffect } from 'react';
        function Example() {
        const [count, setCount] = useState(0);
        useEffect(() => {
            document.title = `You clicked ${count} times`;
        },[count]);
        return (
            <div>
            <p>You clicked {count} times</p>
            <button onClick={() => setCount(count + 1)}>
                Click me
            </button>
            </div>
        );
        }
    
    1. 默许状况

      useEffect的第一个入参是一个匿名函数,在第一次烘托和后续的烘托都会被调用

      import React, { useState, useEffect } from 'react'
      function HookCounter() {
      const [count, setCount] = useState(0)
      useEffect(() => {
          document.title = `${count} times`
      })
      return (
          <div>
          <button onClick={() => {
              setCount(prevCount => prevCount + 1)
          }} >Clicked {count} times</button>
          </div>
      )
      }
      export default HookCounter
      
    • useEffect()的回来值

      useEffect()答应回来一个函数,在组件卸载时,履行该函数,清理副效应。假如不需求清理副效应,useEffect()就不必回来任何值。

      useEffect(() => {
          const subscription = props.source.subscribe();
          return () => {
              subscription.unsubscribe();
          };
      }, [props.source]);
      

为什么不能在if里边写hook

或许会导致 hooks 的履行次序发生改动,由于 React Hooks 内部是经过 hooks 的调用次序来区分是哪个 hook

useState 为例,在 react 内部,每个组件(Fiber)的 hooks 都是以链表的办法存在 memoizeState。 update 阶段,每次调用 useState,链表就会履行 next 向后移动一步。假如将 useState 写在条件判别中,假设条件判别不成立,没有履行里边的 useState 办法,会导致接下来一切的 useState 的取值出现偏移,然后导致异常发生。

为什么推崇函数式组件而不是类组件

类组件 是经过 ES6 中的 class 关键字来界说的,它继承了 React.Component 并完结了一个 render() 办法来回来需求烘托的 UI。类组件能够包括自己的状况(state)和办法(methods),并能够运用生命周期(lifecycle)钩子函数来操控组件的行为。

函数式组件是一个纯函数,它承受一些输入(props)并回来一个 React 元从来表明组件的输出。函数式组件一般比类组件更简略且更易于测试、重构和优化。在 React 16.8 版别中,Hooks API 的引进使得函数式组件也能够具有自己的状况和生命周期函数。

总的来说,假如你需求处理一些杂乱的状况或许需求运用生命周期函数,那么类组件或许更适宜;但假如你只需求依据输入(props)烘托出一个 UI,那么函数式组件或许更具有可读性和可保护性。

完结阿拉伯数字转中文 (算法题)

标题有点忘了,大约是这个意思。

二面

二面难度直接飙升

这儿我就大约同享一下面试题吧

WebSocket协议以及怎样树立衔接的

前面也有过这个题

为什么要运用WebSocket协议,轮询不行吗?什么是长轮询?

介绍一下jwt

能够参阅我的这篇文章

❤️❤️包教包会——Cookie、Session、Token、JWT – 掘金 ()

token为什么要用cookie或许localStorge存储,为什么不考虑session?

这儿我聊了一下它们直接的差异

一些常见的网络进犯

  • XSS跨站脚本进犯

    XSS 进犯是指黑客往 HTML 文件中或许 DOM 中注入歹意脚本,然后在用户浏览页面时运用注入的歹意脚本对用户施行进犯的一种手法。

    • 怎样阻挠XSS进犯

    但无论是何种类型的XSS进犯,它们都有一个共同点,那便是首要往浏览器中注入歹意脚本,然后再经过歹意脚本将用户信息发送至黑客布置的歹意服务器上。 所以要阻挠XSS进犯,咱们能够经过阻挠歹意javaScript脚本的注入和歹意音讯的发送来完结。

    1. 服务器对输入脚本进行过滤或转码
    <script>alert('你被xss进犯了')</script>
    

    过滤之后为空

    1. 充分运用csp

    虽然在服务器端履行过滤或许转码能够阻挠 XSS 进犯的发生,但彻底依托服务器端依然是不行的,咱们还需求把 CSP 等战略充分地运用起来,以下降 XSS 进犯带来的危险和后果。

    约束加载其他域下的资源文件,这样即便黑客刺进了一个 JavaScript 文件,这个 JavaScript 文件也是无法被加载的; 制止向第三方域提交数据,这样用户数据也不会外泄;制止履行内联脚本和未授权的脚本;

    还供给了上报机制,这样能够协助咱们赶快发现有哪些 XSS 进犯,以便赶快修复问题。

  • CSRF进犯

    CSRF,又称为跨站恳求假造,是指黑客引诱用户翻开黑客的网站,在黑客的网站中,运用用户的登录状况建议的跨站恳求。简略来讲,CSRF进犯便是黑客运用了用户的登录状况,并经过第三方的站点来做一些坏事

  • 怎样防止CSRF进犯

    • 充分运用好Cookie的SameSite特点

      原因:黑客会运用用户的登录状况来建议CSRF进犯,而Cookie正是浏览器和服务器之间保护登录状况的一个关键数据 一般CSRF进犯都是从第三方站点建议的,要防止CSRF进犯,咱们最好能完结从第三方站点发送恳求时制止Cookie的发送

    • 验证恳求的来历站点

      在服务器端验证恳求来历的站点。 经过HTTP恳求头中的Referer和Origin特点

    • CSRF Token

      第一步:在浏览器向服务器建议恳求时,服务器生成一个CSRF Token。CSRF Token 其实便是服务器生成的字符串,然后将该字符串植入到回来的页面中 第二步:在浏览器端假如要建议转账的恳求,那么需求带上页面中的 CSRF Token,然后服务器会验证该 Token 是否合法。假如是从第三方站点发出的恳求,那么将无法获取到 CSRF Token 的值,所以即便发出了恳求,服务器也会由于 CSRF Token 不正确而回绝恳求。

  • DNS查询进犯

    DNS查询进犯(DNS Query Flood)是向被进犯的服务器发送海量的随机生成的域名解析恳求,大部分根本就不存在,而且经过假造端口和客户端IP,防止查询恳求被ACL过滤。

    被进犯的DNS服务器在接纳到域名解析恳求后,首要会在服务器上查找是否有对应的缓存,当没有缓存而且该域名无法直接由该DNS服务器进行解析的时分,DNS服务器会向其上层DNS服务器递归查询域名信息,直到全球互联网的13台根DNS服务器。

    很多不存在的域名解析恳求,给服务器带来了很大的负载,当解析恳求超过必定量的时分,就会形成DNS服务器解析域名超时,这样进犯者便达成了进犯目的。

    处理办法: 对忽然建议很多频度较低的域名解析恳求的源 IP 地址进行带宽约束; 约束每个源 IP 地址每秒的域名解析恳求次数。

  • SQL注入进犯

    所谓SQL注入,便是经过把SQL指令刺进到Web表单提交或输入域名或页面恳求的查询字符串,终究到达欺骗服务器履行歹意的SQL指令。

    • 防备:

      • 查看数据类型

      查看输入数据的数据类型,在很大程度上能够对立SQL注入。比方用户在输入邮箱时,有必要严格依照邮箱的格局;输入时刻、日期时,有必要严格依照时刻、日期的格局,等等,都能防止用户数据形成破坏。但数据类型查看并非万能,假如需求便是需求用户提交字符串,比方一段短文,则需求依托其他的办法防范SQL注入。

      • 过滤和转义特殊字符

介绍react hook

同上

介绍一下redux以及为什么会考虑到运用redux进行状况办理

  • redux是什么?

    1. redux 是一个专门用于做状况办理的JS库(不是react插件库)
    2. 它能够用在react,angular,vue等项目中,但根本与react合作运用
    3. 效果:集中式办理react运用中多个组件同享的状况,当需求更新状况的时分,仅需求对这个办理集中处理,而不必去关怀状况是怎样分发到每一个组件内部的。
  • redux三大根本原则

    • 单一数据源

    整个运用的state被储存在一颗object tree 中,而且这个 object tree 只存在于仅有一个 store 中

    • state是只读的

    想要改动State有必要经过Action,而详细使action在state上更新生效的是reducer;

    只读的优点 这种规划能够防止在多个组件之间同享state时出现抵触或意外修正,一起也便利进行状况追踪和调试。由于Redux的作业流程非常明确,咱们能够清楚地知道每个state的来历和改变进程,然后更简略定位问题。 总之,保证state是只读的能够让Redux的状况办理愈加可靠和可保护,也能够进步开发功率和代码质量。

    • Reducer有必要是一个纯函数

    Reducer内部的履行操作有必要是无副效果的,不能对state进行直接修正,当状况发生改变时,需求回来一个全新的方针代表新的state。 保证reducer是一个纯函数,能够使得Redux的行为愈加可猜测且易于调试。假如reducer改动了传入的state或许发生了副效果,那么在调用相同的action时,就无法得到相同的成果,然后导致运用程序的行为不行猜测。

  • redux的作业进程

    Redux首要分为几个部分:dispatch,action,state。 dispatch是redux流程的第一步,在用户界面中经过履行dispatch,传入相对应的action方针参数,action是一个描绘类型的方针,紧接着履行reducer,终究全体回来一个store方针

  • 什么状况下需求运用redux?

    1. 某个组件的状况需求让其他组件能够随时拿到(同享)
    2. 一个组件需求改动另一个组件的状况(通讯)
    3. 整体原则:能不必就不必,假如不必比较吃力才考虑运用

redux中怎样建议异步恳求其原理是什么?

寄了~

react为什么能运转redux?

这怎样答

懒加载的原理

得从代码层面回答,其底层原理,而不是大约完结思路

跨域

jsonp

Jsonp(JSON with Padding) 是 json 的一种‘运用形式’,能够跨域的获取到数据。

原理:

运用<script>标签没有跨域约束的缝隙,网页能够得到从其他来历动态发生的 JSON 数据。
JSONP 恳求必定需求对方的服务器做支撑才干够。
  • 预备带有 padding 的恳求 url,得到一个字符串 dataStr

  • 结构 script

  • js 代码运用 document.createElement 创立一个 script 标签,

  • 在函数效果域中外界怎样拜访到?运用 window

缺点

  • 只能用get进行恳求,不能用post

  • 浏览器默许加载资源的办法便是get恳求

cors

怎样设置

    Http恳求头:
    Origin: http://api.bob.com (发送的源)
    反响:
    Access-Control-Allow-Origin: * (答应一切跨域)
    module.exports = async (ctx,next) => {
    // 设置呼应头
    // 答应拜访跨域服务的白名单 *答应一切
    ctx.set('Access-Control-Allow-Origin','*');
    ctx.set('Access-Control-Allow-Headers','Content-Type');
    ctx.set('Access-Control-Allow-Methods','GET,POST,OPTIONS');
    // OPTIONS 获取资源答应拜访的办法
    // 其实在正式跨域之前浏览器会依据需求建议一次预检也便是option恳求用来让服务端回来答应的办法
    await(next())
    }

缺点

杂乱恳求的时分得先预检(option)再发恳求

优点

在后端设置
websocket

Websocket是HTML5的一个持久化的协议,它完结了浏览器与服务器的全双工通讯,一起也是跨域的一种处理方案。WebSocket和HTTP都是运用层协议,都依据 TCP 协议。可是 WebSocket 是一种双向通讯协议,在树立衔接之后,WebSocket 的 server 与 client 都能主意向对方发送或接纳数据。一起,WebSocket 在树立衔接时需求凭借 HTTP 协议,衔接树立好了之后 client 与 server 之间的双向通讯就与 HTTP 无关了。

Node中间件署理(两次跨域)

完结原理:

同源战略是浏览器需求遵从的规范,而假如是服务器向服务器恳求就无需遵从同源战略。

署理服务器,需求做以下几个步骤:

承受客户端恳求 。
将恳求 转发给服务器。
拿到服务器 呼应 数据。
将 呼应 转发给客户端。
  - 前端署理
```
  "proxy":{
"/api": {
  "target": "http://172.19.5.35:9536",
  "ws": true
  },
"/apc": {
  "target": "http://179.19.5.35:9536",
  "ws": true
  }
},
```
  • 缺点

    增加了网络恳求

iframe + postMessage

这儿是运用3300端口父页面向内嵌子页面3301端口发送音讯

 //a.html
<!-- 运用iframe,src指向3301端口 -->
 <iframe src="http://127.0.0.1:3301/b.html" id="frame" onload="load()"></iframe>
 <script>
 const data = {
   name : '某车',
   like:  '前端'
 }
 const load = function(){
   //负责发布音讯
   let frame = document.getElementById('frame'); 
   const targetWindow = frame.contentWindow;//得到方针窗口的引证
   targetWindow.postMessage(data, 'http://127.0.0.1:3301'); //发送新音讯
   //也监听信息
   window.onmessage = function(event) {
     console.log(event.data)
   }
 }
 </script>

<iframe> 标签用于在 HTML 文档中嵌入另一个 HTML 文档,它能够显现来自不同网站的内容。

postMessage() 办法是 HTML5 中供给的一种跨文档通讯的API,用于在两个窗口之间传递音讯。

它接纳两个参数:第一个参数是要发送的音讯,能够是字符串、数字、方针等;第二个参数指定接纳音讯的窗口的源和方针窗口的 URL。

nginx反向署理

完结原理类似于Node中间件署理,需求你建立一个中转nginx服务器,用于转发恳求。

运用nginx反向署理完结跨域,是最简略的跨域办法。只需求修正nginx的装备即可处理跨域问题,支撑一切浏览器,支撑session,不需求修正任何代码,而且不会影响服务器性能。

完结思路:经过nginx装备一个署理服务器(域名与domain1相同,端口不同)做跳板机,反向署理拜访domain2接口,而且能够趁便修正cookie中domain信息,便利当时域cookie写入,完结跨域登录。

  • nginx是什么?

    1.nginx是一个高性能的Web服务器和反向署理服务器,也可作为电子邮件署理服务器。 2.在衔接高并发的状况下,nginx是Apache服务不错的替代品,能够支撑高达 50,000 个并发衔接数的呼应。

  • 正向署理和反向署理

    1.反向署理是指以署理服务器来承受Internet上的衔接恳求,然后将恳求转发给内部网络上的服务器,并将从服务器上得到的成果回来到Internet上恳求衔接的客户端,此刻署理服务器对外表现为一个反向署理服务器。

    2.正向署理是指用户无法拜访某网站,可是能够拜访某署理服务器,而署理服务器能够拜访该网站。于是用户经过拜访署理服务器去拜访该网站,署理服务器把呼应信息回来给用户。

  • 首要运用

    • 负载均衡

      网站服务器由多台服务器组成一个集群对外供给服务,当用户输入域名进行拜访的时分,负载均衡负责将用户恳求分发到集群中的不同服务器,然后进步并发处理能力。nginx作为拜访的一致入口,分发恳求,完结负载均衡。 负载均衡完结办法有硬件负载均衡和软件负载均衡。

    • 虚拟主机

      虚拟主机便是把一台物理服务器划分红多个“虚拟”的服务器,这样咱们的一台物理服务器就能够当做多个服务器来运用,然后能够装备多个网站。 Nginx下,一个server标签便是一个虚拟主机,设置多个虚拟主机,装备多个server即可。

为什么script能进行跨域的恳求

总感觉面试官是想问为什么要这么规划的原因

jsonp的办法是怎样获取数据加载到页面中的

一个文件姓名hash化怎样完结?以及其原理?

结尾

非常抱愧,我发现哪怕现在现已三万字了,可还是才勉勉强强写完两家的面经

出于时刻关系,后边的面经或许要过段时刻实习的时分不忙的时分才会出了,假如有只想看面经的友友们,能够看我的牛客

闪亮啦啦啦 – 个人主页动态 – 牛客网 (nowcoder.com)

希望能协助到屏幕前的你~