记大厂笔试题(前端相关)

阿里系列

Q1: 请实现一个 find 函数,功能等同于 document.getElementById 。

解析: 难点在于如何获取入口节点。 假如你知道入口节点,例如root节点,那递归就行了。

考察点: 因为平常绝大多数前端童鞋不是用React就是用Vue。 很少有人能对DOM的一些原生操作做到熟悉。

// 方法1,手动写递归。
const nodes = document.body; // 万物起点,获取 body DOM

function getId(node,nodeIdMap){
    if(node){ 
        if(node.id) nodeIdMap[node.id] = node; // 如果 id 属性存在,则把该DOM存入 Map
        const children = node.children;
        for(let i = 0 ; i < children.length; i++){ // 循环
            getId(children[i],nodeIdMap) // + 递归
        }
    }
    return nodeIdMap
}

const ids = getId(nodes,{})

const findId = (id) => ids[id]
// 大家可以拿这段代码试一下。
// 方法2, 借助 document.createNodeIterator 可以去MDN上查看该API
const f =  (id)=> document.createNodeIterator(
    document.body,
    NodeFilter.SHOW_ALL,
    {
      acceptNode(node) {
        return node.id === id? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP;
      }
    }
);

f('anyId').nextNode(); // 即可获取 任意ID 的DOM

Q2: 实现 一个 find 。

测试数据为:

var data = [
    {title: 't1', userId: '10086', name: 'Jay'},
    {title: 't2', userId: '10087', name: 'Tom1'},
    {title: 't3', userId: '10088', name: 'Tina2'},
]

希望如此调用:

find(data).where({
name: /\d$/,
}).orderBy('userId','desc');

得到结果是:

[
    {title: 't3', userId: '10088', name: 'Tina2'},
    {title: 't2', userId: '10087', name: 'Tom1'}
]

考察点: 这其实是一条sql语句。 就像 select title, userId,name from 表名 where 条件 order by userId desc

分析: 咋看上去有点像链式调用? 但这是坑,面试官绝对不是想让你写个链式调用。(因为我就是这么干的,然后被怼了。)

// 先写个类

class FindData {

  constructor(data) {
    this.data = data;
  }

  where(regs) {
    const keys = Object.keys(regs);
    const d = this.data.filter((item) => {
      let r = true;
      for (let i = 0; i < keys.length; i++) {
        const current = item[keys[i]];
        if (!(current && regs[keys[i]].test(current))) {
          r = false;
        }
      }
      return r;
    })
    return new FindData(d);
  }

  orderBy(name, sort) {
    let fn;
    if(sort === 'desc'){
      fn = (a,b)=> b[name] - a[name]
    }else if(sort === 'asc'){
      fn = (a,b)=> a[name] - b[name]
    }
    return this.data.sort(fn)
  }
}

var find = (d) =>  new FindData(d);

find(data).where({name: /\d$/}).orderBy('userId','desc');

Q3: 将字符串转成千分位。例如 '12345678' 转化成千分位是 '12,345,678'.

考察点: 正则。 如果你写的不是正则,那也一定会让你用正则写。零宽断言了解一下

// 零宽断言
str.replace(/\d{1,3}(?=(\d{3})+$)/g,function(s){
    return s + ','
}) 

小结一下

阿里的笔试题不难。说真的,并不难。 但需要你非常深厚的基础。往往你熟悉的不会考你,你不知道的、少用的、模糊的一定会考你。 反正我是跪在了正则的零宽断言上了。 😭😭😭😭

字节系列

Q1: 实现数组扁平化 flat 方法。

var arr1 = [1,2,3,[1,2,3,4, [2,3,4]]];

function flattenDeep(arr1) {
   return arr1.reduce((acc, val) => Array.isArray(val) ? acc.concat(flattenDeep(val)) : acc.concat(val), []);
}
flattenDeep(arr1);// [1, 2, 3, 1, 2, 3, 4, 2, 3, 4]

Q2: 实现对象扁平化 flat 方法。

function flat(obj, key = "", res = {}, isArray = false) {
  for (let [k, v] of Object.entries(obj)) {
    if (Array.isArray(v)) {
      let tmp = isArray ? key + "[" + k + "]" : key + k;
      flat(v, tmp, res, true)
    } else if (typeof v === "object") {
      let tmp = isArray ? key + "[" + k + "]." : key + k + ".";
      flat(v, tmp, res)
    } else {
      let tmp = isArray ? key + "[" + k + "]" : key + k;
      res[tmp] = v
    }
  }
  return res
}

Q3: 实现 applyMiddleWare, 达到如下示例

function rawMethod(a){
    return a + 1;
}

function middleware1(next){
    return function(a){
        return next(a) + 1;
    }
}
function middleware2(next){
    return function(a){
        return next(a) + 1;
    }
}

function middleware3(next){
    return function(a){
        return next(a) + 1;
    }
}

var newMethod = applyMiddleWare(rawMethod, middleware3, middleware2);
var x = newMethod(1); 
// 要求调用顺序: middleware2 -> middleware3 -> middleware. 结果 x = 3
var newMethod2 = applyMiddleWare(newMethod, middleware1);
var y = newMethod2(10); 
// 要求调用顺序: middleware1 -> middleware2 -> middleware3 -> middleware. 结果 y = 131

考察点: 看名称就知道,这特么是要你手写一个 Redux 的 applyMiddleWare 方法啊! 这方法干嘛的?合并中间件插件调用的好伐。。

分析: 需要 compose 方法。

function compose(...funcs) {
    if (funcs.length === 0) {
        return args => args; //如果没有要组合的函数,则返回的函数原封不动的返回参数
    } else if (funcs.length === 1) {
        //要组合的函数只有一个
        return funcs[0];
    }

    // redux官方写法,在下面附有步骤分析,非常巧妙
    // return funcs.reduce((a, b) => (...args) => a(b(...args)));

    // 这是可读性好一些的写法,和上面代码功能一样
    return function (...args) {
        let lastReturn = null; // 记录上一个函数返回的值
        for (let i = funcs.length - 1; i >= 0; i--) {
            const func = funcs[i];
            if (i === funcs.length - 1) {
                lastReturn = func(...args);
            } else {
                lastReturn = func(lastReturn);
            }
        }
        return lastReturn;
    }

复制代码

export function applyMiddleware(...middlewares) {
    // 接收creatStore方法
    return function (createStore) {
        // 接收reducer和默认状态 ,用于创建仓库
        return function (reducer, defaultState) {
            //创建仓库
            const store = createStore(reducer, defaultState);
            let dispatch = () => { throw new Error("目前还不能使用dispatch") };

            const simpleStore = {
                getState: store.getState,
                // 这里不能写成dispatch: dispatch,否则一直是上面那个报错的dispatch
                // 也不能写成store.dispatch,否则一直是最原始的dispatch
                // 写成函数形式是为了保证引用地址一致
                dispatch: (...args) => dispatch(...args)
            }

            //给dispatch赋值
            //根据中间件数组,得到一个dispatch创建函数的数组
            const dispatchProducers = middlewares.map(mid => mid(simpleStore));
            // 在完成dispatch前,是调用不了simpleStore中的dispatch的,只有等包装完
            dispatch = compose(...dispatchProducers)(store.dispatch)
            return {
                ...store,
                dispatch,
            }
        }
    }

、、
复制代码

Q4 : 现有一台阶,共m 层。 一只青蛙每次可以跳任意层数(1 - n)的台阶,。 请问青蛙跳到第m层台阶有多种跳法?

考察点: 经典 青蛙跳台阶问题。 力扣上也有原题。 这道变态版 青蛙跳台阶 力扣上也有原题。我这里就不写了,因为知道答案的你可能会觉得有点侮辱智商😂😂😂😂

小结一下

字节的笔试题风格也很明显,喜欢考一下常用API的实现。 算法题,也都能从力扣上面找到相近的题。 如果说阿里是考你变态的基础,那字节就是考你变态的脑神经了。

腾讯系列

Q1: 写一个双链表循环树。

我跪了。 跪稳了。 求各位大佬指点。 (我曾经被问到过如何写一个单链表循环树,现在特么升级成双链表循环树了。😭😭😭😭😭😭😭)

Q2:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如,数组[3,4,5,1,2][1,2,3,4,5]的一个旋转,该数组的最小值为 1。

考察点: 二分查找。 力扣原题解析

累了。写不动了。。 直接来小结一下

小结一下

腾讯笔试题和字节有点像,不过腾讯更偏向于数据结构算法思想。 需要你对一些常见的额数据结构例如 链表 的操作有比较深的理解。

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

推荐阅读更多精彩内容