关于javascript:我的一些手写js系列

42次阅读

共计 6135 个字符,预计需要花费 16 分钟才能阅读完成。

alert 输入的是字符串

一、手写 call&bind

~function anonymous(proto){function bind(context = window, ...args){return (...amArgs) => {this.apply(context, args.conact(amArgs));
    }
  }

  function call (context, ...args){
    context === null ? context = window : null;
    let type = typeof context;
    if(type !== 'object' && type !== 'function' && type !== 'symbol'){switch(type){
        case "number":
          context = new Number(context);
          break;
        case 'string':
          context = new String(context);
          break;
        case 'boolean':
          context = new Boolean(context);
          break;
      }
    }
    context.$fn = this;
    let result = context.$fn(...args) 
    delete context.$fn;
    return result;
  }
 proto.call = call
  proto.bind = bind
}(Function.prototype)

二、节流防抖

节流 :多少秒再执行,如果没到执行工夫内持续点击,则从新计算执行工夫 利用:input 输入

function debounce(fn, delay){
    let timer = null;
    return function (){if(timer){clearTimeout(timer)
      }
      timer = setTimeout(() => {fn.call(this, ...arguments)
        timer = null;
      }, delay)
    }
  }
  // 示例:handleChange = (e) => {this.value = e.target.value;}
  Input.onChange = debounce(handleChange, 500);
  Input.onChange  = function(){if(timer){clearTimeout(timer);
     }
     timer = setTimeout(() => {handleChange.call(this, ...arguments)
     }, 500)
  }

防抖 :设置两秒距离点击一次,无论你点击多少次,都是两秒之后执行 利用:resize,scroll
1、工夫戳

function throttle(fn, interval){  // 此时立刻执行
  let last = new Date().getTime();
  return function(){let now = new Date().getTime();
    if(now - last > interval){
      last = now;
      fn.apply(this, [...arguments])
    } 
  }
}

2、定时器

function throttle(fn, interval){
  let timer = null
  return function(){if(!timer){timer = setTimeout(() => {fn.apply(this, [arguments])
        clearTimeout(timer)
      }, interval)
    }
  }
}

3、工夫戳和定时器联合形式

 function throttle(fn, delay){ // 节流 10
    let timer = null;
    let startTime = new Date().getTime();  30
    return function (){let curTime = new Date().getTime();
      let remaining = delay - (curTime - startTime);
      let context = this;
      let args = arguments;
      clearTimeout(timer);
      if(remaining <= 0){fn.apply(context, args);
        startTime = curTime;
      } else {timer = setTimeout(fn, remaining);
      }
    }
  }

三、实现一个 new

function self_new(Func, ...args){
  // 默认创立一个实例对象(而且是属于以后这个类的一个实例)let obj = {};
  obj.__proto__ == Func.prototype; // IE 大部分浏览中不容许咱们间接操作__proto__;
  //  let obj = Object.create(Dog.prototype); 等价于下面两行
  let result = Func.call(obj, ...args);
  if((typeof result === 'object' && result !== null) || (typeof result === 'function') ){return result}
  return obj;
  // 也会把类当做一般函数执行
  // 执行的时候要保障 this 指向创立的实例
}

四、继承的四种形式

1、原型继承

  function A () {this.x = 100;}
  A.prototype.getX = function getX () {console.log(this.x)
  }
  function B (){this.y = 200;}
  // 原型继承
  B.prototype = new A()
  B.prototype.getY = function getY(){console.log(this.y);
  }
  let b = new B;
  // 特点:并不会把父类的办法克隆给子类,而是建设了子类和父类的原型链查找机制
  // 重定向子类的原型后,默认会失落原有的 constructor 属性,// 任何一个子类能够批改父类上的属性办法,// 父类的公有属性办法变成子类的私有属性 

2、call 继承

  function A (){this.x = 100;}
  A.prototype.getX = function getX(){console.log(this.x)
  }
  // 把父类当做一般函数执行, 让其执行的时候,办法中的 this 变为子类的实例即可
  function B(){A.call(B);
    this.y = 200;
  }
  B.prototype.getY = function getY(){console.log(this.y)
  }
  let b = new B;
  // 只能继承父类的公有属性,继承的公有属性赋值给子类实例的公有属性
  // 父类的原型办法无奈被继承 

3、寄生组合继承(perfect)

// call 继承实现公有属性继承
  // 原型继承实现私有属性继承
  function A (){this.x = 100;}
  A.prototype.getX = function getX(){console.log(this.x)
  }
  // 把父类当做一般函数执行, 让其执行的时候,办法中的 this 变为子类的实例即可
  function B(){A.call(B);
    this.y = 200;
  }
  // Object.create : 创立一个空对象,让其__proto__ 指向 A.prototype
  B.prototype  = Object.create(A.prototype);
  B.prototype.constructor = 
  B.prototype.getY = function getY(){console.log(this.y)
  }
  let b = new B;

4、class 继承

class A {constructor(){this.x = 100;}
    // 设置 A.prototype 上的办法
    num = 1000;
    // 把 A 当做一般对象设置的属性和办法
    static n = 2000;
    static getH () {console.log('123123')
    }
    getX(){console.log(this.x)
    }
  }

  class B extends A{constructor(){super();
      this.y = 300;
    }
    getY(){console.log(this.y);
    }
  }

五、深拷贝

JOSN.parse(JSON.stringify(obj))

缺点:本义之后,正则 => {}  函数 => null
function deepClone(obj){if(obj  === null) return null;
  // 如果是根本数据值或者函数,也能够间接返回即可 (函数无须要克隆)
  if(typeof obj !== 'object') return obj;
  // 如果是正则
  if(Object.toString.call(obj) === '[Object RegExp]') return new RegExp(obj);
  // 如果是日期格局
  if(Object.toString.call(obj) === '[Object Date]') return new Date(obj);
  
  // obj.constructor:找到所属类原型上的 constructor,而原型上的 constructor 指向的事以后类的自身 ==> 保障传递进来什么类型的值,咱们最初创立的 newObj 也是对应类型
  let newObj = new obj.constructor;
  for(let key in obj){if(!obj.hasOwnProperty(key)) break;
    newObj[key] = deepClone(obj[key]) 
  } 
  return newObj;
}

六、实现 promise

class MyPromise{constructor(executor){
    // 每一个 promise 实例都有一个状态和后果属性
    this.PromiseStatus = 'pending';
    this.PromiseValue = undefined;
    this.resoveFnArr = [];
    this.rejectFnArr = []

    // 定义 resolve/reject 办法用来扭转 promise 实例的状态和后果
    let change = (status, value) => {if(this.PromiseStatus !== 'pending') return;
      this.PromiseValue = value;
      this.PromiseStatus = status;
      let fnArr = status === 'resolved'? this.resoveFnArr: this.rejectFnArr;
      fnArr.forEach(item => {if(typeof item !== 'function'){return}
        item(this.PromiseValue);
      })
    }

    let resolve = result => {if(this.resoveFnArr.length){change('resolved', result)
        return 
      }
      let delayTimer = setTimeout(() => {change('resolved', result)
        clearTimeout(delayTimer)
      }, 0)
    }
    let reject = resason => {if(this.resoveFnArr.length){change('rejected', resason)
        return
      }
      let delayTimer = setTimeout(() => {change('resolved', result)
        clearTimeout(delayTimer)
      }, 0)
    }
    // 每一次 new Promise 都会执行 executor 函数 
    try{executor(resolve, reject);
    } catch(err){reject(err);
    }
  }
  then(resolveFn, rejectFn){
    // 每一次执行 then 都会返回一个新的 promise 实例
    // this.resoveFnArr.push(resolveFn);
    // this.rejectFnArr.push(rejectFn);

    // 如果传递的参数不是函数(null/ 或者不传递),咱们让胜利或者失败传递顺延
    if(typeof resoveFn !== 'function'){resolveFn = (result) => {return result;}
    }
    if(typeof rejectFn !== 'function'){rejectFn = (reason) => {return MyPromise.reject(reason);
      }
    }
    return new MyPromise((resolve, reject) => {
      // 执行 resolve/reject 决定新的实例是胜利还是失败的 
      // 只有执行新实例的 executor 函数中的 resolve/reject 就晓得新的实例是胜利的还是失败的
      this.resoveFnArr.push((result) => {
       try{
         // 不报错,则承受办法的返回后果,会依据后果判断胜利还是失败
        let x = resolveFn(result);
        console.log('设置 then 执行的数据', x , x instanceof MyPromise)
        if(x instanceof MyPromise){x.then(resolve, reject);
          return
        }
        resolve(x);
      } catch(err){
        // 执行报错代表新实例是失败的
        reject(err)
      }
      });
      this.rejectFnArr.push((reason) => {
        try{
           // 不报错,则承受办法的返回后果,会依据后果判断胜利还是失败
          let x = rejectFn(reason);
          if(x instanceof MyPromise){x.then(resolve, reject);
            return 
          }
          resolve(x);
        }catch(err){
          // 执行报错代表新实例是失败的
          reject(err)
        }
      });
    })
  }
  // MyPromise.prototype.catch(fn) === MyPromise.prototye.then(null, fn)
  catch(rejectFn){return this.then(null, rejectFn);
  }
  // 静态方法
  static resolve(result){return new MyPromise((resolve, reject) => {resolve(result);
    })
  }
  static reject(reason){return new MyPromise((resolve, reject)=> {reject(reason);
    })
  }
  static all(arr){return new MyPromise((resolve,reject) => { 
      let index = 0;
      let results = [];
      for(let i = 0; i < arr.length; i++){let item = arr[i];
        if(!(item instanceof MyPromise)) continue;
        item.then( result => {
          index++;
          results[i] = result;
          if(index === arr.length){resolve(results);
          }
        }).catch(reason => {reject(reason)
        })
      }
    })
  }
}

正文完
 0