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

8,262次阅读
没有评论

共计 3779 个字符,预计需要花费 10 分钟才能阅读完成。

前言

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

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

1. token + jwt

2. 如何验证 token 有效

3. 闭包及其适用场景

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

5. js 类型判断

6. for in 和 for of

7. 事件循环

8. prommise 及其几个方法

9. css 怎么画一个三角形(通过 border 属性和透明色 transparent)

二、输出题

1. 闭包

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. 作用域和声明提升

var a = 2; 
function AA() {
    console.log(a);
    var a = 1; 
} 
AA();

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

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

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

3. 事件循环

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. 原型继承

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

//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;ilength;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 方法的手写但这个也确实浪费了很长时间,现在处于半挂不挂的状态也跟这手写题和后面算法有很大关系(确实也是因为这个写的太丐版了)。

四、算法题

输出二叉树的右试图

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

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

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

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

方法一:DFS 深度优先搜索

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 广度优先搜索

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 成,还有一些缩进命名等问题我没有仔细查看,就已经被面试官说停手了,因为面试的时间太长了。

我:😭😭

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

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

🐭🐭下次继续努力~

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

    正文完
     0
    Yojack
    版权声明:本篇文章由 Yojack 于2024-09-14发表,共计3779字。
    转载说明:
    1 本网站名称:优杰开发笔记
    2 本站永久网址:https://yojack.cn
    3 本网站的文章部分内容可能来源于网络,仅供大家学习与参考,如有侵权,请联系站长进行删除处理。
    4 本站一切资源不代表本站立场,并不代表本站赞同其观点和对其真实性负责。
    5 本站所有内容均可转载及分享, 但请注明出处
    6 我们始终尊重原创作者的版权,所有文章在发布时,均尽可能注明出处与作者。
    7 站长邮箱:laylwenl@gmail.com
    评论(没有评论)