前端手撕代码

目录

1. 数组去重

1.1 indexOf

1.2 ES6 Set

2. 快速排序

2.1 冒泡排序

2.2 sort

3.  防抖和节流

4. 浅拷贝和深拷贝

5. 事件委托

6. instanceof

7. call、apply、bind

8.  promise

8.1 promise.all

8.2 promise.race

8.3 promise.allsettled

9. new

10. 发布订阅模式

11. 观察者模式

12.函数柯里化

13.图片懒加载

14.数组拉平


1. 数组去重

1.1 indexOf

var arr=[3,5,1,6,1,3,5,6,9];
var result=[];
arr.forEach(item=>{
    if(result.indexOf(item)==-1){
    result.push(item);
    }
})
console.log(result);

1.2 ES6 Set

var arr=[3,5,1,6,1,3,5,6,9];
var result=Array.from(new Set(arr));
console.log(result);

2. 快速排序

2.1 冒泡排序

function bubbleSort(nums){
    //每轮循环都从最后一个元素开始,比较并交换 一次循环会把最小的数顶到最上面
    for(let i=0;i<nums.length-1;i++){//只是控制次数为n-1
        for(let j=nums.length-1;j>i;j--){
            if(nums[j]){
                //交换
                 let temp=nums[j];
                 nums[j]=nums[j-1];
                 nums[j-1]=temp;
             }
         }
}

//test
nums=[5,1,4,3,5];
bubbleSort(nums);
consloe.log(nums);

2.2 sort

升序x-y

var a=[3,5,2,6];
a.sort(function(x,y){
    return x-y;
})
console.log(a);

降序y-x

var a=[32,3,2,5,21];
a.sort(function(x,y){
    return y-x;
});
console.log(a);

3.  防抖和节流

//防抖函数
function debounce(fn,delay){
    var timeout;

    return function(){
        if(timeout)clearTimeout(timeout);
        timeout=setTimeout(function(){
            fn();
        },delay);
    }
}
//节流 定时器
function throttle(fn,wait){
    var timer;

    return function(){
        if(!timer){
            timer=setTimeout(function(){ 
                timer=null;
                fn();
            },wait)
        }
    }
}

4. 浅拷贝和深拷贝

//浅拷贝
var obj = {
            id: 1,
            name: 'andy',
            msg: {
                age: 18
            }
        };
        var o = {};
        Object.assign(o, obj);
        console.log(o);
        o.msg.age = 20;
        console.log(obj);
//深拷贝
 var obj = {
            id: 1,
            name: 'andy',
            msg: {
                age: 18
            },
            color: ['pink', 'red']
        };
        var o = {};
        // 封装函数 
        function deepCopy(newobj, oldobj) {
            for (var k in oldobj) {
                // 判断我们的属性值属于那种数据类型
                // 1. 获取属性值  oldobj[k]
                var item = oldobj[k];
                // 2. 判断这个值是否是数组
                if (item instanceof Array) {
                    newobj[k] = [];
                    deepCopy(newobj[k], item)
                } else if (item instanceof Object) {
                    // 3. 判断这个值是否是对象
                    newobj[k] = {};
                    deepCopy(newobj[k], item)
                } else {
                    // 4. 属于简单数据类型
                    newobj[k] = item;
                }
 
            }
        }
        deepCopy(o, obj);
        console.log(o);
 
        var arr = [];
        console.log(arr instanceof Object);
        o.msg.age = 20;
        console.log(obj);

5. 事件委托

<ul id="ul">
        <li>0</li>
        <li>1</li>
        <li>2</li>
        <li>3</li>
        <li>4</li>
        <li>5</li>
</ul>
    <button id="btn">点我添加一个li</button>
// 事件委托具体实现
var ul = document.getElementById("ul");
    ul.onclick = function (event) {
        event = event || window.event;
        var target = event.target;
        // 获取目标元素
        if (target.nodeName == 'LI') {
            alert(target.innerHTML);
        }
    }
    // 为按钮绑定点击事件
    var btn = document.getElementById('btn');
    btn.onclick = function () {
        var li = document.createElement('li');
        // 新增li的内容为ul当前子元素的个数
        li.textContent = ul.children.length;
        ul.appendChild(li);

6. instanceof

instanceof:左边是对象,右边是类;

  • 当对象是右边类或子类所创建对象时,返回true;否则,返false。
  • 类的实例包含本身的实例,以及所有直接或间接子类的实例
  • instanceof左边显式声明的类型与右边操作元必须是同种类或存在继承关系,也就是说需要位于同一个继承树,否则会编译错误

function myInstanceof(target,Fn){
  let proto = target.__proto__;
  while(true){
    if(proto===Fn.prototype){
      return true;
    }
    if(proto===null){
      return false;
    }
    proto =  proto.__proto__;
  }

7. call、apply、bind

他们每个都有自己的特点,比如call和apply是立即执行,而bind是绑定this后不立即执行。再有就是apply是第二个参数是数组,而call是依次传入参数。

//call
​​​​​​​Function.prototype.myCall = function(cont){
    let context = cont ||window
    let args = [...arguments].slice(1)
    context._fn = this;
    let res = context._fn(...args);
    delete context._fn;
    return res;
}
//apply
Function.prototype.myCall = function(cont){
    let context = cont ||window
    let args = [...arguments].slice(1)
    context._fn = this;
    let res = context._fn(...args);
    delete context._fn;
    return res;
}
//bind
Function.prototype.MyApply = function (cont){
  let context = cont || window;
  if(typeof this != 'function'){
    throw new Error('this is not a function!')
  }
  const _this  = this;
  return function (){
    _this.call(context,...arguments);
  }

8.  promise

all 、 race 、allsettled 。

  • all 是所有promise完成;
  • race是一个完成,但是有rejected 他俩就结束;
  • allsettled是所有都结束,不管是哪个状态。

8.1 promise.all

//promise.all
function myPromiseAll (promiseArr){
  return new Promise(function(resolve,reject){
    let result = []
    let count = 0;
    for(let i =0;i<promiseArr.length;i++){
      promiseArr[i].then(res=>{
        //注意这里是按照输入数组的顺序,而不是push
        result[i]=res;
        count++;
        if(count==promiseArr.length){
          resolve(result);
        }
      },err=>{
        reject(err)
      })
    }
  })
}

8.2 promise.race

function myPromiseRace (promiseArr){
  return new Promise(function(resolve,reject){
      for(let i =0;i<promiseArr.length;i++){
        promiseArr[i].then(res=>{
          resolve(res)
        },err=>{
          reject(err)
        })
      }
  })
}

8.3 promise.allsettled


function myAllSetteld (promiseArr){
  return new Promise(function(resolve,reject){
    let count = 0;
    let result = [];
    for(let i =0;i<promiseArr.length;i++){
      promiseArr[i].then(res=>{
        result[i]= {'status':'fulfilled','value':res};
        count++;
        if(count==promiseArr.length) resolve(result)
      },err=>{
        result[i] = {'status':'rejected','reason':err};
        count++;
        if(count==promiseArr.length) resolve(result)
      })
    }
  })
}

9. new


function myNew (constructor,...args){
  /* 1. 创建一个新对象
     2. 将构造函数原型上的方法复制给新对象
     3. 传入参数执行构造函数,并获取执行结果
     4. 判断返回值是是否为对象,不为对象返回执行结果 
  */
 let newObj = Object.create(constructor.prototype);
 let result = constructor.apply(newObj,args);
 return typeof result ==='object' ? result : newObj;

10. 发布订阅模式

class EventEmitter {
  constructor(){
    // 是一个对象来记录事件名和相应的触发函数
    this.events = {}
  }
  // 绑定一个事件的事件处理函数
  on(event,fcCallBack){
    if(!this.events[event]){
      this.events[event] = [fcCallBack]
    }else{
      this.events[event].push(fcCallBack)
    }
  }
 
 
  //触发函数
  emit(event,...args){
    if(this.events[event]){
      this.events[event].forEach(el=>{
        el.apply(this,args);
      })
    }
  }
 
 
  //停止某个事件的事件处理函数
  off (event,fcCallBack){
    if(!this.events[event]) return;
    this.events[event].filter(item=> item!= fcCallBack)
  }
 
 
  //绑定单次执行事件处理函数
  once (event,fcCallBack){
    function fn(){
      fcCallBack();
      this.off(event,fcCallBack)
    }
    this.on(event,fn)
  }
 
}

11. 观察者模式


/*
描述
    请补全JavaScript代码,完成"Observer"、"Observerd"类实现观察者模式。要求如下:
    1. 被观察者构造函数需要包含"name"属性和"state"属性且"state"初始值为"走路"
    2. 被观察者创建"setObserver"函数用于保存观察者们
    3. 被观察者创建"setState"函数用于设置该观察者"state"并且通知所有观察者
    4. 观察者创建"update"函数用于被观察者进行消息通知,该函数需要打印(console.log)数据,数据格式为:小明正在走路。其中"小明"为被观察者的"name"属性,"走路"为被观察者的"state"属性
    注意:
    1. "Observer"为观察者,"Observerd"为被观察者
*/
class Observerd {
    constructor(name,state='走路'){
        this.name = name;
        this.state = state;
        this.observers = [];
    } 
    setObserver(observer){
        this.observers.push(observer);
    }
    setState(state){
        this.state = state;
        this.observers.forEach(item=>item.update(this))
    }
 }
 
 
 class Observer {
     update(observerd){
         console.log(`${observerd.name}正在${observerd.state}`)
     }
 }

12.函数柯里化

实现累加

function add(a,b,c){
    console.log(a+b+c)
}
function curry (fn,...args){
    let len = fn.length;
    return function(){
        let _args= [...args,...arguments]
        if(_args.length<len){
            return curry.call(this,fn,..._args);
        }
        return fn.apply(this,_args)
    }
}
let tmp = curry(add);
tmp(3)(1)(4);

13.图片懒加载

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        img {
            display: block;
            width: 100%;
            height: 300px;
            margin-bottom: 10px;
        }
    </style>
</head>

<body>
    <img data-src="mao.jpg" alt="">
    <img data-src="mao.jpg" alt="">
    <img data-src="mao.jpg" alt="">
    <img data-src="mao.jpg" alt="">
    <img data-src="mao.jpg" alt="">
    <img data-src="mao.jpg" alt="">
    <img data-src="mao.jpg" alt="">
    <img data-src="mao.jpg" alt="">
    <img data-src="mao.jpg" alt="">
    <img data-src="mao.jpg" alt="">
    <img data-src="mao.jpg" alt="">
    <img data-src="mao.jpg" alt="">
</body>
<script>
    var imgs = document.querySelectorAll('img');

    //获得元素距离页面顶部的距离
    function getTop(e) {
        var T = e.offsetTop;
        while (e = e.offsetParent) {
            T += e.offsetTop;
        }
        return T;
    }

    function lazyLoad(imgs) {
        //获取可视区高度
        var H = window.innerHeight || document.documentElement.clientHeight;
        //获取被卷页面高度
        var S = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
        for (let i = 0; i < imgs.length; i++) {
            if (H + S > getTop(imgs[i])) {
                imgs[i].src = imgs[i].getAttribute('data-src');
            }
        }
    }

    window.onload = window.onscroll = function () {
        lazyLoad(imgs);
    }
</script>

</html>

14.数组拉平

es6的flat

[1, [2, [3]]].flat(Infinity);  // [1, 2, 3]

 arr.toString().split(’,’)

var arr= [11, [22, 33], [44, 55], 66];
var newArr=arr.toString().split(',');  //["11", "22", "33", "44", "55", "66"]

arr.join().split(’,’)

const arr = [11, [22, 33], [44, 55], 66];
const flatArr = arr.join().split(','); // ["11", "22", "33", "44", "55", "66"]

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值