目录

1.继承是什么?

2.继承的实现方式

        1.原型链继承

        2.借用构造函数继承

        3.组合式继承

        4.原型式继承

        5.寄生式继承

        6.寄生组合式继承


1.继承是什么?

        继承是面向对象编程中的一个重要概念,通过继承可以使子类的实例使用在父类中定义的属性和方法。也就是重复利用另外一个对象的属性和方法。

2.继承的实现方式

        1.原型链继承

        让一个构造函数的原型是另一个类型的实例,那么这个构造函数new出来的实例就具有该实例的属性。

        当试图访问一个对象的属性时,它不仅仅在该对象上搜寻,还会搜寻该对象的原型,以及该对象的原型的原型,依次层层向上搜索,直到找到一个名字匹配的属性或到达原型链的末尾。

 

<script type="text/javascript">
			function Parent() {
			   this.isShow = true
			   this.info = {
			       name: "张三",
			       age: 18,
			   };
			}
			 
			Parent.prototype.getInfo = function() {
			   console.log(this.info);
			   console.log(this.isShow);
			}
			 
			function Child() {};
			//将父构造函数实例对象赋给子构造函数的原型对象;
			Child.prototype = new Parent();
			 
			var child1 = new Child();
			child1.info.sex = "男";
			child1.info.age = "21";
			child1.getInfo(); // {name: '张三', age: 21, sex: '男'} ture
			 
			var child2 = new Child();
			child2.isShow = false;
			console.log(child2.info.sex) // 男
			child2.getInfo(); // {name: '张三', age: 21, sex: '男'} false
</script>

        优点:写法方便简洁,容易理解。

        缺点:对象实例共享所有继承的属性和方法。传教子类型实例的时候,不能传递参数,因为这个对象是一次性创建的。

        2.借用构造函数继承

        在子类型构造函数的内部调用父类型构造函数;使用 apply() 或 call() 方法将父对象的构造函数绑定在子对象上。区别就是apply()传递的参数是用数组传递,而call()则是参数列表的方式传递

<script type="text/javascript">
			function Parent(sex) {
			  this.info = {
			    name: "张三",
			    age: 19,
			    sex: sex
			  }
			}
			 
			function Child(sex) {
			    Parent.call(this, sex)
			}
			 
			var child1 = new Child('男');
			child1.info.height = 180;
			console.log(child1.info);
			 
			var child2 = new Child('女');
			console.log(child2.info);
</script>

        优点:解决了原型链实现继承的不能传参的问题和父类的原型共享的问题。

        缺点:借用构造函数的缺点是方法都在构造函数中定义,因此无法实现函数复用。在父类型的原型中定义的方法,对子类型而言也是不可见的,结果所有类型都只能使用构造函数模式。

        3.组合式继承

        将 原型链 和 借用构造函数 的组合到一块。使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承。这样,既通过在原型上定义方法实现了函数复用,又能够保证每个实例都有自己的属性

<script type="text/javascript">
			function Person(sex) {
			  this.info = {
			    name: "mjy",
			    age: 19,
			    sex: sex
			  }
			}
			 
			Person.prototype.getInfo = function () {   // 使用原型链继承原型上的属性和方法
			  console.log(this.info.name, this.info.age)
			}
			 
			function Child(sex) {
			  Person.call(this, sex) // 使用构造函数法传递参数
			}
			 
			Child.prototype = new Person()
			 
			var child1 = new Child('男');
			child1.info.nickname = 'xiaoma'
			child1.getInfo()
			console.log(child1.info);
			 
			var child2 = new Child('女');
			console.log(child2.info);
</script>

        优点: 解决了原型链继承和借用构造函数继承造成的影响。

        缺点: 无论在什么情况下,都会调用两次构造函数:一次是在创建子类型原型的时候,另一次是在子类型构造函数内部

        4.原型式继承

Object.create() 是把现有对象的属性,挂到新建对象的原型上,新建对象为空对象

ES5通过增加Object.create()方法将原型式继承的概念规范化了。这个方法接收两个参数:作为新对象原型的对象,以及给新对象定义额外属性的对象(第二个可选)。

<script type="text/javascript">
			var person = {
			  name: '张三',
			  age: 19,
			  hoby: ['唱', '跳'],
			  showName() {
			    console.log('my name is: ', this.name)
			  }
			}
			 
			var child1 = Object.create(person)
			child1.name = '李四'
			child1.hoby.push('rap')
			var child2 = Object.create(person)
			child2.name = 'cxk'
			 
			console.log(child1)
			console.log(child2)
			console.log(person.hoby) // ['唱', '跳', 'rap']
</script>

        优点是:不需要单独创建构造函数。

        缺点是:属性中包含的引用值始终会在相关对象间共享,也就是你修改一个属性时,其余实例化对象里相同的属性也会被修改,而且子类实例不能向父类传参

        5.寄生式继承

<script type="text/javascript">
			function objectCopy(obj) {
			  function Fun() { };
			  Fun.prototype = obj;
			  return new Fun();
			}
			 
			function createAnother(obj) {
			  var clone = objectCopy(obj);
			  clone.showName = function () {
			    console.log('my name is:', this.name);
			  };
			  return clone;
			}
			 
			var person = {
			     name: "张三",
			     age: 18,
			     hoby: ['唱', '跳']
			}
			 
			var child1 = createAnother(person);
			child1.hoby.push("rap");
			console.log(child1.hoby); // ['唱', '跳', 'rap']
			child1.showName(); // my name is: 张三
			 
			var child2 = createAnother(person);
			console.log(child2.hoby); // ['唱', '跳', 'rap']
		</script>

        优点:写法简单,不需要单独创建构造函数。

        缺点:通过寄生式继承给对象添加函数会导致函数难以重用。使用寄生式继承来为对象添加函数, 会由于不能做到函数复用而降低效率;这一点与构造函数模式类似。

  6.寄生组合式继承

所谓寄生组合式继承,即通过借用构造函数来继承属性,通过原型链的混成形式来继承方法。其背后的基本思路是:不必为了指定子类型的原型而调用超类型的构造函数,我们所需要的无非就是超类型原型的一个副本而已。本质上,就是使用寄生式继承来继承超类型的原型,然后再将结果指定给子类型的原型。

<script type="text/javascript">
			function Person(name) {
				this.name = name;
				this.sum = function() {
					console.log(this.name)
				}
			}
			Person.prototype.age = 10;
			Person.prototype.sex = function(){
				console.log("男")
			}
			//寄生
			function parent(obj) {
				function Fun(){}
				Fun.prototype = obj;
				return new Fun();
			}
			var child = parent(Person.prototype);

			function Child() {
				Person.call(this,"李四");
			}
			Child.prototype = child;
			child.constructor = Child();
			var child1 = new Child();
			child1.sex()
			console.log(child1.name)
		</script>

优点是:高效率只调用一次父构造函数,并且因此避免了在子原型上面创建不必要,多余的属性。与此同时,原型链还能保持不变;

缺点是:没有缺点。