原型和原型链
- 1. 了解原型和原型链
- 1.1 原型
- 1.2 原型链
- 2. 原型
- 2.1 prototype
- 2.2 `__proto__` 隐式原型
- 3. 原型链
1. 了解原型和原型链
1.1 原型
原型:
prototype
又称显示原型
1、原型是一个普通对象
2、只有构造函数才具备该属性
3、公有属性可操作
1.2 原型链
原型链:
__proto__
1、只有对象(普通对象、函数对象)具备
2、私有的对象属性,不可操作
有了上面的概念之后,我们再来探讨一下什么是原型和原型链。
2. 原型
我们知道在JS中每次创建一个函数,该函数就会自动带有一个prototype属性,该属性指向函数的原型对象。
2.1 prototype
// 生成一个构造函数
function Person() {
this.name = 'wyc'
}
// 在原型上添加属性
Person.prototype.age = 19
// 实例化对象
let person = new Person()
console.log(person);
上述例子中,函数的prototype指向了一个对象,而这个对象正是调用构造函数时创建的实例的原型,也就是person1和person2的原型。
让我们用一张图来展示 构造函数 与 原型对象 之间的关系:
2.2 __proto__
隐式原型
这是js对象中(null和undefined除外)都会存在的属性,这个属性会指向该对象的原型(注意:__proto__因为浏览器兼容性问题,不一定都可以获取到,应当使用Object.getPrototypeOf函数作为获取对象原型的标准API)。
隐式原型只有对象(普通对象、函数对象)才具备,并且隐式原型是一个私有的对象属性,不可操作。
// 生成一个构造函数
function Person() {
this.name = 'wyc'
}
// 在原型上添加属性
Person.prototype.age = 19
// 实例化对象
let person = new Person()
console.log(Person.prototype);
console.log(person.__proto__);
console.log(person.__proto__ === Person.prototype);
通过这个打印结果我们会发现,看着上面这张图,让我们来总结下:
- 构造函数(Person)通过prototype属性指向实例的原型。
- person是基于原型Person.prototype创建出的实例,并且可以通过__proto__属性指向其原型。
- Person.prototype和person.__proto__都指向实例的原型。
看着上面的描述来看这张图片
3. 原型链
在JavaScript 中,每个对象通过__proto__属性指向它的原型对象,这个原型对象又有自己的原型,直到某个对象的原型为 null 为止,这种一级一级的链结构就称为原型链。
class Person { // 生成父类
constructor(name) {
this.name = name;
}
drink() {
console.log('大家都爱喝可乐');
}
}
class Teacher extends Person { // 生成子类 继承 父类的属性和方法
constructor(name, age) {
super(name)
this.age = age;
}
teach() {
console.log('wyc 喜欢 前端工作');
}
}
let my = new Teacher('wyc', 19)
console.log(my);
my.teach();
my.drink()
看下面这副图,通过打印构造函数中的teach方法,能够打印出结果
在打印父类中的drink方法,也是可以打印出结果
通过下面这副图来详细的了解下
- 大家可以看到首先能够展示的是我们构造函数中的数据
- 调用teach方法时找不到,那么会通过自己的隐式原型
__proto__
访问到原型对象,在原型对象中寻找。(红色部分)- 在调用drink方法时找不到,那么先通过
__proto__
找到自己的隐式原型,可以看出隐式原型中也是没有drink方法的,那么在通过__proto__
向上寻找,找到后打印。- 如果一直找到
Object.prototype
对象上,还没有打印,那么就说明,整个原型链对象上都没有此方法,那么就打印为null
。
我们也可以通过 哈默 这张图理解下: