Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[笔记] - 前端面试常手写的代码汇总 #28

Open
zhaofeihao opened this issue May 4, 2020 · 0 comments
Open

[笔记] - 前端面试常手写的代码汇总 #28

zhaofeihao opened this issue May 4, 2020 · 0 comments
Labels

Comments

@zhaofeihao
Copy link
Owner

[TOC]

JS 部分

1. 防抖节流

// 非立即执行版本
function debounce(fn, wait){
    let timer = null;
    
    return function(){
        const context = this;
        const args = arguments;
        
        if(timer){
            clearTimeout(timer);
        }
        timer = setTimeout(()=>{
            fn.apply(context, args);
            timer = null;
        }, wait);
    }
}

timer=null 起不到终止计时器的作用,只是给timer变量赋了值

// 立即执行版本
function debounce(fn, wait){
    let timer = null;
    
    return function(){
        const context = this;
        const args = arguments;
        
        if(!timer){
            fn.apply(context, args);
        }
        if(timer){
            clearTimeout(timer);
        }
        timer = setTimeout(()=>{
            timer = null;
        }, wait);
    }
}

节流:wait时间内,函数只执行一次,分为定时器版和时间戳版

// 时间戳版
function throttle(fn, wait){
    let prev = Date.now();
    
    return function(){
        const context = this;
        const args = arguments;
        let now = Date.now();
        
        if(now - prev > wait){
            fn.apply(context, args);
            prev = Date.now();
        }
    }
}
// 定时器版
function throttle(fn, wait){
    let timer = null;
    
    return function(){
        const context = this;
        const args = arguments;
        
        if(!timer){
            timer = setTimeout(()=>{
                fn.apply(context, args);
                timer = null;
            }, wait)
        }
    }
}

2. call、apply、bind实现

Function.prototype.myCall = function(context){
    const context = context || window;
    // 给context添加一个属性
    // 如 getValue.call(a,'zfh',18) => a.fn = getValue
    context.fn = this;
    // 将参数取出
    const args = [...arguments].slice(1);
    const result = context.fn(...args);
    // 删除fn
    delete context.fn;
    return result;
}
Function.prototype.myApply = function(context){
    const context = context || window;
    context.fn = this;
    
    let result;
    // 需要判断是否存在第二个参数
    // 如果存在则将第二个参数展开
    if(arguments[1]){
        result = context.fn(...arguments[1]);
    }else{
        result = context.fn();
    }

    delete context.fn;
    return result;
}
Function.prototype.myBind = function(context){
    let args = [].slice.call(arguments, 1);
    const context = context;
    const fn = this;
    
    let fbound = function(){
        const newArgs = args.concat([].slice.call(arguments));
        return fn.apply(this instanceof fn ? this : context, newArgs)
    };
    
    function Constructor(){};
    Constructor.prototype = fn.prototype;
    fbound.prototype = new Constructor();
    
    return fbound;
}

3. new

function create(){
    // 创建一个新对象
    let obj = new Object();
    // 获得构造函数
    let Con = [].shift.call(arguments);
    // 链接到原型
    obj.__proto__ = Con.prototype;
    // 绑定this,执行构造函数
    let result = Con.apply(obj, arguments);
    // 确保new出来的是个对象
    return typeof result === 'object' ? result : obj;
}

4. instanceof

// 实现一下 instanceof
function instanceof(left, right) {
    // 获得类型的原型
    let prototype = right.prototype
    // 获得对象的原型
    left = left.__proto__
    // 判断对象的类型是否等于类型的原型
    while (true) {
    	if (left === null)
    		return false
    	if (prototype === left)
    		return true
    	left = left.__proto__
    }
}

5. 二叉树遍历

二叉树遍历
使用JavaScript完成二叉树的一些基本操作

6. Promise各种API的实现

BAT前端经典面试问题:史上最最最详细的手写Promise教程

7. 实现虚拟DOM转真实DOM

