大厂第一次给了字节,虽被丢进鱼塘但也开启了命运之门~

前言

第一次面大厂,面完之后,仿佛开启对大厂的憧憬之门,以前或许还会斟酌下大厂会不会卡学历,面完之后直接海投上压力~

书接上回:字节无缘后,迎来了滴滴二面,好家伙鏖战三小时!

书接下回:百度一和二面分享(今天刚刚面完二面,还来不及写......)

一、八股题(感兴趣可以自行查阅或者跳转)

1. token + jwt

2. 如何验证token有效

3. 闭包及其适用场景

4. 有哪些水平垂直居中方法(不知道具体宽高来实现)

看这 -> 当面试官问你使内容水平垂直居中的方式有哪些时,你可以回答出几种?

5. js类型判断

6. for in 和 for of

看这 -> 那些 for in 和 for of 以及遍历迭代踩过的坑

7. 事件循环

8. prommise 及其几个方法

看这 -> 一次性复习Promise上所有方法的实现原理

二、输出题

1. 闭包

js 复制代码
function func() { 
    let i = 0 
    return () => { 
        i++ 
        console.log(i) 
    } 
} 

const func1 = func() 
const func2 = func() 
func1() 
func2() 
func1()  
func2() 
func1 === func2

注意这里是创建俩个实例对象 func1 和 fuunc2,所以这俩个实例对象都会拥有自己单独的闭包,所以执行 func1() 、func2() 、func1() 、func2() 后各自的实例对象调用各自的闭包,所以打印结果为 1 1 2 2 ,那么最后执行的结果都为2,即 func1 和 fuunc2 的值是一样的,但都是对象有各自的引用地址,且 === 除了判断值相对外还会判断地址是否相等,所以这里打印 false

2. 作用域和声明提升

js 复制代码
var a = 2; 
function AA() { 
    console.log(a);
    var a = 1; 
} 
AA();

这也是一道很经典的题目了,主要考察 varletconst 特性,var 变量的声明会被提升到当前作用域的顶部,虽然 var a = 1 在打印后面,但是var a 变量已经声明到函数作用域的顶部,已经声明但还没有赋值,所以打印的是 undefined,如果 var a = 1 在打印前面则打印 2 ,那么这时候面试官就开始作妖了~

js 复制代码
// 这时候又打印什么呢?
var a = 2; 
function AA() { 
    console.log(a);
    let a = 1; 
} 
AA();

var 变量具有声明提升,但是 let 并没有且具有块级作用域,所以此处打印会报错

3. 事件循环

js 复制代码
setTimeout(function() { 
    console.log(1) 
}, 0); 

new Promise(function(resolve) { 
    console.log(2); 
    for(var i = 0; i < 10000; i++) { 
        if (i === 9999) { 
        resolve(); 
        } 
    } 
    console.log(3); 
}).then(function() { 
    console.log(4); 
}); 

console.log(5);

记住事件循环顺序:同步 -> 异步(微任务 -> 宏任务),所以结果就是 2 3 5 4 1

4. 原型继承

js 复制代码
Function.prototype.a = () => alert(1)
Object.prototype.b = () => alert(2);
function A() {} 
const a = new A(); 
a.a();
a.b();

a.b() 的结果是显示 2 这想必大家都很清楚,因为是直接在对象原型上挂方法,通过原型链逐层往上可以找到,但问题出现在 a.a() 要怎么判断呢?我们可以这么想,我们都知道 Function 上挂方法 a , 实例对象 function A() 是可以访问到的,即 A.a() 可以继承并显示 1 ,那么 function A() 的实例对象 a 可以访问吗?

我们都知道实例对象的隐式原型等于构造函数的显示原型,即 Function.prototype = obj.__proro__

按照这个依据我们就可以这么想:

  1. Function.prototype = A.__proro__ ,所以 function A() 可以继承到 a 方法
  2. A.prototype = a.__proro__ ,这里 A 作为构造函数,但是 Aa 方法在隐式原型上__proro__
  3. 所以实例对象 a 并不能继承到 A 上的隐式原型方法,如果 A.prototype.a = () => alert(1) 则可以

所以这题 a.a() 会报错, a.b() 会显示 2

三、手写题

手写一个Promise.half

js 复制代码
//Proimse.half = function(arr) {} 
//有一半成功,就立即返回[res, res],低于一半,就返回null

