简述Js中的原型与原型链

1、原型

​ Javascript是基于对象的编程语言,他其中也含有部分封装、继承的概念,而原型概念便是基于继承的。

​ 函数的原型类似于面向对象语言中子类的父类,而函数本身类似于子类。函数继承了函数原型中的属性和方法,即函数本身可以调用它原型中的属性和方法。

​ 知识点:若有函数Person,则它的函数原型为Person.prototype,函数原型本身是个对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function Person (name) {
this.name = name;
}
Person.prototype.type = 'human'
Person.prototype.sayName = function () {
console.log(this.name + '说话了')
}
//此时我们用Person构造函数构造了一个p对象
var p = new Person('小王');
//我们打印p.name
console.log(p.name); //结果是'小王',因为Preson函数中已经预置了name属性并且接受了new对象时传入的'小王',结果勿容置疑
//我们再打印p.type 调用p.sayName() 按常理说Preson构造函数中是不存在type属性和sayName方法,若调用应该会报错
console.log(p.type); //结果 human
p.sayName(); // 结果 小王说话了
//结果和我们预想的不同,这是为什么呢?
//因为Person继承了它原型Person.prototype中的信息,当调用p.type时,会优先在Person类中找该属性,若找到了则直接使用,若没找到则在他的原型中找并使用。因为我们设置了Person原型的type属性的,则p可以直接使用

在上面的例子中涉及到了 构造函数、对象和函数原型,接下来给出三者之间的关系图;

2、构造函数、实例、原型三者之间的关系

三者关系

由图中我们可以很直观的看到三者之间的关系。

p对象由Person构造函数构造

p对象通过__proto__属性访问到Person对象原型

Person对象原型通过constructor访问Person构造函数

Person函数通过prototype属性访问到Person原型对象

注意:对象是通过__proto__属性访问对象原型,函数是通过prototype访问对象原型,但两者访问到的对象原型是同一个

验证:

1
console.log(p.__proto__ == Person.prototype); //结果为 true

constructor的作用:可以使得对象访问到对应的构造函数

1
2
3
4
function Person(){
}
var p = new Person();
console.log(p.constructor);// 打印 function Person()

知道以上的知识之后,我们还要了解,其实Person的原型也有原型,即存在Person.prototype.prototype,并且它是Person.prototype的原型,可以用图来直观了解这其中的关系,这便是一个简单的原型链。

3、原型链

原型链

4、原型链中的搜索规则

了解了 构造函数-实例-原型对象 三者之间的关系后,接下来我们来解释一下为什么实例对象可以访问原型对象中的成员。

每当代码读取某个对象的某个属性时,都会执行一次搜索,目标是具有给定名字的属性

  • 搜索首先从对象实例本身开始
  • 如果在实例中找到了具有给定名字的属性,则返回该属性的值
  • 如果没有找到,则继续搜索指针指向的原型对象,在原型对象中查找具有给定名字的属性
  • 如果在原型对象中找到了这个属性,则返回该属性的值

也就是说,在我们调用 p.sayName() 的时候,会先后执行两次搜索:

  • 首先,解析器会问:“实例 p 有 sayName 属性吗?”答:“没有。
  • ”然后,它继续搜索,再问:“ p 的原型有 sayName 属性吗?”答:“有。
  • ”于是,它就读取那个保存在原型对象中的函数。

而这正是多个对象实例共享原型所保存的属性和方法的基本原理。

总结:

  • 先在自己身上找,找到即返回
  • 自己身上找不到,则沿着原型链向上查找,找到即返回
  • 如果一直到原型链的末端还没有找到,则返回 undefined

最后更新: 2019年09月27日 10:24

原始链接: https://HowlCN1997.github.io/2020/01/17/简述Js中的原型与原型链/

× 请我吃糖~
打赏二维码