写在前面:冬天是一个非常冷的季节,注意保暖~
最近在看一本新书籍《javascript设计模式》,文中以对话的方式去描述知识点和实现方式,比较喜欢的内容和描述方式,今天分享的是“面向对象编程之继承”
继承和封装是面向对象中两个主要的特性
继承即是对怨偶对象的封装,从额创建私有属性、私有方法、特权方法、共有属性、共有方法等,对于美中属性和方法特点是不一样的
1.开发过程中功能实现方式?
面向过程:就是初期最长用的一种方式,按照自己的思维方式去实现,将功能实现按照步骤来写
面向对象:将需求抽象成一个对象,然后针对这个对象分析其特征(属性)和方法,也就是类,将共有的属性和方法封装起来
2.封装?
封装主要体现在类上,通过类来对this(函数内部自带的一个变量,用于指向当前的这个对象)的变量添加属性或者方法来实现对类添加属性或者方法。将具有相同的属性和行为的对象抽象出一个公共类~
类的组成
3.继承
通过最常见的new关键字来直接进行继承
function SuperClass(){
this.superValue =[1,2,3,4];
}
SuperClass.prototype.getSuperVlaue=function(){
return this.value;
}
//声明子类
function subClass(){
this.subValue =[3,45];
}
//继承父类
subClass.prototype = new SuperClass(); //新创建的对象复制了父类的构造函数内的属性与方法,并将原型_proto_指向类父类的原型对象
//添加子类的共有方法
subClass.prototype.getSubValue=function(){
return this.subValue;
}
//使用子类
var sub1= new subClass();
var sub2 =new subClass();
console.log(sub1.superValue);//[1, 2, 3, 4]
sub1.superValue.push(‘3333‘); //sub1对superVlaue值进行更改
console.log(sub2.superValue) //[1, 2, 3, 4, "3333"]

类式继承缺点:
(1)由于子类是通过其原型prototype对父类进行的实例化,继承来父类,所以父类的共有属性如果是引用类型,就会被所有子类所共用,一个子类改变其值时,其他的子类也将会改变
(2)由于子类实现的继承是靠prototype对父类实例化的,无法向父类传递参数,因为实例化父类的时候也无法对父类的构造函数的属性进行初始化
console.log(‘%c构造函数继承‘,‘color:red;font-size:16px‘)
function SuperAnimal(type){
this.food = [‘apples‘,‘banana‘];
this.type =type;
function getType(){
console.log(this,type)
}
}
SuperAnimal.prototype.getFood=function(){
console.log(this.food);
}
function SubAnimal(type){
//继承父类
SuperAnimal.call(this,type);
}
//实例化
var animal1 =new SubAnimal(‘dog‘);
var animal2 =new SubAnimal(‘cat‘);
animal1.food.push(‘reak‘);
console.log(animal1.food); //["apples", "banana", "reak"]
console.log(animal1.type); //dog
console.log(animal2.food); //["apples", "banana"]
console.log(animal2.type); //cat
// animal2.getType() //Uncaught TypeError: animal2.getType is not a function
// animal2.getFood(); // Uncaught TypeError: animal2.getFood is not a function
通过构造函数继承的方式,引用类型的父构造函数数据将不会是共有的,父类的原型方法不能被子类所继承,如果想要继承就得放在在构造函数中,因此创建出来的每一个实例化对象都会有一个单独的共有属性,代码复用小
通过浏览器打印animal1实例发现也没有继承父类的prototype扩展的方法

类继承通过子类的原型prototype对父类实例化来实现的,构造函数式继承式通过子类的构造函数作用环境中执行一次父类的构造函数来实现,
console.log(‘%c 组合继承‘,‘color:red;font-size:16px‘)
function SuperStudent(id){
//值类型
this.id =id;
//引用类型
this.score = [22,33,11,33];
}
SuperStudent.prototype.getId=function(){
console.log(this.id)
}
//子类
function SubStudent(id,name){
SuperStudent.call(this,id);
this.name = name;
}
//类式继承+子类原型继承父类
SubStudent.prototype =new SuperStudent();
SubStudent.prototype.getName = function(){
console.log(this.name)
}
//实例化
var student1 = new SubStudent(1,‘mafeng‘);
console.log(student1);
var student2 =new SubStudent(2,‘mingy‘);
console.log(student1.id);//1
student1.getId();//1
student1.getName(); //mafeng
console.log(student2.id); //2
student2.getId();//2
student2.getName();//mingy
通过对student1的实例化进行查看可以知道,子类继承了父类的实例化对象

融合了构造函数继承和类继承的优点 但是不免发现在编译的过程中 父类的构造函数共调用类两遍
function inhertObject(obj){
function F(){};
//过度对象的原型继承父类型
F.prototype =obj;
return new F();
}
var book = {
name:"javascript",
type:[‘technology‘,‘finall‘],
}
var newBook = inhertObject(book);
newBook.name = ‘java‘;
newBook.type.push("thernal"); //改变引用类型的值
var otherBook = inhertObject(book);
otherBook.name = ‘lihai‘;
otherBook.type.push("yyyy"); //改变引用类型的值
console.log(newBook.name); //java
console.log(newBook.type); //["technology", "finall", "thernal", "yyyy"]
console.log(otherBook.name); //lihai
console.log(otherBook.type); //["technology", "finall", "thernal", "yyyy"]
console.log(book.name); //javascript
console.log(book.type); //["technology", "finall", "thernal", "yyyy"]

打印输出后发现:值类型被赋值,但是引用类型被共用,
其实就是对原型类型的第二次封装
//对原型继承的第二次封装
var student={
name:‘uuu‘,
score:[3,4,5,6],
}
function createdStudent(obj){
var o = new inhertObject(obj);
o.getName = function(name){
console.log(name);
}
return o
}
var newStudent = createdStudent(student);
newStudent.name =‘ma‘;
newStudent.score=[4,5,6,4,3];
//
console.log(newStudent.name); //ma
console.log(newStudent.score);// [4,5,6,4,3]
newStudent.getName(‘ooo‘); //ooo
console.log(student.name); // uuu
console.log(student.score);//[3,4,5,6]
从二者构造出的对象中查看,原型继承的对象,其继承的属性值只有值类型的,而引用类型的都是共有的,而寄生式继承的继承了父类的值类型和引用类型的数据

这种继承方式依托于原型继承,原型继承又和类式继承相向
console.log(‘%c 原型类继承‘,‘color:red;font-size:16px‘);
function inheritPrototype(subClass,superClass){
var p = inhertObject(SuperClass);//复制一份父本保存在变量中
p.constructor = subClass;//修改因为重写子类原型而导致的子类constructor属性修改 使刚复制的父类的contructor指向子类
subClass.prototype =p //设置子类的原型
}
//定义父类
function SuperMonther(){
this.name = ‘Mom‘;
this.type=[‘beautifuly‘,‘honest‘];
}
SuperMonther.prototype.getName=function(){
console.log(this.name)
}
function SubMonther(name,age){
SuperMonther.call(this,name);
this.age =age;
}
inheritPrototype(SubMonther,SuperMonther);
SubMonther.prototype.getAge=function(){
console.log(this.age);
}
var mom1 = new SubMonther(‘aa‘,33);
var mom2 =new SubMonther(‘yy‘,44);
mom1.type.push(‘uuuu‘);
console.log(this.mom1.type); //["beautifuly", "honest", "uuuu"]
console.log(this.mom2.type); //["beautifuly", "honest"]
通过寄生的方式重新继承父类的原型,

原文:https://www.cnblogs.com/mfyngu/p/11878239.html