js继承
1.原型链通过子代的原型去new 祖先的构造函数。去继承。
优点:
- 无
缺点:
- 创建子类实例时,不能向父类的构造函数中传递参数
- 父类中所有引用类型的属性会被所有子类实例共享,也就说一个子类实例修改了父类中的某个引用类型的属性时,其他子类实例也会受到影响
例子: a.pototype=new b(); // a,b都是构造函数,a继承b
下面看看修改原型链上面原始值与引用值的区别:
// 原始值
Professor.prototype.tSkill = "java"; function Professor() { } var professor = new Professor(); Teacher.prototype = professor; function Teacher() { this.mSkill = "js"; this.students = 500; this.objs = { a: 1, b: 2, }; } var teacher = new Teacher(); Student.prototype = teacher; function Student() { this.pSkill = "html" } var student = new Student(); student.students++;
// 修改原始值,原型祖先不会更改,会在自己本身新增一个属性
// student.students=student.students+1;
// 右边student.students可以通过原型链在Teacher获取到;
// 左边的这个,可以看成对象新增属性,没有这个属性,就得新增这个属性
// 引用值
列子:
student.objs.a = 11;
student.objs.c = 3;
// 修改对象值,会直接修改原型链祖先的值,不建议这样操作;十分不规范
console.log(student);
console.log(teacher);
不是所有的对象都继承与Object.prototype
Object.create(null);
2.借用构造函数继承(经典继承)
优点:
- 在子类构造函数中可以向父类的构造函数中传递参数
- 避免了父类中的引用类型属性在子类中共享的问题
缺点:
- 父类原型对象上的方法子类继承不到
function Parent(age) { this.name = "parent"; this.age = age; this.hobby = ["sing", "rap"]; } Parent.prototype.sayHi = function() { console.log("Hi"); }; function Child(age) { Parent.call(this, age); this.type = "child"; } let child1 = new Child(15); let child2 = new Child(15); child1.hobby.push("basketball"); console.log(child1.name); // parent console.log(child1.age); // 15 console.log(child1.type); // child console.log(child1.hobby); // [ 'sing', 'rap', 'basketball' ] console.log(child2.hobby); // [ 'sing', 'rap' ] child1.sayHi(); // 报错,child1.sayHi is not a function
3.组合继承
优点:
- 在子类构造函数中可以向父类的构造函数中传递参数
- 避免了父类中的引用类型属性在子类中共享的问题
- 父类原型对象上的方法子类也可以继承到
缺点:
- 父类构造函数被调用了两次
function Parent(age) { this.name = "parent"; this.age = age; this.hobby = ["sing", "rap"]; } Parent.prototype.sayHi = function() { console.log("Hi"); }; function Child(age) { Parent.call(this, age); // 第二次调用Parent this.type = "child"; } Child.prototype = new Parent(); // 第一次调用Parent Child.prototype.constructor = Child; let child1 = new Child(15); let child2 = new Child(15); child1.hobby.push("basketball"); console.log(child1.name); // parent console.log(child1.age); // 15 console.log(child1.type); // child console.log(child1.hobby); // [ 'sing', 'rap', 'basketball' ] console.log(child2.hobby); // [ 'sing', 'rap' ] child1.sayHi(); // Hi
4.组合式继承优化1
优点:
- 在子类构造函数中可以向父类的构造函数中传递参数
- 避免了父类中的引用类型属性在子类中共享的问题
- 父类原型对象上的方法子类也可以继承到
- 父类构造函数也只调用了一次
缺点:
- 向子类原型上增加属性或方法时会影响到父类原型
function Parent(age) { this.name = "parent"; this.age = age; this.hobby = ["sing", "rap"]; } Parent.prototype.sayHi = function() { console.log("Hi"); }; function Child(age) { Parent.call(this, age); this.type = "child"; } Child.prototype = Parent.prototype; Child.prototype.constructor = Child; // 向子类原型上增加testProp属性,同时会被添加到父类原型上 Child.prototype.testProp = 1; console.log(Parent.prototype); // 1 let child1 = new Child(15); let child2 = new Child(15); child1.hobby.push("basketball"); console.log(child1.name); // parent console.log(child1.age); // 15 console.log(child1.type); // child console.log(child1.hobby); // [ 'sing', 'rap', 'basketball' ] console.log(child2.hobby); // [ 'sing', 'rap' ] child1.sayHi(); // Hi
5.组合式继承优化2
优点:
- 实现继承最有效的方式!
缺点:
- 无
function Parent(age) { this.name = "parent"; this.age = age; this.hobby = ["sing", "rap"]; } Parent.prototype.sayHi = function() { console.log("Hi"); }; function Child(age) { Parent.call(this, age); this.type = "child"; } Child.prototype = Object.create(Parent.prototype); Child.prototype.constructor = Child; let child1 = new Child(15); let child2 = new Child(15); child1.hobby.push("basketball"); console.log(child1.name); // parent console.log(child1.age); // 15 console.log(child1.type); // child console.log(child1.hobby); // [ 'sing', 'rap', 'basketball' ] console.log(child2.hobby); // [ 'sing', 'rap' ] child1.sayHi(); // Hi