当前位置: 首页 > news >正文

20230508----重返学习-call()与bind()重写-JS中数据类型检测汇总-装箱与拆箱-类的多种继承方案

day-065-sixty-five-20230508-call()与bind()重写-JS中数据类型检测汇总-装箱与拆箱-类的多种继承方案

call()与bind()重写

call()重写

  • call()的作用例子

    let obj = {name: '珠峰培训'
    }
    const fn = function fn(x, y, ev) {console.log(this, x, y, ev)return x + y
    }
    let res = fn.call(obj, 10, 20)
    console.log(res)
    
  • 自定义call()基本原理

    let obj = {name: "珠峰培训",
    };
    const fn = function fn(x, y, ev) {console.log(this, x, y, ev);return x + y;
    };
    // 需求:把fn执行,传递10、20,并且让函数中的this指向obj
    /* //不行的操作
    // console.log(fn(10, 20)) //this:window  x:10  y:20  ->30
    // console.log(obj.fn(10, 20)) //Uncaught TypeError: obj.fn is not a function  obj此时和fn没有任何的关系,obj.fn->undefined 
    */
    // call的基本原理
    obj.fn = fn
    console.log(obj.fn(10, 20))  //手动让obj和fn有关系 
    
  • 自定义call()需求

    let obj = {name: "珠峰培训",
    };
    const fn = function fn(x, y, ev) {console.log(this, x, y, ev);return x + y;
    };
    // 需求:把fn执行,传递10、20,并且让函数中的this指向obj
    let res = fn.call(obj, 10, 20);
    console.log(res);
    res = fn.apply(obj, [10, 20]);
    console.log(res);
    
  • fn.call()的处理步骤

    1. fn()这个函数,首先基于__proto__找到Function.prototype.call()这个方法

    2. 把找到的call()方法执行

      • call()内部可以访问到的值
        • this:fn
        • context:obj
        • params:[10,20]
      Function.prototype.call = function call(context, ...params) {// this:fn「需要改变this指向的函数」// context:obj「需要改变的this指向」// params:[10,20] 「需要传递给fn函数的实参」context.AAA = this; // obj.AAA = fnlet result = context.AAA(...params); // obj.AAA(10,20)delete context.AAA; // delete obj.AAAreturn result;
      };
      
    3. 而在call()方法内部:把fn()执行,把它里面的this改为obj,并且为其传递了10与20这些入参,接收它的返回值并作为call函数执行的返回值

  • 简洁初步版

    Function.prototype.call = function call(context, ...params) {// this:fn「需要改变this指向的函数」// context:obj「需要改变的this指向」// params:[10,20] 「需要传递给fn函数的实参」context.AAA = this; // obj.AAA = fnlet result = context.AAA(...params); // obj.AAA(10,20)delete context.AAA; // delete obj.AAAreturn result;
    };
    
  • 初步完善版

    Function.prototype.call = function call(context, ...params) {//如果context传递的是null/undefined,则让函数中的this指向window对象if (context == null){ context = window;} //如果传递的context值是原始值类型,是无法为其设置成员的,此时我们需要把其转换为对象类型「非标准特殊对象」if (!/^(object|function)$/.test(typeof context)){ context = Object(context);} let result,key = Symbol("KEY"); //保证给对象新增的成员不会和对象以往的成员有冲突context[key] = this;result = context[key](...params);delete context[key]; //临时设置的这个成员仅仅是为了把函数执行,可以改变其内部的this,用完后需要移除return result;
    };
    

