虽然JS和Java都有对象的概念,但是这两个对象还是有很大区别的。Java对象是基于类创建的,而JS对象是基于一种特殊的对象——原型对象——之前看到一个盖房子的比喻。Java盖房子是先画蓝图再盖房子,而JS盖房子是先盖样板房再盖其他房子,挺贴切的。所以JS中的继承与Java中的继承有很大的不同。它基于原型对象。如果两个对象形成继承关系,那一定是其中一个对象的原型链上有一个指针指向另一个对象。JS中即使两个类声明了继承关系,也是在原型对象上表现出来的。例如:classA{say(){console.log('say:hello!');}}B类扩展A{constructor(){super();}}console.log(A.prototype);//{构造函数:?,说:?}console.log(B.__proto__);//A类{}console.log(B.prototype);//A{constructor:?}首先类在JS中是函数的语法糖,函数本身在JS中也是一个对象,也就是说A和B是两个对象,所以extends操作使得B的自己的原型属性__proto__指向A,相当于constB=Object.create(A);。其次,类的继承关系也会影响它生成的实例。众所周知,函数本身有一个特殊的对象属性:prototype。函数通过构造调用生成的实例的原型属性__proto__指向这个对象,extends操作修改了B的原型对象,所以B实例上的原型属性__proto__也被修改了,A的原型可以通过B实例的原型属性__proto__找到,即A的原型可以在B实例的原型链上找到。constb=newB();console.log(b.__proto__);//A{constructor:?}是B.prototypeconsole.log(b.__proto__.__proto__);//{constructor:?,say:?}即A.prototype在JS中使用字面量定义的对象时,其默认的原型属性__proto__指向Object的原型对象,相当于默认继承自Object,所以文字对象可以调用Object的实例方法。您可以使用isPrototypeOf来确定一个对象是否在另一个对象的原型链上。从上面可以看出,JS中的继承关系与原型对象密切相关。为了实现继承关系(共享一些属性和方法),需要从原型对象入手:使用Object.create创建对象,使两个对象直接产生继承关系consto1={name:'o1',age:18,walk(){console.log('walking...')}};consto2=Object.create(o1);console.log(o2.__proto__);//{name:'o1',age:18}console.log(o2.walk());//行走...console.log(o1.isPrototypeOf(o2));//true使用new操作创建对象,使得生成的实例与类(或函数)的原型对象具有继承关系constb=newB();console.log(B.prototype);//一个{constructor:?}console.log(b.__proto__);//A{constructor:?}是B.prototypeconsole.log(B.prototype.isPrototypeOf(b));//true使用extends关键字使类形成继承关系,扩展类实例的原型链classA{say(){console.log('say:hello!');}}B类扩展A{constructor(){super();}}console.log(A.prototype);//{constructor:?,say:?}constb=newB();控制台日志(b.__proto__.__proto__);//{constructor:?,say:?}ieA.prototypeconsole.log(A.isPrototypeOf(B));//trueconsole.log(A.isPrototypeOf(b));//falseconsole.log(A.prototype.isP原型(b));//true修改函数的原型属性,使函数形成继承关系,扩展函数实例的原型链functionC(){this.name='c';this.operation=function(){return'printing...'};}functionD(){}D.prototype=newC();constd=newD();console.log(d.__proto__.__proto__===C.原型);//trueconsole.log(C.prototype.isPrototypeOf(d));//trueconsole.log(D.prototype.isPrototypeOf(d));//true这里有个问题,就是子类实例化的时候,不能报给父类的构造函数传参窃取父类构造函数,通过call或者调用父类函数(非构造调用)apply在函数内部,可以继承父类实例本身(非原型对象)的属性和方法(相当于子类实例(也就是this)传给父类函数,对this做操作this),虽然在初始化时可以给父类传递参数,但是无法形成原型链functionE(){C.call(this);this.do=function(){return'做作业';}}conste=newE();console.log(E.prototype.isPrototypeOf(e));//trueconsole.log(C.prototype.isPrototypeOf(e));//falseconsole.log(e);//E{name:'c',operation:?,do:?}console.log(e.do());//做功课子类生成的实例不能用于父类,其原型对象使用了instanceof和isPrototypeOf方法。这时候父类如果想把方法共享给子类,必须直接在函数内部定义方法并绑定到实例上,不能通过父类的原型对象来共享。结合4和5,使得子类实例可以继承父类原型对象的属性和方法,可以形成一个原型链函数E(){C.call(this);this.do=function(){return'做作业';}}E.prototype=newC();conste=newE();console.log(E.prototype.isPrototypeOf(e));//trueconsole.log(C.prototype.isPrototypeOf(e));//trueconsole.log(e);//E{name:'c',operation:?,do:?}console.log(e.do());//做功课replacenewwithObject.create()父类实例重写子类的原型对象functioninheritPrototype(subT,superT){letproto=Object.create(superT.prototype);proto.constructor=subT;subT.prototype=proto;}inheritatePrototype(E,C);new中不必要的操作可以丢弃。通过工厂方法和类似工厂函数的方法来共享属性,但不是使用裸对象,而是通过某种方式获取对象(例如返回new等新对象的函数),并为这个对象或方法添加属性以增强功能,并返回一个对象。functioncreateAnother(original){letclone=Object.create(original);克隆.xx=xxx;returnclone;}适用于主要关注对象而不关心类型和构造函数的场景:方法必须定义在构造函数中(属于实例非原型对象的方法),函数不能被重用
