面试问题小结

浏览器、 http

1、浏览器输入地址回车发生了什么
2、http1.0,1.1,2.0区别
3、浏览器缓存(你们项目中用到了吗? 具体干了些什么?)
4、工作原理
5、跨域解决
6、重绘重排
7、前端安全(XSS,CSP, CSRF)如果防范
8、路由原理(哈希路由和history模式)

vue

1、父组件中想用子组件里面的方法,有哪几种方式

  • 子组件可以在自己的created钩子里面用 $emit 把this开放出去
  • 在子组件上添加 ref 指令 拿到当前子组件的实例对象
  • 其实在当前写的项目中,使用了类似angualr2的依赖注入的机制,我们将所有的页面行为操作,和业务逻辑分别写到了action.ts、helper.ts里面了,如果让这两个模块用 @injectable 装饰器注入到实例列表里面,外界就可以轻松使用该实例的任何方法了(但不能为了使用方法而故意注入,这样做也有它的缺点)、

2、vue是怎样实现数据更新的

  • observe Object.defineProperty 数据劫持
  • watcher 告诉订阅值的地方 数据更新了
  • compile 收到更新通知 更新状态

3、vue和angualr2的数据更新机制的区别
4、虚拟dom

React

1、 生命周期
2、 setState同步还是异步?我想拿到异步后的数据怎么办?react为什么把setstate设计成这样?
3、虚拟dom的优势、原理
4、diff算法在虚拟dom中如何比较的新旧树的差异
5、错误边界

js

1、 ["1", "2", "3"].map(parseInt)

[1,NaN,NaN]

2、冒泡、快排、深度递归
3、jsonp
4、深层复制

let a = {
  name: '刘',
  age: 18,
  say: function() {}
}
let b = JSON.parse(JSON.stringify(a));
b.age   //18
b.age = 20;
b.age  // 20
a.age //18
b   // {name:"刘",age: 20}
  • 这种方式可以实现深层复制,但是复制的对象有函数是不行的。
  • 如果对象是一个重复引用的特性的(自己的属性里面有原对象信息,无限的自己引用自己),也不适用

5、es6新语法
6、js原型 能手画出来
7、bind、call、apply
8、隐式转换

+'23' + 1          // 24

9、数组降维

let a = [[1,2],[4,5],[77,88]];

[].concat.apply([], a)

a.flatMap(item => item)

10、promise、async、await、generator生成器
11、发布订阅模式、观察者模式、单例模式
12、面向对象的特点、以及用面向对象编程需要注意的点
13、0.1 + 0.2 !=0.3 为什么?
14、正则匹配三个连续的数字(常用正则)
15、 es6 Proxy
16、怎样区分function、 数组、 对象
17、快速生成一个 0到N的数组,然后要求在不生成新数组的情况下再打乱成随机数组

let a = [...(new Array(n)).keys()];
let b = Array.from({length:n},(v, k) => k);
let c = (n) => Array.from({length:n}).map((v,k) => k);
// 利用sort
arr.sort((v1, v2) => {
    return 0.5 - Math.random() > 0? 1: -1 
 })
// 随机项调换位置
for(let i = 0; i < arr.length; i++) {
    let curr = i;
    let randomIndex = Math.floor(Math.random() * arr.length);
    let currItem = arr[i];
    arr[i] = arr[randomIndex];
    arr[randomIndex] = currItem;
}

18、 广度优先递归一个二叉树
19、 查看两个单链表是否有交叉(有重复值)
20、 时间复杂度
21、 js对象和Map的区别
22、 斐波那切数列 (分析下 函数被调用了多少次)
23、 for in for of 的区别

ts

1、怎样表示下面结构

let a = [
    [Box,Box],
    [Box,Box],
    ...
]
Array<Box[]>

2、装饰器
3、反射
4、接口和抽象类的区别
5、反射实现依赖注入(为了解决什么问题,实现过程)
6、对象值的自动推断

const test  = {
  aa: {aaa: 1},
  bb: {bbb: 2}
}

