讲几道各厂高频面试题


做前端,JS基础永远是最重要的,好的JS基础,不仅能让你日常开发更具有解决问题的能力,也能让你的代码更加的准确减少bug量,当然,最重要的是,好的JS基础是面试的第一敲门砖,尤其是越优秀的团队,越注重JS基础的考察,越是面试的时候,没问什么基础,反而问“有没有做过某某某”、“这个东西会做不”、或者偶尔问了几道JS基础,也没有顺着你的答案深挖下去,这样的团队,大概率,面试官都不怎么行,他怕自己翻车,并且进去之后,这样的团队一般以搬砖为主,并且 ,不注重JS基础的团队,一般会出现很多的恶心代码,甚至出现后端随意改前端的情况~恐怖吧?所以,我希望你,一定是通过自己的强大的JS能力敲开的门而不是侥幸的经历。这算一点面经吧,如果你面试遇到了我上面说到的情况,那么大概率是那样的,好了,废话不多说了,来看一看大厂最常问的几道JS面试题吧。这些题一般都是出现在一面中。我来总结一下。

关于EventLoop的考察

关于事件循环(EventLoop)的考察,不管大厂小厂几乎是百分之百的出现!一定要掌握,如果你还对这些不理解,赶紧补知识!下面是我写的两篇关于事件循环的讲解,大家可以选择性看一下。

关于EventLoop的面试题,大概有这么两类

  • “说说什么是事件循坏”,这是最低级的一种问问题,然后你就可以白话来描述了,例如,“JS是单线程的语言,存在异步的情况,犹豫浏览器或者NodeJS环境的机制,导致JS在运行的时候,分为同步任务和异步任务,同步任务先执行,异步任务后执行,异步任务又分为微任务和宏任务,微任务优先级高于宏任务,微任务是一队一队的执行,宏任务是一个一个的执行的,一直到微任务和宏任务的队列清空为止...”等等等一系列文字描述,我个人任务,但凡是看过两篇关于EventLoop文章的,都能有上面的白话描述。
  • 出题实践,这些题往往也是难度不一,一种是直接套定义就可以套出结果来的,一些就需要你很了解其细节才能答出来的了,下面是一道某O2O公司的面试真题,看一下
console.log("task start");
task1();
setTimeout(() => {
  console.log("setTimeout");
});
new Promise(resolve => {
  console.log("promise");
  resolve();
}).then(() => {
  console.log("promise 1");
});

async function task1() {
  await task2();
  console.log("task1");
}
async function task2() {
  console.log("task2");
}
console.log("task end");

面试也就是一个踩坑的过程,上面这道题可以说是事件循环里面比较难的一道题了,下面我来说一下坑点

  1. 函数调用是一个同步的过程,直接进入函数逻辑即可,不要到这不知道该怎么走
  2. Promise本身是同步的!.then才是异步的,不要见了Promise就是微任务!
  3. async/await本身是返回一个Promise的。只不过会把逻辑绕一下

总结了上面的坑,那么我们可以套原理来求结果了

a. 先执行同步任务,输出'task start'、‘task2’,这里执行完task2后,不要去走end,这时还是会返回到task1中,并且执行完task2后会挂起来一个Promise,这时候应该是接着往下task1()后面走的,所以会打印‘promise’、最后打印task end,这是第一轮的同步任务,先执行完了。'task start'、‘task2’、‘promise’、‘task end’。
b. 接下来执行微任务,我们看一下在第一轮执行的过程中,遇到了哪些微任务,我们需要一次性将他执行完,那就是task1返回的这个Promise,所以先走‘task1’,再就是‘promise 1’。这时候所有微任务执行完了, 执行宏任务‘setTimeout’

OK,这道题就是这样一个过程,中间绕是绕在了async函数里,只要你记住,他本省返回的是一个Promise就好了,上面说了Promise本身是同步的,then才是异步的,自己在捋一捋哈,因为我也感觉我说的有点乱。

关于词法分析的问题

