https://juejin.im/post/5cfd9d30f265da1b94213d28#heading-14
https://juejin.im/post/5d124a12f265da1b9163a28d
https://juejin.im/post/5b44a485e51d4519945fb6b7#heading-19
//1.原型链继承 与Object.create()一样 // 特点(1)通过原型来实现继承时,原型会变成另一个类型的实例;子实例会混入父实例的方式与属性 // 原先的实例属性变成了现在的原型属性,该原型的引用类型属性会被所有的实例共享。 // (2)在创建子类型的实例时,没有办法在不影响所有对象实例的情况下给超类型的构造函数中传递参数 function Parent(name,role){ this.name=name; this.role=role; this.color=['red','yellow','hotpink'] } Parent.prototype.getName=function(){return this.name}; function Child(role){ this.crole=role; this.name=role+'999' //新的实例对象里原型会包含父实例的属性方法;子实例会再次赋值 } Child.prototype=new Parent('wade','papa'); var child1=new Child('child1') child1.color.push('white'); //color: (5) ["red", "yellow", "hotpink", "white", "white"] console.log(child1) //Child {crole: "child1", name: "child1999"} var child2=new Child('child2') child2.color.push('white'); //color: (5) ["red", "yellow", "hotpink", "white", "white"] console.log(child2) //Child {crole: "child2", name: "child2999"} // 2.借助构造函数 // (1)解决了原型中包含引用类型值被所有实例共享的问题;但没继承父类的原型 function Parent(name,role){ this.name=name; this.role=role; this.color=['red','yellow','hotpink'] } Parent.prototype.getName=function(){return this.name}; function Child(name,role){ Parent.call(this,name,role) } var child1=new Child('ken','child1'); child1.color.push('white') console.log(child1) var child2=new Child('peter','child2'); child2.color.push('white') console.log(child2) // 3.组合继承(原型链 + 借用构造函数) // 基本思路:使用原型链实现对原型属性和方法的继承,通过借用构造函数来实现对实例属性的继承, // 既通过在原型上定义方法来实现了函数复用,又保证了每个实例都有自己的属性。可以继承实例属性/方法,也可以继承原型属性/方法 // (1)new了两次 而且new父类会造成父类的实例无用属性挂在在子类实例的原型上 // (2)可以向超类传递参数;每个实例都有自己的属性;实现了函数复用 function Parent(name,role){ this.name=name; this.role=role; this.color=['red','yellow','hotpink'] } Parent.prototype.getName=function(){return this.name}; function Child(name,role){ Parent.call(this,name,role) } Child.prototype=new Parent(); Child.prototype.constructor=Child; var child1=new Child('ken','child1'); child1.color.push('white') console.log(child1) var child2=new Child('peter','child2'); child2.color.push('white') console.log(child2) //3-1组合继承优化 减少new父类实例添加多余的属性方法到子类实例的原型上 // child1 instanceOf Parent =>true child1 instanceOf Child =>true // 可用 child1.constructor去找 function Parent(name,role){ this.name=name; this.role=role; this.color=['red','yellow','hotpink'] } Parent.prototype.getName=function(){return this.name}; function Child(name,role){ Parent.call(this,name,role) } Child.prototype=Parent.prototype; Child.prototype.constructor=Child; var child1=new Child('ken','child1'); // 3-2组合继承优化 function Parent(name,role){ this.name=name; this.role=role; this.color=['red','yellow','hotpink'] } Parent.prototype.getName=function(){return this.name}; function Child(name,role){ Parent.call(this,name,role) } Child.prototype=Object.create(Parent.prototype); Child5.prototype.constructor = Child5; var child1=new Child('ken','child1');
// 4.寄生组合继承 // 通过寄生方式,砍掉父类的实例属性,这样,在调用两次父类的构造的时候,就不会初始化两次实例方法/属性 // 只调用了一次超类构造函数,效率更高。避免在Child.prototype上面创建不必要的、多余的属性,与其同时, // 原型链还能保持不变。 因此寄生组合继承是引用类型最理性的继承范式。 function Parent(name,role){ this.name=name; this.role=role; this.color=['red','yellow','hotpink'] } Parent.prototype.getName=function(){return this.name}; function Child(name,role){ Parent.call(this,name,role) } ( function(){ function F(){} F.prototype=Parent.prototype; Child.prototype=new F(); } )() var child1=new Child('ken','child1');
// 5寄生式组合 function parasitic(target){ function F(){} F.prototype=target.prototype; return new F(); } function createAnother(target){ var resultPrototype=parasitic(target); resultPrototype.sayHi=function(){ console.log('hi'); } return resultPrototype; } function Parent(name,role){ this.name=name; this.role=role; this.color=['red','yellow','hotpink'] } Parent.prototype.getName=function(){return this.name}; function Child(name,role){ Parent.call(this,name,role) } Child.prototype=createAnother(Parent); Child.prototype.constructor=Child; var child1=new Child('ken','child1');
ES6 的 class 允许子类继承父类的静态方法和静态属性:
class MyParent{ static role='parent'; static getRole=()=>{return this.role} } MyParent.getRole() //parent class Mychild extends MyParent{} Mychild.getRole() //"parent"
静态属性与方法:https://www.jb51.net/article/126399.htm
Object.setPrototypeOf(obj, proto)
,用来将obj.__proto__
设置为proto
。Object.getPrototypeOf(obj)
,返回obj.__proto__
。function Parent(){ this.name='i am parent test'; }; Parent.role="parent111"; Parent.getRole=function(){return this.role};
let temObj=Object.setPrototypeOf({},Parent); //等效于 {}.__proto__=Parent return{}
Object.create(proto, [propertiesObject]) //方法创建一个新对象,并且该对象继承了proto。其实第一个参数可以理解为添加到原型上的,第二个参数理解为添加到实例对象上的
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/create
https://www.jianshu.com/p/28d85bebe599
// Shape - 父类(superclass) function Shape() { this.x = 0; this.y = 0; } // 父类的方法 Shape.prototype.move = function(x, y) { this.x += x; this.y += y; console.info('Shape moved.'); }; // Rectangle - 子类(subclass) function Rectangle() { Shape.call(this); // call super constructor. } // 子类续承父类 Rectangle.prototype = Object.create(Shape.prototype); Rectangle.prototype.constructor = Rectangle; var rect = new Rectangle(); console.log('Is rect an instance of Rectangle?', rect instanceof Rectangle); // true console.log('Is rect an instance of Shape?', rect instanceof Shape); // true rect.move(1, 1); // Outputs, 'Shape moved.'
ES6继承
function Parent(){ this.role='parent'; this.color=['red','black','hotpink'] } Parent.prototype.giveMoney=()=>{console.log('$100')}; var parent1=new Parent(); var child1=Object.create(Object.getPrototypeOf(parent1),Object.getOwnPropertyDescriptors({cRole:'child'})) child1.cRole child1.giveMoney() // $100
Class的super ,分两种情况 https://www.jb51.net/article/126399.htm
1、当作函数使用
class A { constructor() { console.log(new.target.name); //new.target指向当前正在执行的函数 } } class B extends A { constructor() { super(); } } new A() // A new B() // B super虽然代表了父类A的构造函数,但是返回的是子类B的实例,即super内部的this指的是B,因此super()在这里相当于A.prototype.constructor.call(this)。
2、当作对象使用,这里也有存和取的区别,存的时候相当于super.x==this.x;取的时候是在普通方法中,指向父类的原型对象;在静态方法中,指向父类。
class A { c() { return 2; } } class B extends A { constructor() { super(); console.log(super.c()); // 2 super在普通方法之中,指向A.prototype,所以super.c()就相当于A.prototype.c()。 } } let b = new B();
//通过super调用父类的方法时,super会绑定子类的this。 class A { constructor() { this.x = 1; } s() { console.log(this.x); } } class B extends A { constructor() { super(); this.x = 2; } m() { super.s(); } } let b = new B(); b.m() // 2 super.s() == A.prototype.s.call(this)
class A { constructor() { this.x = 1; } } class B extends A { constructor() { super(); this.x = 2; super.x = 3; console.log(super.x); // undefined console.log(this.x); // 3 } } let b = new B(); //super.x赋值为3,这时等同于对this.x赋值为3。而当读取super.x的时候,读的是A.prototype.x,所以返回undefined。