type TestObj = typeof test;
const fun: <T extends keyof TestObj>(key: T) => TestObj[T] = key => test[key];
fun('aa');  // 自动推断为 {aaa: number}

css布局

1、css权重
2、c3新选择器
3、less的特性
4、记得小东西 多使用伪类
5、吸顶实现
6、内容过长footer跟随内容,内容很少footer就在屏幕下面 (flex实现)

项目

1、项目的架构
2、项目中遇到问题怎样解决
3、项目优化、首屏优化, 骨架屏
4、提交了几个commit, 线上紧急bug如何处理(考Git)

状态管理工具

1、vuex, redux, vuex和redux的区别
2、谈谈你对rxjs的理解

webpack

1、为什么要用loader,它解析原理
2、优化
3、那些常用的配置(入口,出口,loader,plugin,devserve等)

node

1、事件循环机制 eventloop

手写题

1、 千分位(隔三位插个逗号)

  • var a = '123456789'; => a = '123,456,789,'
function toThounsandInsertStr(str: string): string {
    let result: string = '';
    let rule: RegExp = /\d{3}$/;
    while (rule.test(str)) {
        result = RegExp.lastMatch  + result;
        if (str != RegExp.lastMatch) {
            result = ',' + result;
        }
        str = RegExp.leftContext;
    }
    return str + result;
}
toThounsandInsertStr('1234567') // 1,234,567
toThounsandInsertStr('123')  // 123
toThounsandInsertStr('1')  //1

2、 碰到a就剔除字符串里面的 aa前面的数字

  • var a = '123a456a789aa'; => a = '12457'
let _arr = a.split('');
for(let i = 0; i < _arr.length; i++) {
    let start = 0; let n = 2;
    if(_arr[i] == 'a') {  
         start = i -1 < 0? 0: i -1;
         n = i - 1 < 0? 1: 2;
        _arr.splice(start, n);
        i = n == 2 ? i - 2 : 0;
    }
}
console.log(_arr.join(''))

3、 一个请求在 delay函数延迟过后发送,结果可能成功也可能失败,如果失败就重复发送,重复n次过后还是失败,结束发送返回错误

  • 请求函数 query, 成功{succ: true}, 失败{succ: false}
  • delay函数 本身返回一个promise
function delay(t) { 
    console.log('延迟执行开始')
    return new Promise(resolve => {
        setTimeout(() => {
            console.log('延迟完毕')
            resolve()
        }, t)
    })
}
function query() {
    console.log('请求开始')
    return new Promise(resolve => {
        setTimeout(() => { 
            console.log('1秒失败,请求完毕')
            resolve({succ: false})
        },1000)
    })
 }
async function repeatQuery(delayTime, n) {
      await delay(delayTime)
      let res = await query().then(data => data);
      console.log(12312312, res)
      if(res.succ) {
          return res
      } else {
        if (n <= 0) { 
            return
        }
        return await repeatQuery(delayTime, --n)
    }
}
repeatQuery(2000, 5).then(res => { 
    console.log(111, res)
})

4、数组转树

var a = [
    {id: 1, pid: 0, name: '上海市' },
    {id: 2, pid: 1, name: '宝山'},
    {id: 3, pid: 1, name: '普陀'},
    {id: 4, pid: 0, name: '北京'},
    {id: 5, pid: 4, name: '朝阳'},
    {id: 6, pid: 4, name: '五环'},
    {id: 7, pid: 2, name: '镇平'},
    {id: 8, pid: 2, name: '宝山'},   
]
//转成递归树形式展示
  • 思路整理
    • 第一次遍历节点的时候,会发现遍历的子节点很有可能还没有父亲节点
    • 所以利用第一次遍历,找出根节点,并把所有子节点统一放到Map中,形式为(pid, [pid对应的子节点...])
    • 然后用根节点的id去匹配Map中的pid对应的子节点,匹配到的结果数组也即是当前节点的children
    • 如果有children,把children当做下一次要匹配的元素找每一个children元素的children