词法分析,是JS面试题中比较多的一类面试题了也,除了正常的词法分析,还会有一些绕的欺骗词法,这类题一般以题的形式出现。关于词法分析,大家还是多看看基础知识,这里不做详细概念讲解,大概意思就是,JS在运行过程中,会根据你写代码的顺序,来分析各个变量的作用域,下面看一下某短视频公司的面试真题

var value = 1;
function foo() {
    console.log(value);
}
function bar() {
    var value = 2;
    foo();
}
bar();

这里就是,foo中的value在词法分析阶段就已经确定了。所以打印1。详细知识点,这里需要自己补一下。因内容比较多,就不赘述了。

关于this指向问题

this指向问题可以说也是百分之百的面试内容存在。不管是大公司小公司,都会问,这里也是有两种形式

  • 说一下this指向吧,这是最低级的一种,考概念的话,大概就是this是调用执行栈,总是执行调用它的那个对象。对于箭头函数,它没有自己的this,只是继承至他词法最近的一层普通函数的this指向,明白了这个概念,大部分问概念的都没问题
  • 大部分公司都会以面试题的形式出现,面试题也是各种各样的坑,但只要你记住我上面说的白话概念,那么大部分都会做,这里主要的坑是在箭头函数的this执行, 同样也需要好好参悟我上面说的概念。下面看两道题,都是一线大厂真题
var o = {
a: () => {
const obj = {
fn: () => {
console.log(this);
}
}

function fn() {
console.log(this)
var a = obj.fn
a();
}

fn.call({b:1}) 
}
}
o.a();

这里结果为{b:1},window,可以套一下我上面的概念,应该不能理解为啥箭头函数按个会执行window,为了验证再来一道

var name = "JavaScript"
function language() {
    let name = "CSS"
    let other = {
        name: "HTML",
        fn: () => {
            var name = "Vue"
            console.log(this.name)
        }
    }
    return other
}
language().fn()

这里是打印的JavaScript,this指向的是window,可以按照我上线的分析,分析一下,这里的箭头函数的this是继承了language的this,所以其指向window。

几大手写

各种手写,几乎是所有大厂必考的题,小厂考的可能不太大。下面总结一下常见的手写

实现一个new

遇到这样的问题,一般会先问一下JS的原型链,继承,最后问JS中new一个对象的时候,发生了什么事?,如果你答出来了,那么会接着问下面的问题,“你能实现一个new吗”,如果答不上来发生了什么事,那么就没有然后了。好,我们先来看一下,new一个对象的时候,发生了什么事。

  • 以构造器的prototype属性为原型,创建新对象;
  • 将this(也就是上一句中的新对象)和调用参数传给构造器,执行;
  • 如果构造器没有手动返回对象,则返回第一步创建的新对象,如果有,则舍弃掉第一步创建的新对象,返回手动return的对象。

明白了new的时候发生了什么事以后,那么我们就可以做对应的代码实现了

// 构造器函数
let Parent = function (name, age) {
    this.name = name;
    this.age = age;
};
Parent.prototype.sayName = function () {
    console.log(this.name);
};
//自己定义的new方法
let newMethod = function (Parent, ...rest) {
    // 1.以构造器的prototype属性为原型,创建新对象;
    let child = Object.create(Parent.prototype);
    // 2.将this和调用参数传给构造器执行
    let result = Parent.apply(child, rest);
    // 3.如果构造器没有手动返回对象,则返回第一步的对象
    return typeof result  === 'object' ? result : child;
};
//创建实例,将构造函数Parent与形参作为参数传入
const child = newMethod(Parent, 'echo', 26);
child.sayName() //'echo';

上面是相对比较乞丐一点的,如果想要更加完整的实现,还需要自己再去看一下,或者,面试的时候,能写出一个乞丐版,把里面的东西讲清楚也好。

实现一个Promise.all

同样,关于Promise.all的手动实现也是一个很大概率出现的面试题,一般会出现在大厂的一面中,比较Promise.all的效果大家还是很熟悉的,面试官就会问了,“你说一下Promise.all是干啥的”,概念性的东西,还是比较简单的,你可能只需要回答:“接受一个Promise的队列,只有当所有的Promise都成功后才返回结果”,于是,就有个下面的追问, 那你知道Promise.all是怎么实现的吗?OK,我直接写出代码。
首先Promise.all的效果是下面这样的