bind()重写

  • 需求

    let obj = {name: "珠峰培训",
    };
    const fn = function fn(x, y, ev) {console.log(this, x, y, ev);return x + y;
    };
    // 需求:点击BODY执行fn,让fn中的this指向obj,传递给fn函数10/20,包括事件对象也作为最后一个参数传递给fn
    /* //不行的操作:
    // document.body.onclick = fn //点BODY才会执行fn -> this:document.body  x:事件对象  y:undefined
    // document.body.onclick = fn.call(obj, 10, 20) //还不等到点击就把fn执行了,虽然this和参数都改了,但是ev事件对象没有,它相当于先把fn执行,把执行的结果“30”赋值给点击事件...
    */
    
  • bind基本原理

    let obj = {name: "珠峰培训",
    };
    const fn = function fn(x, y, ev) {console.log(this, x, y, ev);return x + y;
    };
    // 需求:点击BODY执行fn,让fn中的this指向obj,传递给fn函数10/20,包括事件对象也作为最后一个参数传递给fn
    document.body.onclick = function (ev) {// this:document.body  ev:事件对象// 在此函数执行的时候,再把我们真正需要执行的函数fn执行return fn.call(obj, 10, 20, ev);
    };
    
    • 用bind解决

      let obj = {name: "珠峰培训",
      };
      const fn = function fn(x, y, ev) {console.log(this, x, y, ev);return x + y;
      };
      // 需求:点击BODY执行fn,让fn中的this指向obj,传递给fn函数10/20,包括事件对象也作为最后一个参数传递给fn
      document.body.onclick = fn.bind(obj, 10, 20);
      /*
      document.body.onclick = function anonymous(ev) { ... }
      //当点击的时候,先把bind返回的匿名函数执行
      */
      
  • 简洁初步版

    Function.prototype.bind = function bind(context, ...params) {// this:fn  context:obj  params:[10,20]let self = thisreturn function anonymous(ev) {// this:document.body  ev:事件对象// 目的:把fn执行,改变其this指向,并且传递一个个的实参params.push(ev)return self.call(context, ...params)}
    }
    
    • 使用例子

      let obj = {name: "珠峰培训",
      };
      const fn = function fn(x, y, ev) {console.log(this, x, y, ev);return x + y;
      };Function.prototype.bind = function bind(context, ...params) {// this:fn  context:obj  params:[10,20]let self = this;return function anonymous(ev) {// this:document.body  ev:事件对象// 目的:把fn执行,改变其this指向,并且传递一个个的实参params.push(ev);return self.call(context, ...params);};
      };
      document.body.onclick = fn.bind(obj, 10, 20);
      
  • 初步完善版

    Function.prototype.bind = function bind(context, ...params) {let self = thisreturn function anonymous(...args) {return self.call(context, ...params.concat(args))}
    }
    
    • 使用例子

      let obj = {name: "珠峰培训",
      };
      const fn = function fn(x, y, ev) {console.log(this, x, y, ev);return x + y;
      };Function.prototype.bind = function bind(context, ...params) {let self = this;return function anonymous(...args) {return self.call(context, ...params.concat(args));};
      };
      document.body.onclick = fn.bind(obj, 10, 20);
      
  • for-if版-最简基础版

    Function.prototype.bind = function bind(context, ...params) {let self = thisreturn function anonymous(...args) {return self.call(context, ...params,...args)}
    }
    
    const bind = function bind(callback, context, ...params) {let self = callback;return function anonymous(...args) {//return self.call(context, ...params,...args)//连call()也不用// 自己手动实现call(),用原生的可以替代,但为了最基础原理,直接集合在这。if (/^(object|function)$/.test(typeof context)) {context = window; //undefined//严格模式下}if (typeof context !== "object") {context = Object(context);}let key = Symbol("call-key");let hasProto = false;let theContextProto = Object.getPrototypeOf(context);if (typeof theContextProto === "object") {hasProto = true;} else {Object.setPrototypeOf(context,{});}theContextProto[key] = self;let res = context[key](...params, ...args);if (hasProto) {delete theContextProto[key];} else {Object.setPrototypeOf(context,null);}return res;};
    };Function.prototype.bind = function (context, ...params) {bind(this, context, ...params);
    };
    

JS中数据类型检测汇总

  • JS中数据类型检测汇总
    1. typeof [value]

      • 返回值:首先是一个字符串,其次字符串中包含了对应的数据类型

        • number

        • object

        • function

        • 所以两个及两个以上的typeof所得的值必定为字符串string

          console.log(typeof typeof typeof [10, 20]) //"string"
          
      • 特点

        • typeof null //--> "object"
        • 不能细分对象:基于typeof检测对象的时候,除了函数会返回function,其余的都返回object
        • 基于typrof检测一个未被声明的变量,不会报错,结果是undefined
          • 不过暂时性死区除外,依旧会报错。
      • 原理

        • typeof在检测数据类型的时候,是按照数据值在计算机底层存储的二进制值,进行检测的!
          • 其中,如果二进制值的前三位是零,便都被识别为对象。
            • 然后再看此对象是否具备call方法,
              • 具备call方法则返回function,说明其是一个函数
              • 不具备的返回object,说明其是其它对象
          • 而null在计算机底层的二进制值都是零,也就是前三位也是零,所以 typeof null 的结果是 “object” !
      • 应用

        • 检测除null之外的原始值类型
          • typeof用起来方便,而且性能还好
        • 判断兼容性
          • 查看如Promise是否存在
        • 笼统检测是否为对象
    2. 对象 instanceof 构造函数

      • 原本的意义是用来检测某个对象是否是相应类的实例

        • 只不过针对于这个特点,可以用其检测一些数据类型
          • 检测是否为数组:值 instanceof Array
          • 检测是否为正则:值 instanceof RegExp //RegExp是Regular Expressions的简写
        • 也就是基于instanceof,可以弥补typeof不能细分对象的缺陷!
      • 特点:

        • 无法检测原始值类型,返回结果都是false

          • 原因:基于instanceof进行操作,不会对原始值类型进行装箱
            • 10 instanceof Number -> false
        • 原本不是检测数据类型的,现在非要让其检测类型,所以检测的结果不一定精准

          const Fn = function Fn() {this.x = 10;
          };
          Fn.prototype = new Array();
          Fn.prototype.name = "Fn";
          let f = new Fn();
          // f.__proto__ -> Fn.prototype -> Array.prototype -> Object.prototype
          console.log(f instanceof Fn); //true
          console.log(f instanceof Object); //true
          console.log(f instanceof Array); //true//虽然也因为原型链的关系值是true,但f连length这个属性都没有,强行使用Array的方法可能会报错。
          console.log(f instanceof RegExp); //false
          console.log(f);
          
      • 原理:

        • 首先看 构造函数Ctor 是否具备Symbol.hasInstance这个属性

          • 具备:CtorSymbol.hasInstance
          • 不具备:依次查找对象的原型链__proto__,一直到Object.prototype,在此过程中,如果构造函数prototype出现在了其原型链的某个环节,则说明当前对象是此构造函数的一个实例,检测结果就是true!
            • 直接Symbol.hasInstance得用ES6中class类写法中的static关键字并在class中声明

              class Fn {constructor(name) {if (name) this.name = name;}// 设置其静态私有属性方法「这样重写会生效」static [Symbol.hasInstance](obj) {//这里可以针对一些特定属性进行检测,进而让符合条件的才表示是该构造函数类的实例。return obj.hasOwnProperty("name");}
              }
              let f1 = new Fn();
              let f2 = new Fn("珠峰");
              console.log(f1 instanceof Fn); //false   Fn[Symbol.hasInstance](f1)
              console.log(f2 instanceof Fn); //true   Fn[Symbol.hasInstance](f2)
              
              • 直接用ES5的方法设置是不行的。

                // 正常情况下,直接这样重写 Symbol.hasInstance 是不会生效的
                Array[Symbol.hasInstance] = function (obj) {console.log("AAA");
                };
                const Fn = function Fn() {};
                Fn.prototype = new Array();
                Fn.prototype.constructor = Fn;
                let f = new Fn();
                console.log(f);
                console.log(f instanceof Array); //true  等价于 Array[Symbol.hasInstance](f)
                
        • 在支持ES6的浏览器中,Function.prototype上具备Symbol.hasInstance方法,所以只要是函数,也都具备这个方法!

          arr instanceof Array //--> Array[Symbol.hasInstance](arr)
          
          /*
          _instanceof:对内置 instanceof 运算符的重写@paramsobj:要检测的对象Ctor:要被检测的构造函数@return布尔值
          */
          const _instanceof = function _instanceof(obj, Ctor) {// 必须保证Ctor得是一个函数if (typeof Ctor !== "function") {throw new TypeError(`Right-hand side of 'instanceof' is not callable`);}// instanceof无法检测原始值类型if (obj == null || !/^(object|function)$/.test(typeof obj)) {return false;}// Ctor这个函数必须具备prototypeif (!Ctor.prototype) {throw new TypeError(`Function has non-object prototype 'undefined' in instanceof check`);}if (Ctor[Symbol.hasInstance]) {// 具备 Symbol.hasInstance 的构造函数,则直接基于这个方法执行去进行校验即可return Ctor[Symbol.hasInstance](obj);}let proto = Object.getPrototypeOf(obj); //获取对象的原型链,类似于 obj.__proto__// 一直找,直到找到尽头为止while (proto) {if (proto === Ctor.prototype) return true; //在查找中,如果出现了Ctor.prototype,说明对象是此构造函数的一个实例,返回true即可proto = Object.getPrototypeOf(proto); // 获取其原型对象的原型链}return false; //都找完也没有符合条件的,说明对象不是此构造函数的一个实例,直接返回false
          };
          let arr = [10, 20];
          console.log(_instanceof(arr, Array)); //true
          console.log(_instanceof(arr, Object)); //true
          console.log(_instanceof(arr, RegExp)); //false
          
    3. constructor

      • 获取对象的构造函数,从而判断是否是属于某一个数据类型。

        let arr = [10, 20];
        console.log(arr.constructor === Array); //true
        console.log(arr.constructor === Object); //false  如果一个对象的constructor等于Object,说明该对象的__proto__直接指向Object.prototype,也就是说明此对象是“标准普通对象”
        console.log(arr instanceof Array); //true
        console.log(arr instanceof Object); //true
        
        • 可以检测基本数据类型。

          let num = 10;
          console.log(num.constructor === Number); //true  支持原始值类型的检测,因为访问 constructor 属性的时候,原始值会默认的进行装箱
          
      • 只不过这种方式我们一般很少去使用。

        • 因为constructor值是可以被更改的。
          • 修改值的成本低,一但被更改,则检测结果是不准确的!比如可以设置一个私有属性叫constructor。
      • 不过这个可以让其与实例对象的原型上的constructor进行比较,进而让修改对象的成本变高,也更准确。

    4. Object.prototype.toString.call([value])

      • 不仅仅Object.prototype上有toString方法,在Number()/String()/Boolean()/Array()/Function()…等的原型对象上,也有toString方法。

        • 只不过其它原型上的toString方法都是用来转换为字符串的,只有Object.prototype.toString是用来检测数据类型的。

          let arr = [10, 20];
          console.log(arr.toString()); //"10,20"  使用的是Array.prototype.toString
          let obj = { x: 10, y: 20 };
          console.log(obj.toString()); //"[object Object]" 使用的是Object.prototype.toString
          
      • 把Object.prototype上的toString方法执行,让方法中的this指向要检测的数据值,这样就可以返回此数据值的数据类型 -> "[object ?]"

        const toString = Object.prototype.toString;
        let arr = [10, 20],obj = { x: 10, y: 20 };
        console.log(toString.call(arr)); //"[object Array]"
        console.log(toString.call(obj)); //"[object Object]"
        
        • 更简洁地使用

          let toString = Object.prototype.toString.call.bind(Object.prototype.toString)//不用call()来改指向this的指向了。
          toString(String())//'[object Null]'
          
      • 特点:

        • 精准且强大

          • 唯一不足就是写起来麻烦一点,相比于typeof。

          • "[object ?]"中的?在一般情况下,就是检测值所属的构造函数。

            • 例子

              const toString = Object.prototype.toString
              toString.call(null) //-> “[object Null]”  虽然Null不是构造函数,但是结果还是很准的
              toString.call(undefined) //-> “[object Undefined]”
              toString.call([]) //-> “[object Array]”
              toString.call(/\d+/) //-> “[object RegExp]”
              //...
              
            • 前提是内置的构造函数。

              function Fn() {}
              let f = new Fn();
              console.log(toString.call(f)); //"[object Object]"
              
          • 如果被检测的值具备Symbol.toStringTag这个属性,那么属性值是什么,最后检测结果"[object ?]"中的?就是什么。

            • 这个一般是自定义构造函数中来使用的,以便更像原始对象类型,可以让Object.toString()兼容。

              const toString = Object.prototype.toString;
              function Fn() {}
              Fn.prototype[Symbol.toStringTag] = "Fn";
              let f = new Fn();
              console.log(toString.call(f)); //"[object Fn]"
              
            • Promise.prototype上,具备Symbol.toStringTag这个属性,属性值是"Promise"

              let p = new Promise(()=>{})
              toString.call(p)// -> "[object Promise]"
              
        • 此办法虽然不错,但是也不是所有的数据类型检测都使用这个办法。

          • 一般来说:
            • 需要笼统地检测或者按照大的类别去检测,使用typeof会更方便。
            • 而需要很精准地检测的时候,使用toString会更好!
  • 快捷方法
    • isNaN 检测是否为有效数字
    • Array.isArray 检测是否为数组
  • 对象对象的笼统定义说明
    • 身上有键值对或理论上可以定义及设置、在保存之后依旧可以访问到的设置的键值对属性值的变量。

各种检测方法

  • 检测JavaScript内置的基础对象或包装对象的类型。

    // 检测JavaScript内置的基础对象或包装对象的类型。
    const toString = Object.prototype.toString;
    
  • 检测是否为数组。

    // 检测是否为数组。
    const isArray = Array.isArray;
    
  • 把函数转为字符串。

    // 把函数转为字符串。
    const fnToString = Function.prototype.toString;
    
  • 万能检测数据类型的方法;

    // 检测JavaScript内置的基础对象或包装对象的类型。
    const toString = Object.prototype.toString;
    // 检测是否为数组。
    const typeReg = /^(object|function)$/;// 万能检测数据类型的方法;
    //返回小写的入参的值类型字符串
    const isType = function isType(obj) {if (obj === null || obj === undefined) {return obj + "";}let type = typeof obj;let reg = /^\[object (\w+)\]$/;let res = type;if (typeReg.test(type)) {res = reg.exec(toString.call(obj))[1].toLowerCase(); //对象类型;}return res;
    };
    
  • 检测是否为对象。

    // 检测是否为对象
    const isObject = function isObject(obj) {return obj !== null && typeReg.test(typeof obj);
    };
    
  • 检测是否是window对象。

    // 检测是否是window对象
    const isWindow = function isWindow(obj) {return obj != null && obj === obj.window;
    };
    
  • 检测是否为函数。

    // 检测是否为函数
    const isFunction = function isFunction(obj) {return typeof obj === "function";
    };
    
  • 检测是否为数组或者伪数组。

    // 检测是否为数组。
    const isArray = Array.isArray;
    // 检测是否是window对象
    const isWindow = function isWindow(obj) {return obj != null && obj === obj.window;
    };// 检测是否为函数
    const isFunction = function isFunction(obj) {return typeof obj === "function";
    };
    // 检测是否为数组或者伪数组
    const isArrayLike = function isArrayLike(obj) {if (isArray(obj)) return true;let length = !!obj && "length" in obj && obj.length;if (isFunction(obj) || isWindow(obj)) return false;return (length === 0 ||(typeof length === "number" && length > 0 && length - 1 in obj));
    };
    
  • 检测是否为一个纯粹的对象(标准普通对象)。

    // 检测JavaScript内置的基础对象或包装对象的类型。
    const toString = Object.prototype.toString;
    // 检测是否为数组。
    const typeReg = /^(object|function)$/;// 把函数转为字符串。
    const fnToString = Function.prototype.toString;// 检测是否为函数
    const isFunction = function isFunction(obj) {return typeof obj === "function";
    };
    // 万能检测数据类型的方法;
    //返回小写的入参的值类型字符串
    const isType = function isType(obj) {if (obj === null || obj === undefined) {return obj + "";}let type = typeof obj;let reg = /^\[object (\w+)\]$/;let res = type;if (typeReg.test(type)) {res = reg.exec(toString.call(obj))[1].toLowerCase(); //对象类型;}return res;
    };
    // 检测是否为一个纯粹的对象(标准普通对象)
    const isPlainObject = function isPlainObject(obj) {if (isType(obj) !== "object") {return false;}let proto, Ctor;proto = Object.getPrototypeOf(obj);if (!proto) {return true; //匹配 Object.create(null) 这种情况}Ctor = proto.hasOwnProperty("constructor") && proto.constructor;return (isFunction(Ctor) && fnToString.call(Ctor) === fnToString.call(Object));
    };
    
  • 检测是否为空对象。

    // 检测是否为对象
    const isObject = function isObject(obj) {return obj !== null && typeReg.test(typeof obj);
    };
    // 检测是否为空对象
    const isEmptyObject = function isEmptyObject(obj) {if (!isObject(obj)) {throw new TypeError(`obj is not an object`);}let keys = Reflect.ownKeys(obj);return keys.length === 0;
    };
    
  • 检测是否为有效数字。

    // 检测JavaScript内置的基础对象或包装对象的类型。
    const toString = Object.prototype.toString;
    // 检测是否为数组。
    const typeReg = /^(object|function)$/;// 万能检测数据类型的方法;
    //返回小写的入参的值类型字符串
    const isType = function isType(obj) {if (obj === null || obj === undefined) {return obj + "";}let type = typeof obj;let reg = /^\[object (\w+)\]$/;let res = type;if (typeReg.test(type)) {res = reg.exec(toString.call(obj))[1].toLowerCase(); //对象类型;}return res;
    };
    // 检测是否为有效数字
    const isNumeric = function isNumeric(obj) {let type = isType(obj);return (type === "number" || type === "string") && !isNaN(+obj);
    };
    

装箱与拆箱

let num = 10 //原始值类型
console.log(num.toFixed(2)) //"10.00"  默认进行了“装箱”操作(把原始值转换为对象)num->Object(num)
let num2 = new Number(10) //对象类型
console.log(num2 + 10) //20  默认进行了“拆箱”操作(把对象转换为原始值)num2[Symbol.toPrimitive] -> num2['valueOf']() 
  • 把原始值变成对象类型,就是装箱操作
    • 比如对原始值变量调用包装类的方法,(10).toFixed(2)//'10.00'
  • 把对象类型变成原始值,就是拆箱操作
    • 比如:数学运算,Number(10) + 10//20

类的多种继承方案

  • 类的多种继承方案

多态

  • 多态:一个函数的多种形态

    • 相同的方法名,但是因为 参数个数、类型、返回值类型 等不同,构建出了多个不同作用的同名方法。
      • 是因为后端很多请求,都调用同一个方法的话,会导致某个方法的压力比较大
    • 前端JS中是没有类似于后台这样的多态处理的
      • 因为前端大多是客户端由客户来操作,客户一个人的压力而已。
      • 前端多态:同一个函数,根据传参不同,在函数中做不同的事情
        • 压力可以用模块来分担。
  • 后端多态

    public  void  sum(int x,int y){//.....
    } 
    public  String  sum(int x,int y,boolean flag){//.....
    } 
    sum(10,20)
    sum(10,20,true)
    
  • 前端多态

    function sum(x,y,flag){//....
    }
    //前端多态:同一个函数,根据传参不同,我们在函数中做不同的事情
    

继承

  • 继承的目的:让子类的实例,除了具备子类提供的属性方法,还要具备父类提供的属性和方法。
  • 实现继承的方案:
    1. 原型继承

      • 让子类的原型对象指向父类的一个实例。

        Child.prototype = new Parent()
        //子类构造函数.prototype=父类构造函数
        
      • 问题:

        • 父类提供的属性和方法,全部都成为子类实例公有属性和方法。
          • 一般想要的是:父类公有的变成子类公有的。父类私有的变成子类私有的。
        • 子类的原型对象被重定向后,丢失了constructor属性。
          • 可以手动加上,用以弥补。

            Child.prototype.constructor=Child
            //子类构造函数.prototype.constructor=子类构造函数
            
      • 特点

        • 原型继承并不是拷贝式继承,也就是,并不是把父亲的东西copy一份给儿子,而是让儿子基于原型链,找到父亲的方法,再去使用。
          • 拷贝式继承就是把父亲的东西copy一份给儿子,之后就是儿子的东西了。
            • 儿子怎么改动这些属性与方法都与父亲关系不大。
          • 原型继承是非拷贝式继承,这样就存在一个隐患:
            • 如果儿子基于原型链,把父亲原型上的方法改了,这样对父亲的其它实例也有影响。
              • 原则上,子类修改了自己能修改的属性或方法后,一定不会影响到父类或其它实例。
      // 父类
      function Parent() {this.x = 10;this.y = 20;
      }
      Parent.prototype.sum = function sum() {return this.x + this.y;
      };// 子类
      function Child() {this.x = 100;this.z = 300;
      }
      Child.prototype=new Parent()
      Child.prototype.constructor=Child
      Child.prototype.minus = function minus() {return this.z - this.x;
      };let c=new Child()
      console.log(`c-->`, c);
      
    2. call继承

      • 把父类当做普通函数执行,让函数中的this指向子类的实例
      • 问题:
        • 仅仅实现了把父类私有的属性继承给了子类实例的私有属性
          • 有冲突,则以子类为主
          • 但是父类公有的方法并没有被子类实例继承过去!
      • 特点
        • 它是拷贝式继承。
      // 父类
      function Parent() {this.x = 10;this.y = 20;
      }
      Parent.prototype.sum = function sum() {return this.x + this.y;
      };// 子类
      function Child() {Parent.call(this)//this:子类的实例cthis.x = 100;this.z = 300;
      }Child.prototype.minus = function minus() {return this.z - this.x;
      };let c=new Child()
      console.log(`c-->`, c);
      
    3. 寄生组合式继承

      • 把call继承和变异版原型继承混合在一起
      • 基于这样的方案,就实现了:父亲私有的给了儿子私有的,父亲公有的给了儿子公有
      // 父类
      function Parent() {this.x = 10;this.y = 20;
      }
      Parent.prototype.sum = function sum() {return this.x + this.y;
      };// 子类
      function Child() {Parent.call(this)//call继承部分:拷贝式继承this.x = 100;this.z = 300;
      }
      //原型继承部分:非拷贝式继承
      Child.prototype= Object.create(Parent.prototype)
      Child.prototype.constructor=Child
      Child.prototype.minus = function minus() {return this.z - this.x;
      };let c=new Child()
      console.log(`c-->`, c);
      
    4. 基于ES6中的class创建类,其自带了继承方案

      • 原理类似于寄生组合式继承

进阶参考

相关文章:

20230508----重返学习-call()与bind()重写-JS中数据类型检测汇总-装箱与拆箱-类的多种继承方案

day-065-sixty-five-20230508-call()与bind()重写-JS中数据类型检测汇总-装箱与拆箱-类的多种继承方案 call()与bind()重写 call()重写 call()的作用例子 let obj {name: 珠峰培训 } const fn function fn(x, y, ev) {console.log(this, x, y, ev)return x y } let res f…...

Node.js对ES6 及更高版本的支持

目录 1、简介 2、默认情况下什么特性随着 Node.js 一起发布? 3、有哪些特性在开发中? 4、移除这个标记(--harmony)吗 5、Node.js 对应 V8 引擎 1、简介 Node.js 是针对 V8 引擎构建的。通过与此引擎的最新版本保持同步&…...

【华为OD机试2023】工作安排 100% C++ Java Python

【华为OD机试2023】工作安排 100% C++ Java Python 前言 如果您在准备华为的面试,期间有想了解的可以私信我,我会尽可能帮您解答,也可以给您一些建议! 本文解法非最优解(即非性能最优),不能保证通过率。 Tips1:机试为ACM 模式 你的代码需要处理输入输出,input/cin接收…...

面试题Spring - 关于Spring的25个经典问题和答案

文章目录 1 什么是Spring框架?Spring框架有哪些主要模块?2 使用Spring框架能带来哪些好处?3 什么是控制反转(IOC)?什么是依赖注入?4 请解释下Spring框架中的IoC?5 BeanFactory和ApplicationContext有什么区…...

C++学习day--10 条件判断、分支

1、if语句 if 语句的三种形态 形态1&#xff1a;如果。。。那么。。。 #include <iostream> using namespace std; int main( void ) { int salary; cout << " 你月薪多少 ?" ; cin >> salary; if (salary < 20000) { cout <&…...

和月薪5W的聊过后,才发现自己一直在打杂···

前几天和一个朋友聊面试&#xff0c;他说上个月同时拿到了腾讯和阿里的offer&#xff0c;最后选择了阿里。 我了解了下他的面试过程&#xff0c;就一点&#xff0c;不管是阿里还是腾讯的面试&#xff0c;这个级别的程序员&#xff0c;都会考察项目管理能力&#xff0c;并且权重…...

SSM框架学习-AOP通知类型

在AOP中&#xff0c;通知&#xff08;Advice&#xff09;是对切点进行操作的方法&#xff0c;用于实现切面定义的具体逻辑。Spring框架支持五种类型的通知&#xff1a; 1. 前置通知&#xff08;Before advice&#xff09; 在连接点执行前&#xff0c;执行通知 Before("**…...

微信小程序原生开发功能合集十四:登录健权及注册功能实现

本章实现微信自动登录及注册修改功能,包括匿名账号生成、权限自动检测、注册界面及注册流程的实现。   另外还提供小程序开发基础知识讲解课程,包括小程序开发基础知识、组件封装、常用接口组件使用及常用功能实现等内容,具体如下:    1. CSDN课程: https://edu.csdn…...

【Java零基础入门篇】第 ⑤ 期 - 抽象类和接口(二)

博主&#xff1a;命运之光 专栏&#xff1a;Java零基础入门 学习目标 1.了解什么是抽象类&#xff0c;什么是接口&#xff1b; 2.掌握抽象类和接口的定义方法&#xff1b; 3.理解接口和抽象类的使用场景&#xff1b; 4.掌握多态的含义和用法&#xff1b; 5.掌握内部类的定义方法…...

Halcon 集合运算(差集difference、交集intersection、并集union2、打散connection与 合集 union1)

文章目录 1 差集difference2. 交集intersection3. 并集union24 打散connection与 合集 union1 (二者互为反义词)4.1 打散connection与4.2 合集 union1 (注意与交集的区别)5 示例原图1 差集difference difference (Operator) Name difference — Calculate the difference …...

Allegro约束规则设计

首先是物理规则。 然后是间距规则。 如果有些特殊要求&#xff0c;还需要设计电气规则。 原则上&#xff0c;把规则设计好&#xff0c;然后把规则赋值给网络。 物理规则。PCS。 对于名字为DEFAULT的PCS&#xff0c;这是最基础的整板默认规则。 没有特殊要求的网络&#xff0c…...

PyQt5桌面应用开发(11):摸鱼也要讲基本法之桌面精灵

本文目录 PyQt5桌面应用系列鼠标不要钱&#xff0c;手腕还不要钱吗&#xff1f;PyQt5源程序python文件资源定义界面定义文件 技术要素资源文件StyleSheetsQMainWindow设置窗体几何 结论 PyQt5桌面应用系列 PyQt5桌面应用开发&#xff08;1&#xff09;&#xff1a;需求分析 PyQ…...

Talk预告 | 大连理工大学IIAU Lab在读博士生严彬:走向通用实例感知

本期为TechBeat人工智能社区第495期线上Talk&#xff01; 北京时间5月10日(周三)20:00&#xff0c;大连理工大学IIAU Lab在读博士生—严彬的Talk将准时在TechBeat人工智能社区开播&#xff01; 他与大家分享的主题是: “走向通用实例感知”&#xff0c;届时将介绍和探讨通用实…...

2023-05-04 LeetCode每日一题(摘水果)

2023-05-04每日一题 一、题目编号 2106. 摘水果二、题目链接 点击跳转到题目位置 三、题目描述 在一个无限的 x 坐标轴上&#xff0c;有许多水果分布在其中某些位置。给你一个二维整数数组 fruits &#xff0c;其中 fruits[i] [positioni, amounti] 表示共有 amounti 个水…...

[工具]Pytorch-lightning的使用

Pytorch-lightning的使用 Pytorch-lightning介绍Pytorch-lightning与Pytorch的区别Pytorch-lightning框架的优势Pytorch-lightning框架 重要资源 Pytorch-lightning介绍 这里介绍Pytorch_lighting框架. Pytorch-lightning与Pytorch的区别 Pytorch-lightning可以简单的看作是…...

互联网摸鱼日报(2023-05-09)

互联网摸鱼日报&#xff08;2023-05-09&#xff09; InfoQ 热门话题 面向数字化提质提效的低代码架构设计 | 低代码技术内幕 提升字节规模化效能的平台化思路 &#xff5c; 极客有约 从微服务转为单体架构、成本降低 90%&#xff0c;亚马逊内部案例引发轰动&#xff01;CTO&…...

MySQL常见的存储引擎

InnoDB&#xff1a;InnoDB是一种兼顾高可靠性和高性能的通用存储引擎&#xff0c;在MySQL 5.5之后&#xff0c;InnoDB是默认的MySQL存储引擎。 特点&#xff1a;1、DML操作遵循ACID模型&#xff0c;支持事务; 2、行级锁&#xff0c;提高并发访问性能; 3、支持外键FOREIGN KEY约…...

迅为i.MX6ULL开发板生成 KEY 文件,并安装

使用“ssh-keygen” 生成个四个 key 文件“ssh_host_rsa_key” “ssh_host_dsa_key” “ssh_host_ecdsa_key” 和“ssh_host_ed25519_key” 。 1 在虚拟机 Ubuntu 控制台&#xff0c; “ /home/ssh/openssh-4.6p1” 目录下&#xff0c; 使用命 令“ssh-keygen -t rsa -f ssh…...

常见舆情监测系统的分类和特点

随着网络和社交媒体的发展&#xff0c;舆情监测系统逐渐成为企业和政府机构必备的工具之一。舆情监测系统可以帮助企业和政府机构全面了解公众对其品牌、产品、政策等的反应和态度&#xff0c;及时发现和解决问题&#xff0c;提高公信力和形象。本文将介绍常见的舆情监测系统的…...

联合群美叶彦文:坚持,只要有一口气,能坚持多久,就坚持多久

创业之路的成败得失就看有多坚持。 成功并不是终点&#xff0c;失败并不是终结&#xff0c;只有勇气才是永恒。 Success is not final,failure is not fatal,it is the courage to continue that counts. ——温斯顿丘吉尔 迪斯雷利曾经说过&#xff1a;“成功的奥秘在于目标…...

动态规划的学习

文章目录 动态规划的学习一、什么是动态规划&#xff1f;二、如何思考状态转移方程&#xff1f;三、动态规划的基本原理1.[509. 斐波那契数](https://leetcode.cn/problems/fibonacci-number/)1.1 暴力递归解法&#xff1a;1.1.1 递归算法的时间复杂度那为什么时间复杂度会这么…...

计算机网络:HTTPS

目录 HTTP 与 HTTPS 有哪些区别&#xff1f;HTTPS 解决了 HTTP 的哪些问题HTTPS 是如何建立连接的&#xff1f;其间交互了什么TLS 协议建立的详细流程客户端校验数字证书的流程是怎样的&#xff1f; HTTPS 的应用数据是如何保证完整性的HTTPS 一定安全可靠吗参考资料 HTTP 与 H…...

数据库系列-什么是 JDBC?它的作用是什么?

JDBC&#xff08;Java Database Connectivity&#xff09;是 Java 语言提供的一种访问数据库的标准接口&#xff0c;它定义了一组 Java 接口和类&#xff0c;用于实现 Java 程序与各种关系型数据库的连接和交互。JDBC 的主要作用是提供了一种标准的、可靠的、跨平台的方式来访问…...

C++学习day--08 数组和字符串

1、什么是数组 数组&#xff0c;就是多个元素的有序“组合”。 C 和 C语言中的数组&#xff1a; 1 &#xff09;由多个大小相同的小柜子组成 > 相同大小的内存块组成&#xff0c;即相同类型的数据 2 &#xff09;这些小柜子&#xff0c;有自己对应的编号 > 编号从 …...

系统分析师之系统测试与维护(十六)

目录 一、 测试与评审 1.1 测试类型 1.2 测试阶段 1.3 面向对象的测试 1.4 测试自动化 1.5 软件调试 1.6 软件评审 1.7 验收与确认 二、软件质量管理 2.1 软件过程改进-CMMI 2.2 软件开发环境与工具 三、系统运行与评价 3.1 系统转换计划 3.1.1 遗留系统演化策略…...

板材激光切割机切割穿孔时注意的几个问题

激光切割设备广泛应用于钣金、五金制品、钢结构、汽车配件、广告、工艺品等行业&#xff0c;成为加工行业不可缺少的环节。在厚板加工中穿孔时间占很大比重&#xff0c;随着加工板材越来越厚&#xff0c;板材激光切割机切割穿孔也会相应地增加难度。 激光切割机两种常见的穿孔方…...

奶爸式Swagger教学

目录 一、导入依赖 二、SwaggerConfig基础编程 三、Swagger 常用说明注解 1.API 2.ApiOperation 3.ApiModel 4.ApiModelProperty 5.ApiParam 6.ApilmplicitParam 一、导入依赖 <!--开启Swagger --><!-- https://mvnrepository.com/artifact/io.springf…...

入门级的家用洗地机怎么样?入门级洗地机推荐

洗地机的功能有很多&#xff0c;比如除菌、洗地机清洁地面的确是一把好手。但是&#xff01;清洁完之后还要手动清洗洗地机&#xff0c;是一件麻烦事啊&#xff01;现在市面上大部分洗地机都有自清洁这个功能&#xff0c;但是很多洗地机的自清洁并不算真正的自清洁&#xff0c;…...

【面试】Java 反射机制(常见面试题)

文章目录 前言一、反射是什么&#xff1f;二、为什么要有反射三、反射 API3.1 获取 Class 对象的三种方式3.2 获取成员变量3.3 获取构造方法3.4.获取非构造方法 四、实践五、常见面试题5.1. 什么是反射&#xff1f;5.2. 哪里用到反射机制&#xff1f;5.3. 什么叫对象序列化&…...

JavaScript最佳实践

JavaScript最佳实践 2023.5.8版权声明&#xff1a;本文为博主chszs的原创文章&#xff0c;未经博主允许不得转载。 JavaScript 是一种动态编程语言&#xff0c;可让开发者创建动态和交互式 Web 应用程序。然而&#xff0c;编写 JavaScript 代码比较具有挑战性&#xff0c;尤其…...