function myHalf(promise){
    return new Promise((resolve, reject)=>{
        const res = [] // 储存每个promise状态
        let n = 0      // 已经走完的次数
        let ful = 0    // 状态成功的数量
        let re = 0     // 状态失败的数量

        for(let i = 0;i<promise.length;i++){
            promise[i].then((res)=>{ 
                res.push(promise[i])
                ful = ful + 1  // 记录成功状态的个数
                if(ful >= (promise.length)/2){
                    resolve(res)  // 超过一一半直接返回存入成功状态的数组结果
                }
            }).catch((err)=>{
                res.push(promise[i])
                re = re + 1  // 记录失败状态的个数
                if(re >= (promise.length)/2){
                    reject(null)  // 超过一一半直接返回 null
                }
            }).finally(()=>{
                n = n + 1
            })
        }
    })
}

其实这道手写题就是 promise.allSettled 的变种题,promise.allSettled 用于处理一组 Promise 对象,并在所有 Promise 对象都已经 settled(fulfilled 或 rejected)之后返回一个新的 Promise,该 Promise 包含一个数组,数组中的每个元素都代表了原始 Promise 是否已经 fulfilled 或 rejected 以及对应的值或原因。

所以我们只需要把每个promise的状态给用一个数组记录下来,当某个状态超过一半时则返回对应结果,当时我写这题时也是一脸懵,因为也看了其他promise方法的手写但这个也确实浪费了很长时间,现在处于半挂不挂的状态也跟这手写题和后面算法有很大关系(确实也是因为这个写的太丐版了)。

如果对promise的其他方法手写感兴趣可以看看我朋友的这篇文章: 一次性复习Promise上所有方法的实现原理

四、算法题

输出二叉树的右试图

这道题目是力扣中等难度原题:199.二叉树的右试图

  • 输入: [1,2,3,null,5,null,4]
  • 输出: [1,3,4]

题目具体意思是从二叉树的右边看,从上往下输出看的第一个值,具体解题思路是按照中右左的前序遍历 或者层序遍历 来查找,可以使用深度优先递归遍历 或者广度优先层序遍历来进行查找。

方法一:DFS深度优先搜索

js 复制代码
var rightSideView = function(root) {
  if(!root) return []
  let arr = []
  dfs(root, 0, arr)
  return arr
};
function dfs (root, step, res) {
  if(root){
    if(res.length === step){
      res.push(root.val)           // 当数组长度等于当前 深度 时, 把当前的值加入数组
    }
    dfs(root.right, step + 1, res) // 先从右边开始, 当右边没了, 再轮到左边
    dfs(root.left, step + 1, res)
  }
}

方法二:BFS广度优先搜索

js 复制代码
var rightSideView = function(root) {
  if(!root) return []
  let queue = [root]                        // 队列 把树顶加入队列
  let arr = []                              // 用来存储每层最后个元素值
  while(queue.length > 0){
    let len = queue.length
    while (len) {
      let node = queue.shift()               // 取出队列第一个元素
      if(len === 1) arr.push(node.val)       // 当是 当前一层的最后一个元素时,把值加入arr
      if(node.left) queue.push(node.left)    // 继续往队列添加元素
      if(node.right) queue.push(node.right)
      len--
    }
  }
  return arr
};

这题说来惭愧,本人平常都是用python来写算法题目,因为字节的是在飞书的编译平台进行编写,也没有样例可以运行,本人这题只写对了7-8成,还有一些缩进命名等问题我没有仔细查看,就已经被面试官说停手了,因为面试的时间太长了。

我:😭😭

面试官:后面回去等通知😐😐

等了半个月的我既没有收到感谢信也没收到二面通知,大概率进鱼塘了吧......

🐭🐭下次继续努力~

顺带一提的是,算法题后来在力扣平台又成功跑了一遍,思路是对的,但有些地方需要改进。

相关推荐
风清扬_jd3 分钟前
Chromium 中JavaScript Fetch API接口c++代码实现(二)
javascript·c++·chrome
丁总学Java19 分钟前
微信小程序-npm支持-如何使用npm包
前端·微信小程序·npm·node.js
It'sMyGo28 分钟前
Javascript数组研究09_Array.prototype[Symbol.unscopables]
开发语言·javascript·原型模式
懒羊羊大王呀29 分钟前
CSS——属性值计算
前端·css
睡觉然后上课39 分钟前
c基础面试题
c语言·开发语言·c++·面试
李是啥也不会44 分钟前
数组的概念
javascript
无咎.lsy1 小时前
vue之vuex的使用及举例
前端·javascript·vue.js
fishmemory7sec1 小时前
Electron 主进程与渲染进程、预加载preload.js
前端·javascript·electron
fishmemory7sec1 小时前
Electron 使⽤ electron-builder 打包应用
前端·javascript·electron
豆豆2 小时前
为什么用PageAdmin CMS建设网站?
服务器·开发语言·前端·php·软件构建