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()的处理步骤
-
fn()这个函数,首先基于
__proto__
找到Function.prototype.call()这个方法 -
把找到的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; };
- call()内部可以访问到的值
-
而在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中数据类型检测汇总
-
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,说明其是其它对象
- 然后再看此对象是否具备call方法,
- 而null在计算机底层的二进制值都是零,也就是前三位也是零,所以 typeof null 的结果是 “object” !
- 其中,如果二进制值的前三位是零,便都被识别为对象。
- typeof在检测数据类型的时候,是按照数据值在计算机底层存储的二进制值,进行检测的!
-
应用
- 检测除null之外的原始值类型
- typeof用起来方便,而且性能还好
- 判断兼容性
- 查看如Promise是否存在
- 笼统检测是否为对象
- …
- 检测除null之外的原始值类型
-
-
对象 instanceof 构造函数
-
原本的意义是用来检测某个对象是否是相应类的实例
- 只不过针对于这个特点,可以用其检测一些数据类型
- 检测是否为数组:值 instanceof Array
- 检测是否为正则:值 instanceof RegExp //RegExp是Regular Expressions的简写
- …
- 也就是基于instanceof,可以弥补typeof不能细分对象的缺陷!
- 只不过针对于这个特点,可以用其检测一些数据类型
-
特点:
-
无法检测原始值类型,返回结果都是false
- 原因:基于instanceof进行操作,不会对原始值类型进行装箱
10 instanceof Number -> false
- 原因:基于instanceof进行操作,不会对原始值类型进行装箱
-
原本不是检测数据类型的,现在非要让其检测类型,所以检测的结果不一定精准
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
-
-
-
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值是可以被更改的。
-
不过这个可以让其与实例对象的原型上的constructor进行比较,进而让修改对象的成本变高,也更准确。
-
-
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){//.... } //前端多态:同一个函数,根据传参不同,我们在函数中做不同的事情
继承
- 继承的目的:让子类的实例,除了具备子类提供的属性方法,还要具备父类提供的属性和方法。
- 实现继承的方案:
-
原型继承
-
让子类的原型对象指向父类的一个实例。
Child.prototype = new Parent() //子类构造函数.prototype=父类构造函数
-
问题:
- 父类提供的属性和方法,全部都成为子类实例公有属性和方法。
- 一般想要的是:父类公有的变成子类公有的。父类私有的变成子类私有的。
- 子类的原型对象被重定向后,丢失了constructor属性。
-
可以手动加上,用以弥补。
Child.prototype.constructor=Child //子类构造函数.prototype.constructor=子类构造函数
-
- 父类提供的属性和方法,全部都成为子类实例公有属性和方法。
-
特点
- 原型继承并不是
拷贝式继承
,也就是,并不是把父亲的东西copy一份给儿子,而是让儿子基于原型链,找到父亲的方法,再去使用。- 拷贝式继承就是把父亲的东西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);
-
-
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);
-
寄生组合式继承
- 把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);
-
基于ES6中的class创建类,其自带了继承方案
- 原理类似于寄生组合式继承
-