原型链继承
/*1.原型链继承*/function parent(){ this.name = 'parent'}parent.prototype.getname = function(){ console.log(this.name)}function child(){ parent.call(this)}child.prototype = new parent()var child2 = new child()child2.getname() //parent/*由于new出来的是一个对象,所以必须要用对象名.key的方式访问*//*1.引用类型的属性被所有实例共享,举个例子:*/var child3 = new child()child3.getname() //parentchild3.name = '3'child2.getname() //3child3.getname() //3/*在创建 Child 的实例时,不能向Parent传参*/function parent2(){ this.name = 'parent2'}function child4(){ parent2.call(this)}
借用构造函数继承
function parent(){ this.name = ['parent','1']}function child(){ parent.call(this)}var p1 = new child()var p2 = new child()p1.name.push('p1')p2.name.push('p2')console.log(p1.name)console.log(p2.name)// ["parent", "1", "p1"]// ["parent", "1", "p2"]/*优点:1.避免了引用类型的属性被所有实例共享2.可以在child中向parent传参*//*缺点:方法都在构造函数中定义,每次创建实例都会创建一遍方法。*/
原型式继承
/*es5 Object.create模拟实现*/function objectcreate(object){ function f(){} f.prototype = object return new f()}var obj = { name : '123', age : [17,18]}var p1 = objectcreate(obj)var p2 = objectcreate(obj)p1.name = '456'console.log(p2.name) // 123p1.age.push('p1')console.log(p2.age) // [17, 18, "p1"]//缺点:包含引用类型的属性值始终都会共享相应的值,这点跟原型链继承一样。
寄生式继承
//寄生式继承function createobj(o){ var clone = Object.create(o) clone.sayName = function(){ console.log('hi') } return clone}//创建一个仅用于封装继承过程的函数,该函数在内部以某种形式来做增强对象,最后返回对象。// 缺点:跟借用构造函数模式一样,每次创建对象都会创建一遍方法。
组合继承
/*原型链继承和经典继承双剑合璧。*/var parent = function(){ this.name = parent this.color = ['red','blue']}parent.prototype.getname = function(){ console.log(this.name)}var child = function(name,age){ parent.call(this,name) this.age = age}child.prototype = new parent()var p1 = new child()var p2 = new child()console.log(p1)console.log(p2)//child {color: Array(2), age: undefined, name: ƒ}//child {color: Array(2), age: undefined, name: ƒ}//优点:融合原型链继承和构造函数的优点,是 JavaScript 中最常用的继承模式// 组合继承最大的缺点是会调用两次父构造函数。
寄生组合式继承
/*组合继承function parent(name,color){ this.name = name this.color = ['red','blue']}parent.prototype.getname = function(){ console.log(this.name)}function child(name,age){ parent.call(this,name) this.age = age}child.prototype = new parent()var child1 = new child('kevin', '18');console.log(child1)*//*组合继承最大的缺点是会调用两次父构造函数。一次是设置子类型实例的原型的时候:child.prototype = new Parent();一次在创建子类型实例的时候:var child1 = new child('kevin', '18');回想下 new 的模拟实现,其实在这句中,我们会执行:parent.call(this, name);在这里,我们又会调用了一次 Parent 构造函数所以,在这个例子中,如果我们打印 child1 对象,我们会发现 child.prototype 和 child1 都有一个属性为colors,属性值为['red', 'blue', 'green']。console.log(child.prototype)console.log(child1)*//*寄生组合式继承*/function parent(name,color){ this.name = 'parent' this.color = ['red','blue']}function child(name, age) { parent.call(this, name); this.age = age;}function createobj(o){ function f(){} f.prototype = o /* {constructor: ƒ} constructor: ƒ parent(name,color) __proto__: Object */ return new f()}function prototypeobj(child,parent){ var prototype = createobj(parent.prototype) prototype.constructor = child child.prototype = prototype}prototypeobj(child,parent)var p1 = new child()var p2 = new child()p1.name = 'p1'p2.name = 'p2'console.log(p1)console.log(p2)//child {name: "p1", color: Array(2), age: undefined}//child {name: "p2", color: Array(2), age: undefined}/*寄生组合原理:p1的constructor为child,__proto__中的constructor为parentcreateobj(parent.prototype) 这一步的功能是创建一个对象,这个对象是parent的实例,具有parent的constructor方法prototype.constructor = child 这一步将prototype的constructor设为child函数child.prototype = prototype 设置child的原型为prototype 这样child就继承了parent的constructor 通过prototypeobj方法,child的prototype有了两个constructor,一份是原本自己的,另一份通过__proto__ 寻找到父级的constructor*//*三步骤首先先创建个变量 var prototype = Object.create(父类的prototype) prototype.constructor = child(子类的constructor)child.prototype(子类的prototype) = prototype*/
es6 extend
class Point{ constructor(x){ this.x = x; this.p = 2; this.j = 3; } print(){ return this.x } m(){ return this.p } static b(){ console.log(this.c()) } static c(){ return 'world' }}Point.prototype.z = 2//调用var p1 = new Point('p1') //更es5一样,调用Point构造函数new一个实例对象console.log(p1)//Point {x: "p1", p: 2}/*constructor是该类的构造函数,即使你没有创建,系统也会自动生成一个。一般 constructor 方法返回实例对象 this ,但是也可以指定 constructor 方法返回一个全新的对象,让返回的实例对象不是该类的实例。*//*上面的代码用es5可以这样表达function Point(x){ this.x = x; this.p = 2;}Point.prototype.print = function(){ return this.x}*//*super*//*函数时使用super只能在子类的constructor使用,不能在别的方法调用*/class colorPoint extends Point{ constructor(x){ super(x) // 调用父类的constructor(x) this.y = 2 super.y = 3 } b(){ console.log(super.print()) //调用父类的print() this指向子类colorPoint的实例 console.log(super.m()) //调用父类的m() 结果是2 console.log(super.z) //获取父类的prototype.z属性 }}let p2 = new colorPoint('p2')//colorPoint {x: "p2", p: 2}/*对象时使用super.print(),将super当作一个对象使用,super指向Point.prototype,此时print就是Point.prototype.print方法super.z 由于super指向Point.prototype,此时z就是Point.prototype.zsuper.y赋值为3,这时等同于对this.y赋值为3。而当读取super.y的时候,读的是A.prototype.y 显示为undefined*//*Object.getPrototypeOf方法可以用来从子类上获取父类*/Object.getPrototypeOf(colorPoint) === Point //true/*static 静态方法static关键字,就表示该方法不会被实例继承,而是直接通过类来调用,这就称为“静态方法”。1.可以被子类继承2.只能通过类调用3.this指本类,不指实例4.通过this调用只能调用本类定义的static方法*/Point.b()// worldcolorPoint.b()// world/*new.targetnew.target属性允许你检测函数或构造方法是否通过是通过new运算符被调用的。*/