"javaScript 没有提供传统面向对象语言中的类式继承,而是经过原型委托的方式来实现对象与对象之间的继承",这句话是摘自《javaScript设计模式与开发实践》书中第一章的一句话,这句话开门见山的说明了js的编程模式“原型”,而这样也直接说明了javaScript的面向对象是基于原型克隆的方式来建立对象,并以原型链的方式实现对象与对象之间的关系。java
那咱们先来了解一下这js这种基于原型编程语言的基本规则:es6
上面这几句话,我一样是摘自《javaScript设计模式与开发实践》里面的,原模原样抄录下来分享给你们的。编程
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方法
在上面的继承演示中,无论是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
关键字主要作了以下工做:
javaScript的面向对象与继承,继承的核心思想是复用,不须要在去编写多余代码,还有就是代码的管理。喜欢的朋友给个赞吧,谢谢。