javaScript的面向对象与继承

js面向对象概述

"javaScript 没有提供传统面向对象语言中的类式继承,而是经过原型委托的方式来实现对象与对象之间的继承",这句话是摘自《javaScript设计模式与开发实践》书中第一章的一句话,这句话开门见山的说明了js的编程模式“原型”,而这样也直接说明了javaScript的面向对象是基于原型克隆的方式来建立对象,并以原型链的方式实现对象与对象之间的关系。java

那咱们先来了解一下这js这种基于原型编程语言的基本规则:es6

  • 一. 全部的数据都是对象,
  • 二. 要获得一个对象,不是经过实例化类,而是找到一个对象做为原型并克隆它,
  • 三. 对象会记住它的原型,
  • 四. 若是对象没法响应某个请求,它会把这个请求委托给它本身的原型。

上面这几句话,我一样是摘自《javaScript设计模式与开发实践》里面的,原模原样抄录下来分享给你们的。编程

js继承

1. 原型链继承设计模式

实现方式:新对象的实例的原型等于父对象类的实例。 `闭包

let Animals = function (type, name) {   // 定义父类
	this.type = type;
	this.name = name;
    }
    Animals.prototype.animal = '动物';
    Animals.prototype.eat = function () {
		console.log('这是一只小'+ this.type + ': 它会吃东西')
    }			   
		   
let Cat = function (sex) {  // 定义子类
	this.sex = sex
    }
		   
Cat.prototype = new Animals('猫', '小花');  // 原型链继承
	let cat = new Cat('公') // 生成子类实例
	cat.eat()   // 执行继承来的方法
复制代码

` 原型链继承的特色是:可继承父类的私有属性和原型上的属性和方法,可是,父类私有上的属性方法它们之间的继承是属于引用同一个内存地址,所以修改其中的一个,也会影响到另外一个对象app

2. 构造函数继承编程语言

实现方式:在子类的函数体里执行父类,经过call和apply来改变this的指向。函数

`性能

let Dog = function (sex) {
	Animals.call(this, '狗', '旺财');   // 构造继承:执行父类,经过call改变this指向
	this.sex = sex;
	}
let dog = new Dog('母');
dog.eat();  // 报错:Uncaught TypeError: dog.eat is not a function;
复制代码

`this

构造函数继承: 可继承父类里的私有属性和方法,可是不能继承父类原型上的方法和属性,此类继承修改一个对象的属性不会影响到另外一个对象

3. 组合式继承

实现方式:该方式的继承其实就是上面的原型继承和构造函数继承的混合方式。

`

let Dog = function (sex) {
	Animals.call(this, '狗', '旺财');   // 构造继承: 执行父类,经过call改变this指向
	this.sex = sex;
	}
Dog.prototype = new Animals('猫', '小花');  // 原型链继承
let dog = new Dog('母');
dog.eat();  // 执行父类原型上的方法
复制代码

` 组合式继承:可继承父类私有的属性和方法,继承的私有属性和方法都是子类私有的,能够继承父类原型上的属性,能够传参,可复用。可是组合式继承调用了两次父类方法,所以在性能上有必定的损耗

4. 包装式继承

实现方式: 经过一个包装函数,把父类实例做为参数传递进去,子类实例在包装函数体里生成。

`

function context (obj) {    // 定义包装函数,并传递父类实例
		function Pig () {
		   	this.sex = '公'		
		}
		Pig.prototype = obj;    // 继承父类实例
		return new Pig()    // 返回子类实例
	}
		   
    let animals = new Animals('猪', '小胖')
	let pig = context(animals);
    pig.type = '羊';  //这样写等于给子类添加一个新的type属性
	pig.eat()    // 输出:这是一只小羊: 它会吃东西
	animals.eat()    // 输出: 这是一只小猪: 它会吃东西
复制代码

` 包装式继承:相似于函数闭包的用法,语义上不够明显。

5. 组合寄生式继承

实现方式: 经过寄生方式,砍掉父类的实例属性,这样,在调用两次父类的构造的时候,就不会初始化两次实例方法/属性,避免的组合继承的缺点。

`

function context (obj) {
		function Fn () {
		   this.sex = '公'
		}
		Fn.prototype = obj; // 函数的原型等于另外一个实例
		   return new Fn()
	}
		   
    let objA = context(Animals.prototype);
		   
    function Cattle () {
		Animals.call(this, '牛', '小蛮'); //在函数中用apply或者call引入另外一个构造函数
	}
		   
    Cattle.prototype = objA;
		   
	objA.constructor = Cattle;   // 修复实例
		   
    let cattle = new Cattle();
		   
	console.log(cattle)
复制代码

`

组合寄生式继承:一、函数的原型等于另外一个实例。二、在函数中用apply或者call引入另外一个构造函数。继承方式太过复杂。

6. es6继承 (使用最多)

实现方式:使用class关键字声明类,经过extends关键字实现继承。

`

class Animals {
	constructor(type, name) {
		this.type = type;
		this.name = name;
	}			
	eat () {
		console.log('这是一只小'+ this.type + ': 它会吃东西')
			}
		}
		
    let animal = new Animals('狗', '旺财');
		
	class Car extends Animals {
		constructor(sex) {
		super('猫', '小花');   
		// 此处是重点在子类的构造函数中,只有调用super以后,才能够使用this关键字,不然
		// 会报错。这是由于子类实例的构建,基于父类实例,只有super方法才能调用父类实例
				this.sex = sex;
			}
		}			
	let car = new Car('公')
	car.eat()
复制代码

` es6继承:使用extends关键字实现继承,语法上更加清晰明了,子类继承父类后,子类的构造函数,必须执行super方法

new关键字

在上面的继承演示中,无论是es5仍是es6,js建立一个类都必须使用new关键字去执行。 `

let Animals = function (type, name) {   // 定义父类
	this.type = type;
	this.name = name;
    }
    Animals.prototype.animal = '动物';
    Animals.prototype.eat = function () {
		console.log('这是一只小'+ this.type + ': 它会吃东西')
    }
复制代码

`

在这里面,new关键字主要作了以下工做:

  • 一:建立了一个对象obj;
  • 二:将这个obj对象的__proto__成员指向了Animals函数的prototype;
  • 三:将Animals函数对象的this指针替换成obj;
  • 四:将obj对象返回出来,也就是咱们的实例;

总结

javaScript的面向对象与继承,继承的核心思想是复用,不须要在去编写多余代码,还有就是代码的管理。喜欢的朋友给个赞吧,谢谢。

相关文章
相关标签/搜索