面向对象的三大特性:封装 、继承 、多态
本文主要内容:利用JavaScript原型链实现继承。
JavaScript原型链
每一个对象都有原型,指向另一个对象,另一个对象也有自己的原型,就这样由原型的原型构成的链条就叫原型链。
原型链的尽头
如果一个原型链是,没用尽头的,那么在查找一原型链上不存在的属性时,就会一直查找下去,存在死循环了。显然不是这样的,那么原型链的尽头是什么?
Object的原型
顶层原型
看代码~
var obj = {
name: "fzb",
};
console.log(obj.__proto__);
console.log(obj.__proto__.__proto__);
[Object: null prototype] {} 的特殊之处:
1、该对象存在原型属性,只是原型指向了null ,就是已经是顶层原型 了。
2、该对象上还存在许多其他的方法,只是不可枚举,看不到。
创建Object对象的内存图
上方例子的内存图
Object是所有类的父类
原型链最顶层的原型对象就是Object的原型对象
例子:
function Student(sno, name) {
this.sno = sno;
this.name = name;
}
const stu = new Student(201801, "fzb");
console.log(stu);
console.log(stu.__proto__);
console.log(stu.__proto__.__proto__);
console.log(Student.__proto__);
console.log(Student.__proto__.__proto__);
内存图:
原型链实现继承
继承可以重复利用代码,子类可以使用
例子:
function Person() {
this.name = "fzb";
}
Person.prototype.running = function () {
console.log(this.name + "正在跑步~");
};
function Student(sno) {
this.sno = sno;
}
Student.prototype = new Person();
Object.defineProperty(Student.prototype, "constructor", {
configurable: true,
enumerable: false,
writable: true,
value: Student,
});
Student.prototype.studying = function () {
console.log(this.name + "正在学习");
};
const stu = new Student(201801);
stu.running();
stu.studying();
内存图:
缺陷
1> 在打印子类对象时,有些属性本应该打印出来的,但是因为在父类上,无法打印出来。
2> 多个子类对象在进行某些操作时,会出现相互影响。
function Person() {
this.name = "fzb";
this.friends = [];
}
const stu1 = new Student(201801);
stu1.friends.push("zzw");
const stu2 = new Student(201801);
console.log(stu2.friends);
3> 无法传递参数,有些属性存在父类构造函数内,子类实例化时,初始化参数无法传入到父类。
借用构造函数实现继承
在子类构造函数内,调用构造函数。使改变父类构造函数内的this指向,然后父类在this上添加的属性就会在子类实例化的对象上。
function Person(name) {
this.name = name;
this.friends = [];
}
Person.prototype.running = function () {
console.log(this.name + "正在跑步~");
};
function Student(sno, name) {
Person.call(this, name);
this.sno = sno;
}
Student.prototype = new Person();
Object.defineProperty(Student.prototype, "constructor", {
configurable: true,
enumerable: false,
writable: true,
value: Student,
});
Student.prototype.studying = function () {
console.log(this.name + "正在学习");
};
const stu1 = new Student(201801,"stu1");
stu1.friends.push("zzw");
const stu2 = new Student(201802,"stu2");
console.log(stu2.friends);
这时原型链实现继承的三个弊端,就解决的。但是又出现了新的缺陷。
缺陷
1> 父类构造函数至少执行了两次以上
2> 子类构造函数的原型对象是父类的实例对象,那么个对象上的属性将会是undefined
|