我的一些手写js系列

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)
        })
      }
    })
  }
}

你可能感兴趣的:(javascript)