let promise1 = new Promise(function(resolve) {
  resolve(1);
});
let promise2 = new Promise(function(resolve) {
  resolve(2);
});
let promise3 = new Promise(function(resolve) {
  resolve(3);
});

let promiseAll = Promise.all([promise1, promise2, promise3]);
promiseAll.then(function(res) {
  console.log(res); // [1,2,3]
});

那么我们只要实现上面的结果就好了

const myPromiseAll = (arr)=>{
    let result = [];
    return new Promise((resolve,reject)=>{
        for(let i = 0;i < arr.length;i++){
                arr[i].then((data)=>{
                    result[i] = data;
                    if(result.length === arr.length){
                        resolve(result)
                    }
                },reject)
        }    
    })
}

大概的思路是,因为传入的是一个Promise的数组,那么每一项都具有then属性,这样我们把结果都放入一个数组中,如果,结果的长度和传入的数组长度相同,就说明,所有的Promise都执行完毕了,我们把结果resolve就可以了。当然了,上面的代码也是一个乞丐版的,我个人觉得面试的过程中,写出这样的乞丐版把思路说清就够了,当然,我还为大家准备了一个比较完整版的,比如我们会判断传入的数组的每一项到底是不是Promise

function isPromise(obj) {
    return !!obj && (typeof obj === 'object' || typeof obj === 'function') && typeof obj.then === 'function';  
}

const myPromiseAll = (arr)=>{
    let result = [];
    return new Promise((resolve,reject)=>{
        for(let i = 0;i < arr.length;i++){
            if(isPromise(arr[i])){
                arr[i].then((data)=>{
                    result[i] = data;
                    if(result.length === arr.length){
                        resolve(result)
                    }
                },reject)
            }else{
                result[i] = arr[i];
            }
        }    
    })
}

实现一个bind

实现一个bind也是出现率很高的一个手写面试题,面试官一般会先问callapplybind三者的区别,当你说完后,会让你实现一个bind~。关于bind的实现,我们只要知道bind是干了哪些事,“改变this指向,并返回一个函数”我们去实现这个功能就好了,注意参数的收集,下面我总结了三种实现bind的方法,由初级到高级,当然了,你写的越高级,边界情况越多,那么你的评分会更高

初级版(使用const...,代码简洁,不兼容IE)
// 初级:ES6 新语法 const/...
function bind_1(asThis, ...args) {
  // 这里的 this 就是调用 bind 的函数 func
  const fn = this; 
  return function (...args2) {
    return fn.call(asThis, ...args, ...args2);
  };
}
中级版本(兼容IE,但不支持new )
// 中级:兼容 ES5
function bind_2(asThis) {
  var slice = Array.prototype.slice;
  var args = slice.call(arguments, 1);
  var fn = this;
  if (typeof fn !== "function") {
    throw new Error("cannot bind non_function");
  }
  return function () {
    var args2 = slice.call(arguments, 0);
    return fn.apply(asThis, args.concat(args2));
  };
}

实际面试中,一般写中级版本就够了,机油思想,也够复杂,我觉得

高级版(复杂但支持new)
// 高级:支持 new,例如 new (funcA.bind(thisArg, args))
function bind_3(asThis) {
  var slice = Array.prototype.slice;
  var args1 = slice.call(arguments, 1);
  var fn = this;
  if (typeof fn !== "function") {
    throw new Error("Must accept function");
  }
  function resultFn() {
    var args2 = slice.call(arguments, 0);
    return fn.apply(
      resultFn.prototype.isPrototypeOf(this) ? this : asThis, // 用来绑定 this
      args1.concat(args2)
    );
  }
  resultFn.prototype = fn.prototype;
  return resultFn;
}

写在后面

本文,根据朋友们分享的经验,做了一篇总结和部分讲解,希望对正在面试的你,有一定的帮助

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,546评论 6 507
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,224评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,911评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,737评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,753评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,598评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,338评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,249评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,696评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,888评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,013评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,731评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,348评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,929评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,048评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,203评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,960评论 2 355

推荐阅读更多精彩内容