前端面试总结

939 阅读8分钟

不错文章推荐

一、html部分

二、 css部分

1、BFC 链接

  • 在一个块级排版上下文中,盒子是从包含块顶部开始,垂直的一个接一个的排列的。 相邻两个盒子之间的垂直的间距是被margin属性所决定的,在一个块级排版上下文中相邻的两个块级盒之间的垂直margin是折叠的

2、水平竖直居中方案链接

3、重绘和重排 详情

  • 重绘:当盒子的位置、大小以及其他属性,例如颜色、字体大小等都确定下来之后,浏览器便把这些原色都按照各自的特性绘制一遍,将内容呈现在页面上。 重绘是指一个元素外观的改变所触发的浏览器行为,浏览器会根据元素的新属性重新绘制,使元素呈现新的外观。 触发重绘的条件:改变元素外观属性。如:color,background-color等。
  • 重排: 当渲染树中的一部分(或全部)因为元素的规模尺寸,布局,隐藏等改变而需要重新构建, 这就称为回流(reflow)。每个页面至少需要一次回流,就是在页面第一次加载的时候。
  • 联系:重绘和重排的关系:在回流的时候,浏览器会使渲染树中受到影响的部分失效,并重新构造这部分渲染树,完成回流后,浏览器会重新绘制受影响的部分到屏幕中,该过程称为重绘。 所以,重排必定会引发重绘,但重绘不一定会引发重排。

4、三列布局(左右两边固定,中间自适应) 链接

4.1利用浮动,注意左中右位置

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        *{
            margin: 0;
            padding: 0;
        }
        .left{
            width: 200px;
            height: 200px;
            background: red;
            float: left;
        }
        .middle{

        }
        .right{
            width: 200px;
            height: 200px;
            background: blue;
            float: right;
        }
    </style>
</head>
<body>
    <div>
        <div class="left">left</div>
        <div class="right">right</div>
        <div class="middle">前些日子从@张鑫旭微博处得一份推荐(Front-end-tutorial),号称 最全的资源教程 -前端涉及的所有知识体系;有粗略查看,果然“叹为观止”,至少比想象中涉猎丰富许多;果断有Fork了来:Front-end-tutorial;本就有收藏&分享欲,这种事儿早期也想做了,勘叹见识未广而深;幸遇这良心收集,得以借他人之酒杯,一浇我心之夙愿块垒。毕竟人为收集,并未臻于不可附加之境,还是有许多可以补充的点;因此,有特引于博客,将酌情适当增删些内容,一来做自己查纠探索之源,二来分享给更多朋友;好文章好工具,很多时候都被隐藏于犄角旮旯了,有居干货,欢请分享。</div>
    </div>
</body>
</html>

4.2利用position 绝对定位,脱离文档流

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        *{
            margin: 0;
            padding: 0;
        }
        .left{
            width: 200px;
            height: 200px;
            background: red;
            position: absolute;
            left: 0;
            top:0;
        }
        .middle{
           margin:0 200px;
        }
        .right{
            width: 200px;
            height: 200px;
            background: blue;
            position: absolute;
            top: 0;
            right: 0;
        }
    </style>
</head>
<body>
    <div>
        <div class="left">left</div>
        <div class="middle">前些日子从@张鑫旭微博处得一份推荐(Front-end-tutorial),号称 最全的资源教程 -前端涉及的所有知识体系;有粗略查看,果然“叹为观止”,至少比想象中涉猎丰富许多;果断有Fork了来:Front-end-tutorial;本就有收藏&分享欲,这种事儿早期也想做了,勘叹见识未广而深;幸遇这良心收集,得以借他人之酒杯,一浇我心之夙愿块垒。毕竟人为收集,并未臻于不可附加之境,还是有许多可以补充的点;因此,有特引于博客,将酌情适当增删些内容,一来做自己查纠探索之源,二来分享给更多朋友;好文章好工具,很多时候都被隐藏于犄角旮旯了,有居干货,欢请分享。</div>
        <div class="right">right</div>
    </div>
</body>
</html>

4.3、flex实现


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        *{
            margin: 0;
            padding: 0;
        }
        .container{
            display: flex;
        }
        .left{
            width: 200px;
            height: 200px;
            background: red;
        }
        .middle{
            flex: 1;
        }
        .right{
            width: 200px;
            height: 200px;
            background: blue;
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="left">left</div>
        <div class="middle">前些日子从@张鑫旭微博处得一份推荐(Front-end-tutorial),号称 最全的资源教程 -前端涉及的所有知识体系;有粗略查看,果然“叹为观止”,至少比想象中涉猎丰富许多;果断有Fork了来:Front-end-tutorial;本就有收藏&分享欲,这种事儿早期也想做了,勘叹见识未广而深;幸遇这良心收集,得以借他人之酒杯,一浇我心之夙愿块垒。毕竟人为收集,并未臻于不可附加之境,还是有许多可以补充的点;因此,有特引于博客,将酌情适当增删些内容,一来做自己查纠探索之源,二来分享给更多朋友;好文章好工具,很多时候都被隐藏于犄角旮旯了,有居干货,欢请分享。</div>
        <div class="right">right</div>
    </div>
</body>
</html>

4.4双飞翼

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        *{
            margin: 0;
            padding: 0;
        }
        .middle-wrap {
            float: left;
            width: 100%;
            height: 200px;
            background-color: yellow;
        }
        .middle-wrap .middle {
            height: 200px;
            margin: 0 200px; /*留出距离*/
            background-color: yellow;
        }
        .left {
            float: left;
            width: 200px;
            margin-left: -100%;
            height: 200px;
            background-color: red;
        }
        .right{
            float: left;
            width: 200px;
            height:200px;
            margin-left: -200px;
            background-color: green;
        }
    </style>
</head>
<body>
<div>
    <!--主元素要放在文档流最前面-->
    <div class="middle-wrap">
        <div class="middle"><span>div-middle</span></div>
    </div>
    <div class="left"><span>div-left</span></div>
    <div class="right"><span>div-right</span></div>
</div>
</body>
</html>

4.5圣杯布局


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        *{
            margin: 0;
            padding: 0;
        }
        .container{
            padding:  0 100px;/* 留出左右的距离*/
            height: 100px;
        }
        .middle {
            float: left;
            width: 100%;
            height: 50px;
            background-color: yellow;

        }
        .left {
            float: left;
            width: 100px;
            margin-left: -100%;
            height: 50px;
            background-color: red;
            position: relative;
            left: -100px;/*往左拉*/
        }
        .right{
            float: left;
            width: 100px;
            height:50px;
            margin-left: -100px;
            background-color: green;
            position: relative;
            right: -100px;/*往右拉*/
    </style>
</head>
<body>
<div class="container">
    <!--主元素要放在文档流最前面-->
    <div class="middle"><span>div-middle</span></div>
    <div class="left"><span>div-left</span></div>
    <div class="right"><span>div-right</span></div>
</div>
</body>
</html>

三、js部分

1、new 构造函数发生了哪几个步骤

  • 创建一个新对象;
  • 将构造函数的作用域赋给新对象(因此this就指向了这个新对象);
  • 执行构造函数中的代码(为这个新对象添加属性);
  • 返回新对象

2、原型链问题 链接 连接二

foo = function () {
    this.number = 1;
};
foo.number = 2;
foo.prototype.number = 3;
bar = new foo();
console.log(foo.number); //2 
console.log(bar.number);    //1
console.log(foo.constructor);   //Fun
console.log(foo.prototype.constructor); //foo 
console.log(bar.constructor);   //foo 
console.log(bar.prototype);     //underfined

3、http2优势 地址

  • 多路复用
  • 二进制分帧
  • 首部(头部)压缩
  • 服务端主动推送消息

4、强制缓存与协商缓存 地址

  • 强制缓存Catch-Control 、 Expires
cache-control:max-age=691200  
expires:Fri, 14 Apr 2017 10:47:02 GMT  
  • 协商缓存
Last-Modified和If-Modified-Since对应  
Etag和If-None-Match  

5、手写防抖函数 地址

const debounce = (fn,delay)=>{
  let timer;
  if(timer) {
    clearTimeout(timer);
  }
  return (...args)=>{
    timer = setTimeout(() => {
      fn(...args);
      timer = null;
    }, delay);
  } 
}

6、二叉树 地址

  • 前序遍历:访问根–>遍历左子树–>遍历右子树;

  • 中序遍历:遍历左子树–>访问根–>遍历右子树;

  • 后序遍历:遍历左子树–>遍历右子树–>访问根;

  • 广度遍历:按照层次一层层遍历;

7、浏览器的事件循环 地址

进程是资源分配的最小单位,线程是CPU调度的最小单位

  • 常见的宏任务:
    setTimeout
    setImmediate(只有ie支持)
    setInterval
    messageChannel
  • 常见的微任务:
    Promise.then()
    mutationObserver
    process.nextTick(callback)
async function async1(){
  console.log('1')
  await async2()
  console.log('2')
}
async function async2(){
  console.log('3')
}
console.log('4')
setTimeout(function(){
  console.log('5') 
},0)  
async1();
new Promise(function(resolve){
  console.log('6')
  resolve();
}).then(function(){
  console.log('7')
})
console.log('8');

//  4 | 1 | 3 | 6 | 8 | 2 |  7 | 5

8、闭包 链接

for (var j = 0; j < 3; j++) {
    (function (j) {
        setTimeout(function () {
            console.log(j)
        }, 1000)
    })(j)
}

9、数组的去重链接

let arr = [2,4,2,6,4,8,10];  
//1、利用for嵌套for,然后splice去重  
function unique(arr) {
    for (let i = 0; i < arr.length; i++) {
        for (let j = i + 1; j < arr.length; j++) {
            if (arr[i] == arr[j]) {
                arr.splice(j, 1);
                j--;
            }
        }
    }
    return arr
}
//2、利用indexOf去重  
function unique1(arr) {
    let array = [];
    for (let i = 0; i < arr.length; i++) {
        if (array.indexOf(arr[i]) === -1) {
            array.push(arr[i])
        }
    }
    return array
}
//3、利用对象的属性不能相同的特点进行去重  
function unique(arr){
  var obj = {}
  var result = []
  for(var i in arr){
    if(!obj[arr[i]]){
      obj[arr[i]] = true;
      result.push(arr[i]);
    }
  }
  return result;
}
  
  
//4、 reduce + include去重
function unique(arr){
    return arr.reduce((prev,cur) => prev.includes(cur) ? prev : [...prev,cur],[]);
}


10、promise实现多个请求并发,控制并发数

const promises = [p1, p2, p3, p4, p5];
const max = 2;
let ins = 0;
let result = [];

function send(promises) {
if(promises.length) {
const pros = promises.slice(ins * max, max);
ins++;
pros.length && Promise.all(pros).then(res => {
result = result.concat(res);
send(promises);
});
}
}

11、深拷贝实现 链接

 function deepClone(obj) {
      if (obj === null) return null; //null 的情况
      if (obj instanceof RegExp) return new RegExp(obj); //正则表达式的情况
      if (obj instanceof Date) return new Date(obj); //日期对象的情况
      if (typeof obj == 'Function') return new function(obj){}; //函数的情况
      if (typeof obj != "object") {
        //非复杂类型,直接返回 也是结束递归的条件
        return obj
      }
      //[].__proto__.constructor=Array()
      //{}.__proto__.constructor=Object()
      //因此处理数组的情况时,可以取巧用这个办法来new新对象
      var newObj = new obj.__proto__.constructor;
      for (var key in obj) {
        newObj[key] = deepClone(obj[key])
      }
      return newObj;
    }


12、common.js和es6区别 链接

四、webpack部分

1、loader和plugin区别 [链接])(github.com/Advanced-Fr…)

2、webpack的性能优化 链接

四、react部分

1、生命周期

2、setState同步异步的问题

3、Route 渲染组件的三种方式

  • component 最常用,只有匹配 location 才会加载 component 对应的 React组件
  • render 路由匹配函数就会调用
  • children 不管路由是否匹配都会渲染对应组件

五、node部分

1、中间件实现(koa)

function app() {  
  
}  
app.routes = [];  
app.use = function (fn) {  
 app.routes.push(fn)};  
app.use((ctx,next)=>{  
 console.log(1); next(); console.log(2);});  
app.use((ctx,next)=>{  
 console.log(3); next(); console.log(4);});    
  
let index= 0;  
function next() {  
 if(app.routes.length ===index) return; let route =  app.routes[index++]; console.log(String(route)); route({},next);}  
next();  

2、generator函数

//  generator 必须要有* 配合yeild ,碰到yield 就停止,再次调用next就继续走  
// 当遇到return时就迭代完成了  
// 第一个next传递参数是没有效果的  
// 第二次next传递的参数 是第一次yield的返回值  
function* thing() {
    let a = yield 1;
    console.log(a);
    let b = yield 2;
    console.log(b);
    return b;
}
let it = thing();  
console.log(it.next(111));  
console.log(it.next(2000));  
console.log(it.next('4000'));  

六、http相关

1、说下从输入url发生了什么?链接

2、xss和csrf 链接

  • xss跨站脚本攻击 1、HttpOnly 防止劫取 Cookie 2、转义
  • csrf跨站请求伪造 1、增加验证码 2、验证token 3、Referer Check

3、 http相关 链接

七、前端常见算法 链接

1、随机生成指定长度的字符串

function randomString(n){
    let str = 'abcdefghijklmnopqrstuvwxyz9876543210';
    let tmp = '',i=0,l=str.length;
    for(i=0;i<n;i++){
        tmp+=str.charAt(Math.floor(Math.random()*l))
    }
}

console.log(str.charAt(8) );

2、冒泡排序

function bubbleSort(arr) {
    for(let i=0;i<arr.length-1;i++){
        for(let j=0;j<arr.length-i-1;j++){
            if(arr[j]>arr[j+1]){
                let temp=arr[j];
                arr[j]=arr[j+1];
                arr[j+1]=temp;
            }
        }
    }
    return arr
}
console.log(bubbleSort([8,94,15,88,55,76,21,39]));

3、快速排序 链接

function quickSort(arr) {
    if (arr.length == 0) {
        return [];
    }
    let left = [];
    let right = [];
    let pivot = arr[0];

    for(let i=1;i<arr.length;i++){
        if(arr[i]<pivot){
            left.push(arr[i])
        }else{
            right.push(arr[i]);
        }
    }
    return quickSort(left).concat(pivot,quickSort(right))
}

console.log(quickSort([15, 94, 8, 88]));

4、二分查找

function binary_search(arr, key) {
    var low = 0,
        high = arr.length - 1;

    while(low <= high) {
        var mid = parseInt((high + low) /2);
        // console.log(mid+'h'+high+'l'+low);
        if(key == arr[mid]) {
            return mid;
        } else if(key > arr[mid]) {
            low = mid + 1;
        } else {
            high = mid -1;
        }
    }
    return -1
}

var arr = [1,2,3,4,5,6,7,8,9,10,11,23,44,86];
var result = binary_search(arr, 10);
console.log(result);   // 9
var resultNone = binary_search(arr, 100);
console.log(resultNone);  // -1

5、数组的diff

const arrA = [1, 2, 3, 4];
const arrB = [1, 2, 5, 8];
const difference = arrA.concat(arrB).filter(v =>
  // console.log(v);
  arrA.includes(v) && !arrB.includes(v) // [1,3]

);
console.log(difference);

七、常见打印问题

1、promise相关

async function async1() {
    console.log('async1 start')
    await async2()
    console.log('async1 end')
}

async function async2() {
    console.log('async2')
}

console.log('script start')

setTimeout(function () {
    console.log('setTimeout')
}, 0)

async1()

new Promise(function (resolve) {
    console.log('promise1')
    resolve()
}).then(function () {
    console.log('promise2')
})
console.log('script end')