构造函数会在每一个实例上都创建一遍! 使用原型模式定义的属性和方法由所有实例共享! 原型链
1 2 3 4 5 6 7 8 9 10 function Parent ( ){ this .name = 'kevin' ; } Parent .prototype .getName =function ( ) { console .log (this .name ); } function Child ( ) {}Child .prototype = new Parent (); var child1 = new Child ();console .log (child1.getName ())
缺点 1.引用类型的属性被所有实例共享 2.创建Child实例时,不能向Parent传参 借用构造函数(经典继承)
1 2 3 4 5 6 7 8 9 10 11 function Parent ( ){ this .names =['kevin' ,'daisy' ]; } function Child ( ){ Parent .call (this ); } var child1 = new Child ();child1.names .push ('yayu' ); console .log (child1.names );var child2 = new Child ();console .log (child2.names );
1.避免了引用类型的属性被所有实例共享 2.可以在Child中向Parent传参 缺点 方法都在构造函数中定义,每次创建实例都会创建一遍方法 组合继承 原型链继承+经典继承双创合璧
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 function Parent (name ){ this .name =name; this .colors =['red' ,'blue' ,'green' ]; Parent .prototype .getName = function ( ) { console .log (this .name ) } } function Child (name,age ){ Parent .call (this ,name); this .age =age; } Child .prototype = new Parent ();Child .prototype .constructor = Child ;var child1 = new Child ('kevin' ,'18' );child1.colors .push ('black' ); console .log (child1.name );console .log (child1.age );console .log (child1.colors );var child2 = new Child ('daisy' ,'20' );console .log (child2.name );console .log (child2.age );console .log (child2.colors );
融合原型链继承和构造函数的优点,JS最常用继承模式 原型式继承
1 2 3 4 5 function createobj (o ){ function F ( ){} F.prototype = o; return new F (); }
一个使用这种方法实现继承的例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 let parentObj = { name : 'Parent' , sayHello : function ( ) { console .log (`Hello from ${this .name} ` ); } }; function createobj (o ) { function F ( ) {} F.prototype = o; return new F (); } let childObj = createobj (parentObj);childObj.name = 'Child' ; childObj.sayHello ();
ES5 Object.create的模拟实现,将传入对象作为创建的对象的原型 包含引用类型的属性值都会共享相应的值一—和原型链继承一样
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 function createobj (o ) { function F ( ) {} F.prototype = o; return new F (); } var person = { name :'kevin' , friends :['daisy' ,'kelly' ] } var person1 = createobj (person);var person2 = createobj (person);person1.name = 'person1' ; console .log (person2.name );person1.friends .push ('taylor' ); console .log (person2.friends );
寄生式继承 创建一个仅用于封装继承过程的函数,该函数在内部以某种形式做增强对象,再返回对象
1 2 3 4 5 6 function createobj (o ){ var clone = Object .create (o); clone.sayName = function ( ) console .log ('hi' ); return clone; }
缺点 和借用构造函数一样,每次创建对象都会创建一遍方法 寄生组合式继承 组合继承最大缺点一调用2次父构造方法 1.设置子实例的原型时 2.创建子类型的实例时 如何避免重复调用? 如果我f们不使用Child.prototy pe=new Parent(),而是间接让Child.prototype访问Parent..prototypel呢?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 function Parent (name ){ this .name =name; this .colors =['red' ,'blue' ,'green' ]; Parent .prototype .getName function ( ) console .log (this .name ) } function Child (name,age ){Parent .call (this ,name);this .age age;var F = function ({} F.prototype = Parent.prototype; Child.prototype = new F(); var child1 = new Child('kevin' ,'18' );console .log(child1);封装一下这个继承方法 function object(o)function F(){}F.prototype o; return new F();function prototype(child,parent){ var prototype = object(parent.prototype);//创建父类原型对象的副本 prototype.constructor = child;//增强对象,补充因重写原型而失去的默认的constructor/属性 child.prototype = prototype;//将创建的新副本指定给子类的原型对象 } prototype(Child,Parent);
优点一引用类型最理想的继承方式 只调用一次Parent构造函数,避免了在Parent.prototype.上面创建不必要的、多余的属性 同时,原型链能保持不变,能正常使用instanceof和isPrototypeOf
————————————-分割线———————————–
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 function Animal (name ) { this .name = name; } Animal .prototype .speak = function ( ) { console .log (this .name + ' makes a noise.' ); }; function Dog (name ) { Animal .call (this , name); } Dog .prototype = Object .create (Animal .prototype );Dog .prototype .constructor = Dog ;Dog .prototype .speak = function ( ) { console .log (this .name + ' barks.' ); }; const myDog = new Dog ('Rex' );console .log (myDog instanceof Dog ); console .log (myDog instanceof Animal ); console .log (myDog instanceof Object ); function myInstanceof (left, right ) { console .log (`Checking if ${left} is an instance of ${right.name} ` ); if (left === null || typeof right !== 'function' ) { return false ; } let proto = Object .getPrototypeOf (left); const prototype = right.prototype ; while (proto !== null ) { if (proto === prototype) { return true ; } proto = Object .getPrototypeOf (proto); } return false ; } console .log (myInstanceof (myDog, Dog )); console .log (myInstanceof (myDog, Animal )); console .log (myInstanceof (myDog, Object )); console .log (myInstanceof (myDog, Array ));
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 function Person (name, age ) { this .name = name; this .age = age; } Person .prototype .sayHello = function ( ) { console .log ('Hello, my name is ' + this .name ); }; var person1 = new Person ('Alice' , 25 );var person2 = new Person ('Bob' , 30 );console .log ('person1 的 name:' , person1.name ); console .log ('person1 的 age:' , person1.age ); person1.sayHello (); person2.sayHello (); console .log ('person1.__proto__ === Person.prototype:' , person1.__proto__ === Person .prototype ); console .log ('Person.prototype:' , Person .prototype ); console .log ('person1.__proto__:' , person1.__proto__ ); console .log ('person1 instanceof Person:' , person1 instanceof Person ); console .log ('Person.prototype.__proto__ === Object.prototype:' , Person .prototype .__proto__ === Object .prototype ); var obj = { greeting : 'Hi' };console .log ('obj.__proto__ === Object.prototype:' , obj.__proto__ === Object .prototype ); console .log ('obj 是 Object 的实例:' , obj instanceof Object );