文章目录
- 概要
- 继承的进化史
- 技术名词解释
- 寄生式继承
- 案列分析
- 源代码解析
- 效果图
- 小结
概要
这阵子在整理JS的7种继承方式,发现很多文章跟视频,讲解后都不能让自己理解清晰,索性自己记录一下,希望个位发表需要修改的意见,共勉之。
部分文章总结出来的数据可能是错误的,网络上太多数据了,有些不严谨,当然我也可能是其中一人,如果有问题,欢迎提出来,共同进步。
继承的进化史
JS的7种并不是逐级进化的(个人觉得~),可以参考下图:
技术名词解释
- 原型式继承:返回一个空的构造函数所创建的实例,并该构造函数的prototype指向需要继承的对象,说白了就是直接浅拷贝copy一个新的对象给你用,可以参考原型式继承的一句话代码:
let parent2 = Object.create(obj);
。 - 工厂模式:定义一个创建对象的方法,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。
寄生式继承
说的寄生式继承,不得不提到上一篇文章的原型式继承,因为原型式继承无法传参
,对父类部分属性重写只能在上下文中,通过 .
操作符操作。而寄生式继承就是封装好一个函数,对原型式继承的实例化对象进行再加工,也是通过.
操作符,不过环境上下文切换到了函数。这个也就是我们熟悉的设计模式之一工厂模式
,既美化了代码,也实现了复用。
即原型式继承+工厂模式=寄生式继承
…
案列分析
- 父类:parentObj,要被继承的对象,可以理解为人。
- 子类:childrenFactory,创建子类的工厂,不同的工厂,可以代表不同的工种或者说是职业。
- 实例:person1 ,person2,实例化的子类,一般实例化后数据就分开了,复合数据类型要注意…
父类属性:
- name:父类属性,每个人都有名字 基础数据类型
- data:父类属性,个人的一些数据 复合数据类型,可以理解为个人的收藏,有人喜欢红酒,有人喜欢首饰
这里有BUG,数据混乱问题。
- sayData:父类方法,用来打印等下误操作的数据问题,打印BUG的地方,这边直接打印复合对象里面单独的属性,因为如果直接打印data,则永远指向最新的内存区域,也就是最后面修改的值,看不出变化…
- setData:父类方法,用于修改 data.a ,为了查看数据混乱。
- job:子类属性,代表工作,这里用于展示子类自带属性的一个实现,就是父子类总要有区别的嘛~
- sayJob:子类方法,用于打印工作内容。
源代码解析
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>寄生式继承</title>
</head>
<body>
<h3>寄生式继承</h3>
<h4>
上一章节:原型式继承,里面对父类的重写都是放在上下文中通过
.操作符来进行的,不是特别优雅。
</h4>
<h4>
寄生式继承,就是在原型式继承基础上,通过一个函数对齐进行封装,而这类函数也是属于设计模式之一的工厂模式。
</h4>
<h4>优化:相对于原型式继承,可以传参。</h4>
<h4>缺点:对象如果是复合数据类型的数据,会造成数据混乱。</h4>
<script>
let parentObj = {
name: "未初始化的人",
data: {
a: 1,
b: 2,
c: 3,
},
sayData: function () {
// 这里还不能直接打印对象出来,因为是一个指针,总是指向最新的数据...
console.log(this.name + " 的数据如下:");
console.dir(this.data.a);
console.dir(this.data.b);
console.dir(this.data.c);
console.log("我的数据结束====");
},
setDataA: function () {
this.data.a = 666;
},
};
// 这边仅使用Object.create() 来实现,避免代码量过多。
function childrenFactory(name, job) {
// 这里返回的是一个空的对象,obj放在了原型上了,所以只能修改temp中的数据。
let temp = Object.create(parentObj);
temp.name = name;
temp.job = job ? job : "没工作";
temp.sayJob = function () {
console.log(`${this.name} 的工作是 ${this.job} ...`);
};
return temp;
}
let person1 = childrenFactory("钟先生", "程序员");
let person2 = childrenFactory("刘小姐", "清洁阿姨");
// 未修改数据
console.log("===未修改数据的时候...");
person1.sayData();
person2.sayData();
console.log("===修改钟先生一个人的数据的时候...");
person1.setDataA();
person1.sayData();
person2.sayData();
console.log(person1);
console.log(person2);
</script>
</body>
</html>
效果图
部分同学不知道哪里修改了数据,这边贴上上方源码部分修改代码!
sayData: function () {
// 这里还不能直接打印对象出来,因为是一个指针,总是指向最新的数据...
console.log(this.name + " 的数据如下:");
console.dir(this.data.a);
console.dir(this.data.b);
console.dir(this.data.c);
console.log("我的数据结束====");
}
console.log("===修改钟先生一个人的数据的时候...");
person1.setDataA(); // 就是这一句。
person1.sayData();
person2.sayData();
小结
- 优化:相对于原型式继承,通过工厂模式,行进了更好的封装,由于有了函数,也实现了复用。
- 缺点:原型链继承,原型式继承,寄生式继承,都存放复合数据类型数据混乱问题。