function arrTotree(arr) { 
    let parentMap = new Map();
    // let nodeMap = new Map();
    arr.forEach(item => {
       // nodeMap.set(item.id, item);
        if(parentMap.has(item.pid)) {
            let arr =  parentMap.get(item.pid);
            arr.push(item)
        } else {
            parentMap.set(item.pid, [item])
        }
    })
    let res = [];
    res = parentMap.get(0);
    (function loopAddChild(res) {
        res.forEach(item => {
            if (parentMap.has(item.id)) {
                item.children = parentMap.get(item.id);
                loopAddChild(item.children)
            }
         })
    })(res)
    return res;
}
// 简化版
function arrToTree(arr) {
    let map = new Map();
    arr.forEach(item => {
        if(!map.has(item.pid)) {
            map.set(item.pid, [item])
        } else {
            let arr = map.get(item.pid);
            arr.push(item)   
        }
    })
   // 都是指针 第二次遍历原数组 匹配id和pid 一样的话 map取出来当做当前遍历元素的children
    arr.forEach(item => {
        if (map.has(item.id)) {
            item.children = map.get(item.id);
        }
    })
    // 把顶级的数组取出来 返回
    return map.get(0)
}

5、 数组去重(两种方式, 如果有for循环,时间复杂度不能是o(n^2))

var a = [1,2,3,3,2,1,4,5,6,6];
Array.from(new Set([...a]))
// ----
[...new Set([...a])]
// for循环 - 空间换时间
let arr= []
let b = {};
for (let i = 0; i < a.length; i++) {
    let curr = a[i];
    if (b[curr] >= 0) { 
        continue
    }
    b[curr] = i;
    arr.push(a[i]);
}
console.log(arr)

6、浏览器事件循环

原则1:先执行主任务,然后是微任务(promise),最后是宏任务(setTimeout)
原则2:执行宏任务的时候碰到微任务,先将其推到task队列,执行完当前宏任务后,去清空微任务队列
原则3: 宏任务、微任务先进先出
原则4:new Promise 会立即执行 但 resolve是一个异步回调
原则5:async 返回的是一个Promise
原则6:await 会跳出当前执行的 async 函数体(await 让出线程)接着执行
原则7:当await操作符后面的表达式是一个Promise的时候,它的返回值,实际上就是Promise的回调函数resolve的参数
原则8:谨记上面 分析完下面三道题 就无敌了

题1

Promise.resolve().then(function promise1 () {
       console.log('promise1');
})
setTimeout(function setTimeout1 (){
    console.log('setTimeout1')
    Promise.resolve().then(function  promise2 () {
       console.log('promise2');
    })
}, 0)
Promise.resolve().then(function promise1 () {
       console.log('promise3');
})
setTimeout(function setTimeout2 (){
   console.log('setTimeout2')
}, 0)

题2

setTimeout(() => {
    console.log(1)
})
log()
function log() {
    setTimeout(() => {
        console.log(2)
        setTimeout(() => {
            console.log(3)
        })
    })
}
var a = new Promise(resolve => {
    setTimeout(() => {
        console.log(4)
    })
    resolve(() => {
        setTimeout(() => {
            console.log(5)
            setTimeout(() => {
                console.log(6)
            })
        })
    })
})
setTimeout(() => {
    console.log(7)
})
a.then((fn: any) => {
    fn()
    setTimeout(() => {
        console.log(8)
    })
})

题3

console.log('1')
async function async1() {
    await async2()
    console.log('2')
}
async function async2() {
    await async3()
    console.log('3')
}
async function async3() {
    console.log('4')
}
async1()
setTimeout(function () {
    console.log('5')
}, 0)

new Promise(resolve => {
    console.log('6')
    resolve()
}).then(function () {
    console.log('7')
    return new Promise(resolve => {
        console.log('8')
        resolve()
    })
}).then(function () {
    console.log('9')
})
console.log('10')

7、一个数组中有一系列的整数 例如 [1,2,-3,4,5,-3,4,-6],利用一个for循环在数组中找出连续相加和最大的一段 [4,5,-3,4] 和为 10

