这阵子在整理JS的7种继承方式,发现很多文章跟视频,讲解后都不能让自己理解清晰,索性自己记录一下,希望个位发表需要修改的意见,共勉之。
部分文章总结出来的数据可能是错误的,网络上太多数据了,有些不严谨,当然我也可能是其中一人,如果有问题,欢迎提出来,共同进步。
JS的7种并不是逐级进化的(个人觉得~),可以参考下图:
Children.prototype = new Parent(); 这个是手动指向
。__proto__
:子类实例对象 所指向的原型(实例化的父类) 这个是new 操作符里面的操作
。道格拉斯·克罗克福德在一篇文章中介绍了一种实现继承的方法,这种方法并没有使用严格意义上的构造函数。它的想法是借助原型可以基于已有的对象创建新对象,同时还不必因此创建自定义类型。
let obj = {
name: "Penk是个码农",
data: {
a: 1,
b: 2,
c: 3,
},
sayData: function () {
console.log(this.data);
},
};
function createObj(obj) {
function Fun() {}
Fun.prototype = obj;
return new Fun();
}
let parent = createObj(obj);
console.log(parent);
es5新增了一个类似功能的函数,Object.create();
let obj = {
name: "Penk是个码农",
data: {
a: 1,
b: 2,
c: 3,
},
sayData: function () {
console.log(this.data);
},
};
let parent = Object(obj);
console.log(parent);
之前讲的其他文章,原型链继承,构造函数继承,组合式继承都是以构造函数为基础的继承,原型式继承感觉就是通过对象,所以在这里可能会难以理解,但是也确实是实现了继承,没办法,开发用不上,但是考官可不理你... : <
let parent2 = Object.create(obj);
。之前的案例都是用父子类,这边依旧用它,不能因为换了技术方案就要换个场景。
原型式继承是通过对象浅拷贝,再通过
.操作符添加属性已到达继承跟重写的功能。
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>
<script>
let obj = {
name: "未初始化的人",
data: {
a: 1,
b: 2,
c: 3,
},
sayData: function () {
console.log(this.data);
},
setDataA: function () {
this.data.a = 666;
},
};
// 第一种方式,函数传参返回一个实例
// 该实例对应的构造函数的原型指向了传参
function createObj(obj) {
function Fun() {
// ... 这里不可以有方法以及属性,不然会覆盖Fun的原型对象上的方法以及属性
}
// 父类的公共方法以及属性需要放在这里,会被 "Fun.prototype = obj;" 覆盖...
// ... Fun.prototype.name = "";
Fun.prototype = obj;
// 放在这里也不可以,会覆盖传进来的参数obj
// ... Fun.prototype.name = 111;
// ... Fun.prototype.sayName = function () {
// ... console.log(this.name);
// ... };
return new Fun();
}
// 就当成一个父类吧
let parent = createObj(obj);
console.log(parent);
// 所以说,原型式继承,只能继承传进来的参数obj
// 第二种方式创建obj,使用object.create()
let parent2 = Object.create(obj);
console.log(parent2);
console.log(
"=====通过上面的对比,可以得知,Object.create(),可以实现原型式继承..."
);
console.log("=====================");
console.log("=====================");
console.log("接下来要展示原型式继承的BUG...");
// 就当成一个子类
let children = Object.create(parent);
children.job = "未找到工作";
children.sayJob = function () {
console.log(`${this.name} 的工作是${this.job}...`);
};
// 实例化2个子类对象
let person1 = Object.create(children);
let person2 = Object.create(children);
// 真的不知道怎么初始化,没找到相关资料...
// 这边就随便来了,有好建议欢迎交流.
person1.name = "钟先生";
person1.job = "程序员";
console.log(person1);
console.log(person2);
person1.sayJob();
person2.sayJob();
console.log("大概就是这样,一层套一层,还不能传参...");
console.log("=====================");
console.log("=====================");
console.warn("====这里如果使用了复合数据类型的话,也会出现数据混乱...");
// 初始化
person1.name = "钟先生";
person1.job = "程序员";
person2.name = "刘小姐";
person2.job = "清洁阿姨";
// 未修改数据
console.log("===未修改数据的时候...");
person1.sayData();
person2.sayData();
console.log("===修改数据的时候...");
person1.setDataA();
person1.sayData();
person2.sayData();
console.log(person1);
console.log(person2);
script>
body>
html>
实例化了person1跟person2 两个实例对象,并且都初始化了,第一次打印数据,相同没问题,第二次打印前,person1修改了原型上的复合数据类型中的变量a=>person1.__proto__.data.a
的值,这里是引用类型数据,所以混乱了。
无。
.
操作符,下一次将用升级版:寄生式继承。