js手写系列

180 阅读2分钟

1.数组扁平化 : 数组扁平化是指将一个多维数组变为一个一维数组

const res = [];
const fn = (arr) => {
    for(let i=0;i<arr.length;i++){
        if (Array.isArray(arr[i])){
            fn(arr[i])
        } else {
            res.push(arr[i])
        }
    }
};

例子:
fn([1, [2, [3, [4, 5]]], 6])

2.数组去重

const unique = arr => {
    let res=[];
    for(let i=0;i<arr.length;i++){
        if (res.indexOf(arr[i]) === -1){
            res.push(arr[i])
        }
    }
    return res
}

例子:
unique([1,1,3,4,5,6,5])

3.类数组转化为数组 : 类数组是具有length属性,但不具有数组原型上的方法。常见的类数组有arguments、DOM操作方法返回的结果。

1.[...document.querySelectorAll('div')];
2.Array.prototype.splice.call(document.querySelectorAll('div'));

4.filter

Array.prototype._filter = function(fn){
    if(!Array.isArray(this)){
        throw Error('type error')
    }
    if(typeof fn !== 'function'){
        throw Error(fn + 'is not a function')
    }
    let res=[];
    for(let i=0;i<this.length;i++){
        if (fn(this[i], i, this)){
            res.push(this[i])
        }
    }
    return res;
}

例子:
function fun(e,i,a){
    return e>2
}
var arr = [1,2,3,4];
var res = arr._filter(fun);
console.log(res)

5.map

Array.prototype._map = function(fn){
    if (!Array.isArray(this)){
        throw Error('type error')
    }
    if(typeof fn !== 'function'){
        throw Error(fn + 'is not a function')
    }
    let res=[]
    for(let i=0;i<this.length;i++){
        res.push(fn(this[i], i, this))
    }
    return res;
}

function ArrReduce(e){
    return e * 2;
}
var arr = [1,2,3];
var res = arr._map(ArrReduce)
console.log(res)

6.forEach

Array.prototype._forEach = function(fn){
    if(!Array.isArray(this)){
        throw Error('type error')
    }
    if(typeof fn !== 'function'){
        throw Error(fn + 'is not a function')
    }
    for(let i=0;i<this.length;i++){
        fn(this[i], i, this)
    }
}

例子:
let list = [1,2,3,4,5]
list._forEach((elem,i)=>{
    console.log(elem, i)
})

7.reduce

Array.prototype._reduce = function (fn, initValue) {
  if (!Array.isArray(this)) {
    throw Error("type error");
  }
  if (typeof fn !== "function") {
    throw Error(fn + "is not a function");
  }
  let acc;
  if (initValue) {
    acc = initValue;
  } else {
    acc = 0;
  }
  for (let i = 0; i < this.length; i++) {
    acc = fn(acc, this[i]);
  }
  return acc;
};

例子:
var arr = [1, 2, 3];
var res = arr._reduce(function (acc, el) {
  return acc + el;
}, 2);
console.log(res);

8.apply

Function.prototype._apply = function(ctx=window, args){
    if (typeof this !== 'function') { 
        throw Error(this + 'is not a function')
    }

    if(typeof ctx !== 'object'){
        throw Error(this + 'is not a Object')
    }
    
    if(!Array.isArray(args)){
       throw Error(args + 'is not a Array')
    }
    
    ctx['fn'] = this;
    let res = ctx['fn'](...args);
    delete ctx['fn'];
    return res;
}

function fn(...args) {
    console.log(this)
    console.log(args)
}
fn._apply({x:10}, [1,2,3])

9.call

Function.prototype._call = function(ctx=window, ...args){
    if (typeof this !== 'function') { 
        throw Error(this + 'is not a function')
    }

    if(typeof ctx !== 'object'){
        throw Error(this + 'is not a Object')
    }
    ctx['fn'] = this;
    let res = ctx['fn'](...args);
    delete ctx['fn'];
    return res;
}

例子:
function fn(...args) {
    console.log(this)
    console.log(...args)
}
fn._call({x:10}, 1,2,3)

10.bind

Function.prototype._bind = function(ctx=window) {
  if (typeof this !== 'function') {
    return;
  }
  var _self = this;
  var args = Array.prototype.slice.call(arguments, 1)
  var fn = function () {
    // 检测 New
    // 如果当前函数的this指向的是构造函数中的this 则判定为new 操作
    var _this = this instanceof _self ? this : ctx;
    return _self.apply(_this, args.concat(Array.prototype.slice.call(arguments)));
  }
  // 如果忽略掉原型连接这行代码,其原型对象并不等于原函数 _self 的原型,而是指定的传入的对象,不是 new 返回的对象
  fn.prototype = this.prototype;
  return fn;
}

例子:
function fn(...args) {
    console.log(this)
    console.log(...args)
}
let b = fn._bind({x:10}, 1,2,3)
b(4)

11.函数防抖: 触发高频时间后n秒内函数只会执行一次,如果n秒内高频时间再次触发,则重新计算时间。

function debounce (fn, delay){
    let timer = null;
    let that = this;
    return function(){
        if(timer){
            clearTimeout(timer)
        }
        timer = setTimeout(function(){
            fn.apply(that,arguments)
            timer = null
        },delay)
    }
}

12.函数节流: 高频时间触发,但n秒内只会执行一次,所以节流会稀释函数的执行频率。

function throttle(fn,delay){
    let timer = null;
    return function(){
       let that = this;
       if(!timer){
         timer = setTimeout(()=>{
           fn.apply(that,arguments)
           timer = null
         }, delay)
       }
    }
}

13.函数柯里化: 指的是将一个接受多个参数的函数 变为 接受一个参数返回一个函数的固定形式,这样便于再次调用,例如f(1)(2)=3;

function f(){
    const _args = [...arguments];
    function fn(){
        _args.push(...arguments);
        return fn;
    }
    fn.toString = function(){
        return _args.reduce((sum, cur) => sum + cur);
    }
    return fn
}

14.模拟new操作

function myNew(fn,...args) {
    const obj = Object.create(null)
    obj.__proto__ = fn.prototype
    const result = fn.apply(obj, args)
    const isObject = typeof result === 'object' && result !== null 
    const isFunction = typeof result === 'function'
    if(isObject || isFunction) return result
    return obj
}

例:
function P() {
    const args = Array.prototype.slice.call(arguments, 0)
    console.log(args)
}
var p = myNew(P, 1,2,3)
var p2 = new p(1,2,3)

15.手写ajax

function _ajax(url){
    let p = new Promose((resolve, reject)=>{
        const xhr = new XMLHttpRequest();
        xhr.open('GET', url, true);
        xhr.onreadystatechange = function(){
            if(xhr.readyState === 4){
                if(xhr.status === 200){
                    resolve(
                        JSON.parse(xhr.responseText);
                    )
                } else if(xhr.status === 404){
                    reject(new Error('404 not found'))
                }
            }
        }
        xhr.send(null);
    });
    return p;
}

16.深拷贝

function deepClone(obj={}){
    if(typeof obj !== 'object' || obj === null){
        return obj;
    }
    let result;
    if(obj instanceof Array){
        result = [];
    } else {
        result = {};
    }
    for(let key in obj){
        if(obj.hasOwnProperty(key)){
            result[key]=deepClone(obj[key]);
        }
    }
    return result;
}

17.instanceof

instanceof 原理:判断某个对象是否属于某个类型,或者是该类型的父类型祖先类型。

function myInstanceof(left, right) {
    let leftValue = left.__proto__
    let rightValue = right.prototype
    while(leftValue) {
      if(leftValue===rightValue) {
        return true
      }
      leftValue = leftValue.__proto__
    }
    return false
  }
  
例:
function P() {}
const p = new P()
console.log(p instanceof P)
console.log(myInstanceof(p, P))

18.Promsie.all

核心思路:

  1. 接收一个Promise实例的数组或者具有Iterator接口的对象作为参数
  2. 这个方法返回一个新的Promsie对象
  3. 遍历传入的参数,用Promsie.resolve()将参数进行包裹使其变成一个Promsie对象
  4. 参数所有回调成功才是成功,返回值数组与参数顺序一致,参数数组只要有一个失败则触发失败状态
 function promiseAll(promsies) {
    return new Promise((resolve, reject)=> {
      if(!Array.isArray(promsies)) {
        throw new Error('not Array')
      }
      let len = promsies.length
      let count = 0
      let result = []
      for(let i=0;i<len;i++) {
        Promise.resolve(promsies[i]).then(data=> {
          result.push(data)
          count++
          if(count===len) {
            return resolve(result)
          }
        }).catch(err=> {
          return reject(err)
        })
      }
    })
 }
 
 例:
 const p1 = Promise.resolve(1)
  const p2 = Promise.resolve(2)
  Promise.all([p1, p2]).then(data=> {
      console.log(data)
  })
  promiseAll([p1, p2]).then(data=> {
      console.log(data)
  })