理解虚拟DOM,实现DOM

8. 各种排序算法

js实现几种常见排序算法

9. repeat函数,考察闭包

闭包面试题两道
题2的另一种解法:

function repeat(func, times, wait){
    return function(){
        var args = Array.from(arguments);
        for(let i = 0; i < times; i++){
            setTimeout(func, wait * i, ...args);
        }
    }
}

10. JavaScript中的浅拷贝和深拷贝

解决循环引用的问题,使用一个set记录遍历过的值,每次拷贝前查出Set中存在这个值,就直接返回。
JavaScript中的浅拷贝和深拷贝
面试官:请你实现一个深克隆

11. 数组扁平化、去重

// 方法 1
var arr = [1, [2, [3, 4]]];

function flatten(arr) {
    var result = [];
    for (var i = 0, len = arr.length; i < len; i++) {
        if (Array.isArray(arr[i])) {
            result = result.concat(flatten(arr[i]))
        }
        else {
            result.push(arr[i])
        }
    }
    return result;
}
// 方法2
var arr = [1, [2, [3, 4]]];

function flatten(arr) {
    return arr.toString().split(',').map(function(item){
        return +item // +会使字符串发生类型转换
    })
}
// 方法3
var arr = [1, [2, [3, 4]]];

function flatten(arr) {
    return arr.reduce(function(prev, next){
        return prev.concat(Array.isArray(next) ? flatten(next) : next)
    }, [])
}
// 方法4
function flatten(arr){
    arr.flatMap(item=>Array.isArray(item)?item.flat():item);
    return arr;
}

12. 求二叉树的最大最小高度

二叉树的最大深度(JavaScript)
二叉树的最小深度

13. 柯里化

从一道面试题认识函数柯里化
前端进击的巨人(五):学会函数柯里化(curry)

14. ES6 map reduce 方法实现

Array.prototype.fakeMap = function(fn,context) {
	let arr = this;
	let temp = [];
	for(let i=0;i<arr.length;i++){
		let result = fn.call(context,arr[i],i,arr);
		temp.push(result);
	}
	return temp;
}
Array.prototype.fakeReduce = function fakeReduce(fn, base) {
  if (typeof fn !== "function") {
    throw new TypeError("arguments[0] is not a function");
  }
  let initialArr = this;
  let arr = initialArr.concat();

  if (base) arr.unshift(base);
  let index, newValue;

  while (arr.length > 1) {
    index = initialArr.length - arr.length + 1;
    newValue = fn.call(null, arr[0], arr[1], index, initialArr);

    arr.splice(0, 2, newValue); // 直接用 splice 实现替换
  }

  return newValue;
};
// 精简版
Array.prototype.reduce = function(cb, init){
    let arr = this;
    if(init){
        arr.unshift(init);
    }
    while(arr.length > 1){
        let args = arr.splice(0, 2);
        let res = cb.apply(this, args);
        arr.unshift(res);
    }

    return arr[0]
}

JavaScript 实现 reduce() 方法函数

15. 字符串压缩

字符串压缩-正则

16.EventEmitter实现

循序渐进教你实现一个完整的node的EventEmitter模块
EventEmitter 源码分析与简易实现

CSS 部分

三角形、梯形、扇形

用 css 画三角形、梯形、扇形、箭头和椭圆几种基本形状

两栏布局

  1. 第一种方式 --- 浮动
.outer1 .left {
    width: 200px;
    float: left;
}
.outer1 .right {
    width: auto;
    margin-left: 200px;
}

<div class="outer outer1">
    <div class="left">1-left</div>
    <div class="right">1-right</div>
</div>
  1. flex
.outer2 {
   display: flex;
}
.outer2 .left {
   flex: 0 0 200px; /* flex-grow: 0;flex-shrink:0; flex-basis:200px; */
}
.outer2 .right {
   flex: auto;
}

