最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 手写instanceof、深拷贝、new、apply、bind、softBind、JSON.Stringify

    正文概述 掘金(miniYM)   2021-03-07   436

    实现instanceof

    function myInstanceof(left,right){ 
      // 如果是基础类型直接返回false 
      if(typeof left !== 'object' && typeof left == null) return false;
      // Object.getPrototypeOf() 方法返回指定对象的原型(内部[[Prototype]]属性的值)
      let proto = Object.getPrototypeOf(left);
      while(true){
        if(!proto) return false;
        if(proto == right.prototype) return true;
          proto =  Object.getPrototypeOf(proto);
        }
    }
    

    实现深拷贝

    手写instanceof、深拷贝、new、apply、bind、softBind、JSON.Stringify

    function deepClone(obj,map = new Map()){
      if(obj instanceof Object){
        if(obj instanceof Function) return obj;
        if(obj instanceof Date) return new Date(obj);
        if(obj instanceof RegExp) return new RegExp(obj);
        // 解决循环引用
        if(map.has(obj)) return map.get(obj);
        // 拷贝原型链
        let allDesc = Object.getOwnPropertyDescriptors(target);
        let cloneObj = Object.create(Object.getPrototypeOf(target), allDesc);
        map.set(obj,cloneObj);
        // Reflect.ownKeys可以拿到不可枚举属性和symbol类型的键名
        for(let key of Reflect.ownKeys(obj)){
          cloneObj[key] = deepClone(obj[key],map);
        }
        return cloneObj
      }else{
        return obj;
      }
    }
    

    实现new

    function myNew(ctor,...args){
      if(typeof ctor !=='function'){
        throw 'ctor must be function';
      } 
      // 创建一个新对象
      let obj = Object.create(ctor.prototype);
      // 改变this指向,执行构造函数中的代码,
      let res = ctor.apply(obj,[...args]);
      let isObject = typeof res === 'object'&& typeof res !== null;
      let isFunction = typeof res == 'function';
      // 返回新对象
      return isObject || isFunction? res : obj;
    }
    

    实现apply

    Function.prototype.myApply =function(context = window,args){
      // 利用symbol声明唯一变量
      let fn = Symbol('fn')
      // 为context绑定当前的方法,改变this指向
      context[fn] = this;
      // 执行当前的方法
      var result = context[fn](args);
      delete context.fn;
      return result;
    }
    

    实现bind

    Function.prototype.myBind =function(context = window,...args){
      var self = this;
      var fbound = function(...args1){
        return self.apply(context,[...args,...args1]);
      }
      fbound.prototype = Object.create(this.prototype);
      // 返回一个函数
      return fbound;
    }
    

    实现softBind

    为什么需要softBind,让我们一同来看一个例子。 手写instanceof、深拷贝、new、apply、bind、softBind、JSON.Stringify 我们可以看到bind之后,无法通过call来再次改变this的指向。我们想要输出c的value,但是却依旧输出的是b的value。为了解决以上问题我们要实现一种软绑定。
    那如何更改this呢?如何区分直接调用还是通过call这两种情况呢?我们分析可以得到两种情况:

    1. fn直接执行的时候,this指向的window
    2. 调用fn.call的时候,this指向call的第一个参数,
    Function.prototype.softBind = function(context = window,...args){
      var self = this;
      var fbound = function(...args1){ 
        //此行逻辑是重点!结合上述分析可分析出原因
        var _context = (!this||this==(window || global))?context:this;
        return self.apply(_context,[...args,...args1]);
      }
      fbound.prototype = Object.create(this.prototype);
      return fbound;
    }
    

    实现JSON.Stringify

    看一下MDN上对规则的描述: 手写instanceof、深拷贝、new、apply、bind、softBind、JSON.Stringify

    function jsonStringify(data){
      let result = '';
      var type = typeof data;
      if(type !== 'object' || data === null ){
        // 基础类型在此处理
        result = data;
        if(type == 'number' &&(Number.isNaN(data) || !Number.isFinite(data))){
          // 规则8:NaN 和 Infinity格式的数值会被当做 null。
          result = "null";
        }else if(type == 'function' || type == 'undefined' || type == 'symbol'){
          // 规则4:函数、undefined 被单独转换时,会返回 undefined,
          result = "undefined";
        }else if(type == 'string'){
          result = `"${data}"`
        }
        result = String(result);
      }else{
        if(data.toJSON && typeof data.toJSON =='function'){
          //规则1:转换值如果有 toJSON() 方法,该方法定义什么值将被序列化。
          result+=jsonStringify(data.toJSON())
        }else if(data instanceof Array){
          result = [];
          data.forEach((item,index)=>{
            let itemType = typeof item;
            // 规则4:undefined、任意的函数以及 symbol 值,出现在数组中时,被转换成 null
            if(itemType == 'undefined' || itemType =='function' || itemType =='symbol'){
              result[index]="null";
            }else{
              result[index]=jsonStringify(item);
            }
          })
          result = `[${result}]`
        }else{
          result = [];
          Object.keys(data).forEach((item,index)=>{
            // 规则6:所有以 symbol 为属性键的属性都会被完全忽略掉,Object.keys返回包括对象自身的(不含继承的)所有可枚举属性(不含 Symbol 属性)的键名。
            let valueType = typeof data[item];
            if(valueType == 'undefined' || valueType =='function' || valueType =='symbol'){
              // 规则4:undefined、任意的函数以及 symbol 值,在序列化过程中会被忽略(出现在非数组对象的属性值中时)
            }else if(data[item] == data){
              // 规则5:对包含循环引用的对象(对象之间相互引用,形成无限循环)执行此方法,会抛出错误。
              throw "cycling";
            }else{
              result.push(`"${item}":${jsonStringify(data[item])}`);
            }
          })
          result = `{${result}}`
        }
      }
      return result;
    }
    

    起源地下载网 » 手写instanceof、深拷贝、new、apply、bind、softBind、JSON.Stringify

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元