var a = [6, -3, -2, 7, -15, 1, 2, 2];
var b = [1, -2, 2, -1, 4, 5, -3, 4, -1, -2];
function findSum(arr) {
    if (arr.length < 0) return 0;
    let maxSum = 0;
    let temSum = 0;
    let resArr = []
    let originIndex = 0
    let spliceIndex = 0
    for (let i = 0; i < arr.length; i++) {
        temSum += arr[i];
        resArr.push(arr[i])
        if (temSum > maxSum) {
            maxSum = temSum;
            spliceIndex = i - originIndex
        } 
        if(temSum < 0) {
            temSum = 0;
            resArr = []
            originIndex = i
        }
    }
    resArr.splice(spliceIndex, resArr.length - 1)
    return {
        maxSum,
        resArr
    }
}
// 简单测了下 好像是对的... 
console.log(findSum(a));
console.log(findSum(b));

8、一个牧场,有一个母牛, 2年后母牛会生一头母牛和一头公牛,3年只生一头公牛,5年母牛会死,4年公牛也会死,N年后这个牧场里面有多少只牛

9、 如何让if(a == 1 && a == 2 && a == 3 ) 为true
10、用js打印杨辉三角形
11、微信抢红包逻辑
12、找出一个单词在字典中所有字母一样的单词, 如 god -> dog (查字典), 给出思路
13、实现一个无线可调用的函数用来做加法运算 add(1)(2)(3)() ---- 6

function add(num, prevSum) {
    let result = prevSum || 0
    return num ? function (nextNum) {
        result = result + num
        return add(nextNum, result) 
    } : result
}

let a = add(1)(2)(3)()
console.log(a)
// 如果非要求柯里化,可以用arguments

14、使用Promise自身特性,实现每隔两秒顺序打印数组

  • 正常思路都是在一个async的方法里面用for循环await
  • 这里运用 Promise自身可链式调用的特性
const list: number[] = [1, 2, 3]

function a(i: number): ProNum  {
    return new Promise((resolve) => {
        setTimeout(() => {
            console.log(i)
            resolve(i)   
        }, 2000)
    })
}
var p: ProNum = Promise.resolve(0)
function test (i = 0) {
    if (i === list.length) return
    p = p.then(() => a(list[i]))
    test(i+1)
}
test(0)


type ProNum = Promise<number>

15、 合并两个有序数组

function mergeTwoOrderArr(...chunk: number[][]): number[] {
    const [arr1, arr2] = chunk;
    let tem = Array.from(arr1)
    let i = arr1.length - 1;
    let j = arr2.length - 1;
    let tail = arr1.length + arr2.length - 1;
    while (j >= 0) {
        if (arr1[i] > arr2[j]) {
            tem[tail] = arr1[i]
            i--
        } else {
            tem[tail] = arr2[j]
            j--
        }
        tail --
    }
    return tem
}

其他

1、未来几年的职业计划
2、为什么选择前端
3、 学习前端技术的途径
4、 自身优缺点
5、对未来公司有什么要求
6、开发项目中遇到了什么让你感觉最骄傲的事情
7、你对我们公司有什么想要了解的
8、为什么离职
9、讲一下你最近在做的项目

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

推荐阅读更多精彩内容

  • 一般公司比较注重基础细节问题,面试问的基本上是一些基础知识,从基础知识的回答可以看出其掌握的熟练度以及深度和广度(...
    _信仰zmh阅读 466评论 0 3
  • HTML5 是 HTML 的最新稳定版本。 新增的布局元素 标签语义display 导航block 页眉block...
    limengzhe阅读 268评论 0 0
  • 含义 async函数是Generator函数的语法糖,它使得异步操作变得更加方便。 写成async函数,就是下面这...
    oWSQo阅读 1,978评论 0 2
  • 读到生本教育的理念觉得和自己的很多理念是相通的,也是接受的。越是了解,越是发现生本教育和蒙氏教育以及很多教育理念都...
    栀子花开Gardenia阅读 537评论 0 0
  • 赵孟頫 (fǔ),字子昂,号松雪道人,水晶宫道人,公元1254-1322年,湖州(今浙江吴兴)人。元代著名书画家。...
    三福阅读 1,354评论 0 0