笔试题

作者: Shiki_思清 | 来源:发表于2021-11-26 00:42 被阅读0次

实现一个new的伪代码

function _new(){
  let obj = new Object();
  let Con = [].shift.call(arguments);
  obj.__proto__ = Con.prototype;
  let result = Con.apply(obj,arguments);
  return typeof result === 'object' ? result : obj
}

深拷贝和浅拷贝

    // ----------------------------------------------浅拷贝
    // 只是把对象的属性和属性值拷贝到另一个对象中
    var obj1 = {
      a: {
        a1: { a2: 1 },
        a10: { a11: 123, a111: { a1111: 123123 } }
      },
      b: 123,
      c: "123"
    }
    // 方式1
    function shallowClone1(o) {
      let obj = {}

      for (let i in o) {
        obj[i] = o[i]
      }
      return obj
    }

    // 方式2
    var shallowObj2 = { ...obj1 }

    // 方式3
    var shallowObj3 = Object.assign({}, obj1)

    let shallowObj = shallowClone1(obj1);

    shallowObj.a.a1 = 999
    shallowObj.b = true

    console.log(obj1);  //第一层的没有被改变,一层以下就被改变了



    // ----------------------------------------------深拷贝

    // 简易版  
    function deepClone(o) {
      let obj = {}
      for (var i in o) {
        // if(o.hasOwnProperty(i)){
        if (typeof o[i] === "object") {
          obj[i] = deepClone(o[i])
        } else {
          obj[i] = o[i]
        }
        // }
      }
      return obj
    }


    var myObj = {
      a: {
        a1: { a2: 1 },
        a10: { a11: 123, a111: { a1111: 123123 } }
      },
      b: 123,
      c: "123"
    }

    var deepObj1 = deepClone(myObj)
    deepObj1.a.a1 = 999
    deepObj1.b = false
    console.log(myObj);



    // 简易版存在的问题:参数没有做检验,传入的可能是 Array、null、regExp、Date
    function deepClone2(o) {
      if (Object.prototype.toString.call(o) === "[object Object]") {  //检测是否为对象
        let obj = {}
        for (var i in o) {
          if (o.hasOwnProperty(i)) {
            if (typeof o[i] === "object") {
              obj[i] = deepClone(o[i])
            } else {
              obj[i] = o[i]
            }
          }
        }
        return obj
      } else {
        return o
      }
    }

    function isObject(o) {
      return Object.prototype.toString.call(o) === "[object Object]" || Object.prototype.toString.call(o) === "[object Array]"
    }

    // 继续升级,没有考虑到数组,以及ES6中的map、set、weakset、weakmap
    function deepClone3(o) {
      if (isObject(o)) {//检测是否为对象或者数组
        let obj = Array.isArray(o) ? [] : {}
        for (let i in o) {
          if (isObject(o[i])) {
            obj[i] = deepClone(o[i])
          } else {
            obj[i] = o[i]
          }
        }
        return obj
      } else {
        return o
      }
    }


    // 有可能碰到循环引用问题  var a = {}; a.a = a; clone(a);//会造成一个死循环
    // 循环检测
    // 继续升级
    function deepClone4(o, hash = new map()) {
      if (!isObject(o)) return o//检测是否为对象或者数组
      if (hash.has(o)) return hash.get(o)
      let obj = Array.isArray(o) ? [] : {}

      hash.set(o, obj)
      for (let i in o) {
        if (isObject(o[i])) {
          obj[i] = deepClone4(o[i], hash)
        } else {
          obj[i] = o[i]
        }
      }
      return obj
    }

    // 递归易出现爆栈问题
    //  将递归改为循环,就不会出现爆栈问题了
    var a1 = { a: 1, b: 2, c: { c1: 3, c2: { c21: 4, c22: 5 } }, d: 'asd' };
    var b1 = { b: { c: { d: 1 } } }
    function cloneLoop(x) {
      const root = {};
      // 栈 
      const loopList = [  //->[]->[{parent:{a:1,b:2},key:c,data:{ c1: 3, c2: { c21: 4, c22: 5 } }}]
        {
          parent: root,
          key: undefined,
          data: x,
        }
      ];
      while (loopList.length) {
        // 深度优先
        const node = loopList.pop();
        const parent = node.parent; //{} //{a:1,b:2}
        const key = node.key; //undefined //c
        const data = node.data; //{ a: 1, b: 2, c: { c1: 3, c2: { c21: 4, c22: 5 } }, d: 'asd' }  //{ c1: 3, c2: { c21: 4, c22: 5 } }}
        // 初始化赋值目标,key 为 undefined 则拷贝到父元素,否则拷贝到子元素
        let res = parent; //{}->{a:1,b:2,d:'asd'} //{a:1,b:2}->{}
        if (typeof key !== 'undefined') {
          res = parent[key] = {};
        }
        for (let k in data) {
          if (data.hasOwnProperty(k)) {
            if (typeof data[k] === 'object') {
              // 下一次循环 
              loopList.push({
                parent: res,
                key: k,
                data: data[k],
              })
            } else {
              res[k] = data[k];
            }
          }
        }
      }
      return root
    }


    function deepClone5(o) {
      let result = {}
      let loopList = [
        {
          parent: result,
          key: undefined,
          data: o
        }
      ]

      while (loopList.length) {
        let node = loopList.pop()
        let { parent, key, data } = node
        let anoPar = parent
        if (typeof key !== 'undefined') {
          anoPar = parent[key] = {}
        }

        for (let i in data) {
          if (typeof data[i] === 'object') {
            loopList.push({
              parent: anoPar,
              key: i,
              data: data[i]
            })
          } else {
            anoPar[i] = data[i]
          }
        }
      }
      return result
    }


    let cloneA1 = deepClone5(a1)
    cloneA1.c.c2.c22 = 5555555
    console.log(a1);
    console.log(cloneA1);


    // ------------------------------------------JSON.stringify()实现深拷贝

    function cloneJson(o) {
      return JSON.parse(JSON.stringify(o))
    }

    // let obj = { a: { c: 1 }, b: {} };
    // obj.b = obj;
    // console.log(JSON.parse(JSON.stringify(obj))) // 报错 // Converting circular structure to JSON

    

防抖节流

    // ---------------------------------------------------------防抖函数
    function debounce(func, delay) {
      let timeout
      return function () {
        let arg = arguments
        if (timeout) clearTimeout(timeout)
        timeout = setTimeout(() => {
          func(arg)
        }, delay);
      }
    }

    // ---------------------------------------------------------立即执行防抖函数
    function debounce2(fn, delay) {
      let timer

      return function () {
        let args = arguments
        if (timer) clearTimeout(timer)


        let callNow = !timer
        timer = setTimeout(() => {
          timer = null
        }, delay);
        if (callNow) { fn(args) }
      }
    }
    // ---------------------------------------------------------立即执行防抖函数+普通防抖
    function debounce3(fn, delay, immediate) {
      let timer

      return function () {
        let args = arguments
        let _this = this
        if (timer) clearTimeout(timer)

        if (immediate) {
          let callNow = !timer
          timer = setTimeout(() => {
            timer = null
          }, delay);

          if (callNow) { fn.apply(_this, args) }
        } else {
          timeout = setTimeout(() => {
            func.apply(_this, arguments)
          }, delay);
        }
      }
    }

    // ---------------------------------------------------------节流 ,时间戳版

    function throttle(fn, wait) {

      let previous = 0
      return function () {
        let now = Date.now()
        let _this = this
        let args = arguments
        if (now - previous > wait) {
          fn.apply(_this, arguments)
          previous = now
        }
      }
    }

    // ---------------------------------------------------------节流 ,定时器版
    function throttle2(fn, wait) {
      let timer
      return function () {
        let _this = this
        let args = arguments
        if (!timer) {
          timer = setTimeout(() => {
            timer = null
            fn.apply(_this, arguments)
          }, wait);
        }
      }
    }

call

    Function.prototype.myCall = function (context) {
      // 先判断调用myCall是不是一个函数
      // 这里的this就是调用myCall的
      if (typeof this !== 'function') {
        throw new TypeError("Not a Function")
      }

      // 不传参数默认为window
      context = context || window

      // 保存this
      context.fn = this

      // 保存参数
      let args = Array.from(arguments).slice(1)   //Array.from 把伪数组对象转为数组

      // 调用函数
      let result = context.fn(...args)

      delete context.fn

      return result

    }

apply

Function.prototype.myApply = function (context) {
      // 判断this是不是函数
      if (typeof this !== "function") {
        throw new TypeError("Not a Function")
      }

      let result

      // 默认是window
      context = context || window

      // 保存this
      context.fn = this

      // 是否传参
      if (arguments[1]) {
        result = context.fn(...arguments[1])
      } else {
        result = context.fn()
      }
      delete context.fn

      return result
    }

bind

    Function.prototype.myBind = function(context){
      // 判断是否是一个函数
      if(typeof this !== "function") {
        throw new TypeError("Not a Function")
      }
      // 保存调用bind的函数
      const _this = this 
      // 保存参数
      const args = Array.prototype.slice.call(arguments,1)
      // 返回一个函数
      return function F () {
        // 判断是不是new出来的
        if(this instanceof F) {
          // 如果是new出来的
          // 返回一个空对象,且使创建出来的实例的__proto__指向_this的prototype,且完成函数柯里化
          return new _this(...args,...arguments)
        }else{
          // 如果不是new出来的改变this指向,且完成函数柯里化
          return _this.apply(context,args.concat(...arguments))
        }
      } 
    }

原型继承

var person = {
      friends: ["a", "b", "c", "d"]
    }

    var p1 = Object.create(person)

    p1.friends.push("aaa")//缺点:子类的实例共享了父类构造函数的引用属性

    console.log(p1);
    console.log(person);//缺点:子类的实例共享了父类构造函数的引用属性

组合继承

function Father(name) {
      this.name = name
      this.hobby = ["篮球", "足球", "乒乓球"]
    }

    Father.prototype.getName = function () {
      console.log(this.name);
    }

    function Son(name, age) {
      Father.call(this, name)
      this.age = age
    }

    Son.prototype = new Father()
    Son.prototype.constructor = Son


    var s = new Son("ming", 20)

寄生组合继承

    function Father(name) {
      this.name = name
      this.hobby = ["篮球", "足球", "乒乓球"]
    }

    Father.prototype.getName = function () {
      console.log(this.name);
    }

    function Son(name, age) {
      Father.call(this, name)
      this.age = age
    }

    Son.prototype = Object.create(Father.prototype)
    Son.prototype.constructor = Son

    var s2 = new Son("ming", 18)

相关文章

网友评论

      本文标题:笔试题

      本文链接:https://www.haomeiwen.com/subject/huhtxrtx.html