原型和原型链

114 阅读3分钟
来源

在面对对象的编程思想中,继承是一个很重要的概念,而且被广泛运用,比如java中,子类可以继承父类的部分属性和方法,在JavaScript中,在es6之前是没有class这个概念的,JavaScript的开发者们,为了给js增加共享功能,就创造了原型这一概念,来实现数据和方法的共享。

原型的定义

在ECMAScript2019规范中,原型(prototype)被定义为:给其他对象提供共享属性的对象

《 javascript高级程序设计 》中这样描述原型:

每个函数都会创建一个prototype属性,这个属性是一个对象,包含应该由特定引用类型的实例共享的属性和方法。实际上,这个对象就是通过调用构造函数创建的对象的原型。使用原型对象的好处是,在它上面定义的属性和方法都可以被对象实例共享。原来在构造函数中直接赋给对象实例的值,可以直接赋值给它们的原型。

《 你不知道的javascript 》中对原型的描述

javascript中的对象有一个特殊的 [[Prototype]] 内置属性,其实就是对其他对象的引用。几乎所有的对象在创建时 [[Prototype]] 都会被赋予一个非空的值。

小结
  1. 原型是一个对象,为其他对象提供共享属性的对象,又称原型对象。可以说原型不是一个固定的对象,它只是承担了某种职责。当某个对象,承担了为其他对象提供共享属性的职责时,它就成了该对象的原型。换而言之,不同对象的原型可能都是不一样的。
  2. 几乎所有对象在创建时都会被赋予一个非空的值作为原型对象的引用,来实现共享数据的效果。
  3. 在不同的对象上原型存放的方式也有所差别
  • 函数(function):函数是一种特殊的对象,函数的原型存放在prototype属性上
  • 对象(Object): 普通对象的原型是存放到内置属性 [[Prototype]] 上,可以通过对象的 proto 来访问对象的原型
  • 数组(Array): 数组也是一种特殊的对象,但与函数不同的是它的原型和普通对象一样,也是存放到内置属性 [[Prototype]] 上,可以通过数组的 proto 来访问数组的原型
prototype 与 __proto__

prototype 一般称为显式原型,__proto__一般称为隐式原型。 每一个函数在创建之后,在默认情况下,会拥有一个名为 prototype 的属性,这个属性表示函数的原型对象。

原型链

当我们访问一个JS对象属性的时候,JS先会在这个对象定义的属性里找,找不到就会沿着这个对象的__proto__这个隐式原型关联起来的链条向上一个对象查找,这个链条就叫原型链。

function Fn() {}
Fn.prototype.name = 'coboy'
let fn1 = new Fn()
fn1.age = 18
console.log(fn1.name) // coboy
console.log(fn1.age) // 18

fn1是Fn函数new出来的实例对象,fn1.age是这个实例对象上属性,fn1.name则从Fn.prototype原型对象而来,因为fn1的__proto__隐式原型就是指向Fn这个函数的原型对象Fn.prototype。原型链某种意义上是让一个引用类型继承另一个引用类型的属性和方法。

function Fn(){}
Fn.prototype.name = 'coboy'
let fn1 = new Fn()
fn1.name = 'cobyte'
console.log(fn1.name) // cobyte

当访问fn1这个实例对象的属性name的时候,JS先会在fn1这个实例对象的属性里查找,刚好fn1定义了一个name属性,所以就直接返回自身属性的值cobyte,否则就会继续沿着原型链向fn.prototype上去找,name就会返回coboy.

Vue中使用: Vue.prototype.$http = http

方便在组件中通过this直接调用