<div class="outer outer2">
    <div class="left">2-left</div>
    <div class="right">2-right</div>
</div>
  1. 绝对定位
.outer3 {
   position: relative;
}
.outer3 .left {
   position: absolute;
   width: 200px;
}
.outer3 .right {
   margin-left: 200px;
}

<div class="outer outer3">
   <div class="left">3-left</div>
   <div class="right">3-right</div>
</div>

三栏布局

  1. 绝对定位
.outer1 {
   position: relative;
}
.outer1 .left {
   position: absolute;
   width: 100px;
}
.outer1 .middle {
   margin: 0 200px 0 100px;
}
.outer1 .right {
   position: absolute;
   width: 200px;
   top: 0;
   right: 0;
}
/*注意:左右分别使用绝对定位,中间设置外边距*/

<div class="outer outer1">
   <div class="left">1-left</div>
   <div class="middle">1-middle</div>
   <div class="right">1-right</div>
</div>
  1. flex
.outer2 {
   display: flex;
}
.outer2 .left {
   flex: 0 0 100px;
}
.outer2 .middle {
   flex: auto;
}
.outer2 .right {
   flex: 0 0 200px;
}

<div class="outer outer2">
   <div class="left">2-left</div>
   <div class="middle">2-middle</div>
   <div class="right">2-right</div>
</div>
  1. 浮动
.outer3 .left{
   float: left;
   width: 100px;
}
.outer3 .right {
   float: right;
   width: 200px;
}
.outer3 .middle {
   margin: 0 200px 0 100px;
}

<div class="outer outer3">
   <div class="left">3-left</div>
   <div class="right">3-right</div>
   <div class="middle">3-middle</div>
</div>

圣杯布局

<style>
*{
        box-sizing:content-box;/* 伸缩项目自动box-sizing:border-box,所以需调整为content-box */
        margin:0;
        padding:0;
    }

    body{
        display:flex;
        flex-direction:column;/* 头、中部、脚纵向显示 */
    }

    header,footer{
        flex:0 0 50px;/* 头、脚尺寸固定,不放大、不缩小 */
        background:#3f3f3f;
    }

    .main{
        display:flex;

        /* 
        flex:1 == 1 1 auto:剩余空间放大比例(flex-grow)  空间不足缩小比例(flex-shrink)    分配多余空间之前项目占据的主轴空间(flex-basis)
        flex:1指的是:中部区域自由伸缩
        auto指的是项目本来大小,因未给main设置高度,main高度由子元素最高者决定,若子元素高度为0,则main高度为0
        块级元素未主动设置高度或未被子元素撑起高度,浏览器默认为块级元素分配高度为0。
        */
        flex:1;
    }

   .content{
        background:red;
        height:1000px;

        /* 
        横向中间内容区自适应,即使未指定宽度,但会分配宽度 
        块级元素未主动设置宽度或未被子元素撑起宽度,浏览器默认为块级元素分配宽度为可使用的全部宽度,比如全屏宽。
        */
        flex:1;
   }
   .left,.right{
        height:800px; /*不设置高度,则自动撑满整个高度*/
        background:blue;
        flex:0 0 100px;/* 左右两列固定宽 */
   }

   .left{
        order:-1;/* 让left居于左侧 */
   }
</style>

<html>
<body>
    <header></header>
    <div class="main">
        <div class="content">中间栏要在放在文档流前面以优先渲染。</div>
        <div class="left"></div>
        <div class="right"></div>
    </div>
    <footer></footer>
</body>
</html>

双飞翼布局

其实就是左右两侧定宽,中间自适应的三列布局,跟圣杯差不多

水平垂直居中

  1. 定宽
.box {
    position: absolute;
    top: 50%;
    left: 50%;
    margin-left: -50px;
    margin-top: -25px;
}
  1. 不定宽
body {
    display: flex;
    justify-content: center;
    align-items: center;
}
  1. transform:tranlate
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant