原型&原型链的理解

321 阅读4分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

前言

提到原型和原型链,相信很多小伙伴都知道这两个概念,而且也是经常会用到,对于我来说,因为之前也是就了解了下,没怎么去看更详细的解释或者用法,这几天在对js的一些基础知识点做一个回顾复习,正好趁此对原型、原型链、构造函数等概念做一下详细的个人理解。

1. 原型与原型链.PNG

上面这张图就是官方对原型&原型链做的一个详细图解,下面就结合这个图对原型的相关概念做一下个人的一些理解

原型

JavaScript高级程序设计 中对原型是这么解释的:

"每个函数都会创建一个 prototype 属性,这个属性是一个对象,包含应该由特定引用类型的实例共享的属性和方法。实际上,这个对象就是通过调用构造函数创建的对象的原型。"

下面用一个栗子来结合理解:

// 定义构造函数 Person
function Person(){
    this.name = '张三'
}
// 使用构造函数实例化对象
let p = new Person()

// 分别打印一下实例对象 p 和构造函数 Person
console.log(p,'实例对象')
console.dir(Person)

打印一下实例和构造函数

原型1.png

原型2.png

上面显示实例对象p有一个 [[Prototype]] 属性,而构造函数 Person 有一个 prototype 属性,它们二者是全等的,因此我们可以说实例对象的原型对象是指向构造函数的 prototype 属性的,二者是通过__proto__ 进行访问(也可以理解为连接)

__proto__

__proto__: 有些浏览器中也用 [[Prototype]] 表示,在所有的对象创建时都会默认添加一个 [[Prototype]] 属性,可以理解为一个隐式原型,prototype作为显式原型,或者说是一个容器(指针),指向的构造函数的 prototype属性,使用 对象.__proto__ 这种方式进行访问

构造函数

先说一下函数,在JavaScript高级程序中提到:每个函数都是 Function 的实例,是一种函数对象,都是由 Function 构造的实例,通过 new Function() 方式实例化的,只是一般我们用 函数声明(具名函数) 或者 函数表达式(匿名函数) 方式创建函数,ES6又新增了使用箭头函数方式创建。

构造函数: 通过 new 函数名来实例化对象的函数叫做构造函数,一般定义函数名时首字母需要大写,构造函数又分原生构造函数(如:Function、Object、Array、String、RegExp等)和自定义构造函数。特别的: 箭头函数无法使用new关键字,所以不是构造函数

原型链

我们创建一个实例对象后, 如果需要通过该实例对象去访问某个属性或者方法时,会先在自身上找, 没有找到就通过 __proto__ 去上一层构造函数的原型对象(prototype)上去找, 如果找到了就返回,如果还是没找到就再通过 __proto__ 去上一层找,直到 __proto__ 的结果为 null,没有该属性就返回 undefined,没有该方法也是 undefined,只是执行时会报错 实例对象.xxx is not a function。这样通过 __proto__ 在原型上查找的过程就形成了原型链。

下面还是结合一个栗子来理解:

// 定义一个构造函数
function Car(name){
    this.name = name
    // 在构造函数的原型属性上添加一个属性
    Car.prototype.count = 20
}
// 在 Object 构造函数的原型属性上添加一个属性
Object.prototype.color = 'white'

// 实例化对象
let Benz = new Car('奔驰')
console.log(Benz.name)       // '奔驰'
console.log(Benz.count)      // 20
console.log(Benz.price)      // undefined
console.log(Benz.color)      // color

原型链.png

总结

原型&原型链的个人理解.png

  1. 函数在创建时,会创建一个 prototype 属性,该属性是一个对象,指向实例的原型对象[[Prototype]], [[Prototype]] 是每个对象都有的一个属性(可以理解为隐式原型),实例对象通过 __proto__ 去访问构造函数的 prototype(显式原型),这样层层访问就形成了原型链。

  2. 所有构造函数都是 Function 的实例对象,它的构造函数是本身,Function 的 prototype 中的原型对象又指向 Object 的 prototype 属性

  3. 通过原型和原型链的方式可以实现属性和方法被多个实例对象共用

  4. 可以使用 es5 的方法 Object.getPrototypeOf() 获取对象的原型

  5. 使用 for...in 可以遍历对象(会遍历整个原型链),使用 hasOwnProperty() 方法判断某个属性或方法是否在当前对象上(不会遍历原型链),结合二者可以判断是否是原型链上的属性或方法

以上就是个人对原型&原型链的理解,有不对的地方希望能够指出,谢谢!!!

Thanks.png