侧边栏壁纸
  • 累计撰写 29 篇文章
  • 累计收到 1 条评论

前端常见的手写

admin
2022-07-08 / 0 评论 / 24 阅读 / 正在检测是否收录...

call:

Function.prototype.myCall = function(context){
  let context = context || window
  context.fn = this
  let args = [...arguments].slice(1)
  let result = args.length > 0 ? context.fn(...args) : context.fn()
  delete context.fn
  return result
}

apply:

Function.prototype.myApply = function(context){
  let context = context || window
  context.fn = this
  let args = [...arguments].slice(1)
  let result = args.length > 0 ? context.fn(args) : context.fn()
  delete context.fn
  return result
}

bind

Function.prototype.myBind = function(context){
  let fn = this
  let args = [...arguments].slice(1)
  return function newFn(...newFnArgs){
    if(this instanceOf newFn){
      return new fn(...args,...newFnArgs)
    }
    return fn.apply(context,[...args,...newFnArgs])
  }
}

new的过程

function ctor(){
  ...
}
function myNew(ctor,...args){
  if(typeOf ctor !== 'function'){
    throw 'error'
  }
  let newObj = Object.creat(ctor.prototype)
  let result = ctor.apply(newObj,args)
  let isObject = typeOf result === 'object' && result !==null
  let isFunction = typeOf result === 'function'
  if(isObject || isFunction){
    return result
  }
  return newObj
}

继承

// 父类
function Animal(name){
  this.name = name
  this.sleep = function(){
    console.log('sleep')
  }
}
animal.prototype.eat = function(){
  console.log('eat')
}
//原型链继承  --将父类的实例作为子类的原型
//实例是子类的实例,也是父类的实例,父类新增原型上的属性可以访问到
//缺点:给子类新增属性和方法要在子类构造函数中。无法多继承。原型对象的属性被实例共享。创建子类实例时,无法向父类构造函数传参

function Cat(){
}
cat.protytype = new Animal()
cat.protytype.name = 'cat'

let cat = new Cat()


//构造继承--使用父类构造函数来增强子类实例,等于说复制父类实例属性给子类
// 解决了共享属性的问题,创建子类实例可以给父类传参数,可以多继承
// 缺点:实例并不是父类的实例,仅仅是子类的。不能继承父类原型属性和方法,无法复用,每个子类都有父类实例函数的副本,影响性能
function Cat(name){
  Animal.call(this)
  this.name = name
}
// 实例继承---为父类实例添加新特性,作为实例子类返回
// 不限制调用方式,不管是new 子类()还是子类(),返回的对象具有相同的效果
// 缺点:实例是父类的实例,不是子类的实例,不能多继承
function Cat(name){
  let instance = new Animal()
  instance.name = name
  return instance
}


// 拷贝继承
// 可以多继承
// 效率低,因为拷贝。无法获取父类不可枚举的属性
function Cat(name){
  var animal = new Animal();
  for(let p in animal){
     Cat.prototype[p] = animal[p];
  }
  this.name = name || 'Tom';
}

// 组合继承---通过调用父类构造,继承父类的属性并保留传参的优点,然后通过将父类实例作为子类原型,实现函数复用
// 实例与原型属性方法都可以继承、既是子类的实例,也是父类的实例、无属性共享、可传参、可复用
// 缺点: 调用了两次父类构造函数,生成了两份实例(子类实例将子类原型上的那份屏蔽了)
function Cat(name){
  Animal.call(this)
  this.name = name
}
Cat.prototype = new Animal()
// 组合继承需要修复构造函数指向
Cat.prototype.constructor = Cat;


// 寄生组合继承---通过寄生方式,砍掉父类的实例属性,这样,在调用两次父类的构造的时候,就不会初始化两次实例方法/属性,避免的组合继承的缺点
// 完美,没有缺点
function Cat(name){
  Animal.call(this)
  this.name = name
}
(function(){
  // 创建一个没有实例方法的类
  var Super = function(){};
  Super.prototype = Animal.prototype;
  //将实例作为子类的原型
  Cat.prototype = new Super();
})


// ES6继承
//class 相当于es5中构造函数
//class中定义方法时,前后不能加function,全部定义在class的protopyte属性中
//class中定义的所有方法是不可枚举的
//class中只能定义方法,不能定义对象,变量等
//class和方法内默认都是严格模式
//es5中constructor为隐式属性
class People{
  constructor(name='wang',age='27'){
    this.name = name;
    this.age = age;
  }
  eat(){
    console.log(`${this.name} ${this.age} eat food`)
  }
}
// 子类
class Woman extends People{ 
   constructor(name = 'ren',age = '27'){ 
     //继承父类属性
     super(name, age); 
   } 
    eat(){ 
     //继承父类方法
      super.eat() 
    } 
} 
let wonmanObj=new Woman('xiaoxiami'); 

Object.create()

Object.myCreate(obj){
  function fn(){}
  fn.prototype = obj
  return new fn()
}

instanceOf()
ps:关于原型链的一个知识点, Object和Function的构造函数都是Function,所以他们两个的__proto__都指向Function.prototype。特殊点在于Function是实例也是对象。
所有对象原型链的终点都是Object.prototype

// 判断A是否是B的实例--A instanceof B
// 不能检测基本数据类型,在原型链上的结果未必准确,不能检测null,undefined
function myInstanceOf(a,b){
  let left = a.__proto__
  let right = b.prototype
  while(true){
    if(left === null){
      return false
    }
    if(left === right){
      return true
    }
    left = left.__proto__
  }
}

Object.assign()

// 该方法用于将所有可枚举属性的值从一个或多个源对象(sources)分配到目标对象(target),并返回目标对象。是浅拷贝,继承的属性也不可以复制。属性名冲突时以后面的参数为准,异常也会打断后续的拷贝任务
// 如果想要深拷贝可以let obj = Object.assign(obj2,JSON.parse(JSON.stringify(obj1)));
Object.myAssign = function(target,...source){
  if(target === null){
    throw new error('error')
  }
  // 将target转换为对象(避免基本数据类型不是对象)
  let ret = Object(target)
  source.forEach(function(obj){
    if(obj !== null){
      for(let key in obj){
        // hasOwnProperty --查找obj是否有key这个属性,不去原型上找
        // 由于in运算符会查找原型身上的可枚举属性,所以需要hasOwnProperty过滤
        if(obj.hasOwnProperty(key)){
          ret[key] = obj[key]
        }
      }
    }
  })
  return ret
}

AJAX

function myAjax(url,method,body,headers){
  return new Promise((resolve,reject) => {
    // XMLHttpRequest用于发送请求,有一些参数可选
    let req = new XMLHttpRequest();
    req.open(method,url)
    for(let key in headers){
      req.setRequestHeader(key,headers[key])
    }
    req.onreadystatechange(() => {
      if(req.readystate === 4){
        if(req.status >= '200' && req.status <= 300){
          resolve(req.responeText)
        }else{
          reject(req)
        }
      }
    })
    req.send(body)
  })
}
0

评论 (0)

取消