引入
相信大家都使用过构造函数,它可以很方便的让我们构造出一个对象上所包含的属性和方法,并通过new关键词把我们所需要的对象构造出来,但当我们用到一些公共方法时,我们可能会遇到许多问题。
举个例子:我们通过构造函数创建一个小狗的对象,并添加属性和方法,并实例化出来
我们知道,小狗对象只有名字与年龄是不同的,而方法say是每个实例化小狗对象都拥有的,不需要做改变。但是这种写法所实例化的过程是这样的:
而我们的想要的效果是下面这样的:
在使用new关键字,每次创建一个对象的时候,都会在内存开辟一个新的空间,我们从上图可以看出,每只创建的小狗有一个say方法,这个方法都是独立的,但是功能完全相同。随着创建小狗的数量增多,造成内存的浪费就更多,这就是我们需要解决的问题。
我们很容易想到,在全局定义一个函数,在构造函数内部去引入这个对象不就行了吗?
但是其实这样写依然存在问题:
- 全局变量增多,会增加引入框架命名冲突的风险
- 代码结构混乱,会变得难以维护
原型的概念
- prototype:原型。每个构造函数在创建出来的时候系统会自动给这个构造函数创建,并且关联一个空的对象。这个空的对象,就叫做原型。
- 每一个由构造函数创建出来的对象,都会默认的和构造函数的原型关联;
- 当使用一个方法进行属性或者方法访问的时候,会先在当前对象内查找该属性和方法,如果当前对象内未找到,就会去跟它关联的原型对象内进行查找;
- 也就是说,在原型中定义的方法跟属性,会被这个构造函数创建出来的对象所共享;
- 访问原型的方式:构造函数名.prototype。
- 用图来理解就是:
那我们知道原型的特性后,我们来对其进行改造吧:
我们可以看到,在上面的代码里,本身Dog这个构造函数中是没有say这个方法的,我们通过Dog.prototype.say的方式,在构造函数Dog的原型中创建了一个方法,实例化出来的dog1、dog2会先在自己的对象先找say方法,找不到的时候,会去他们的原型对象中查找。
画个图理解:
在构造函数的原型中可以存放所有对象共享的数据,这样可以避免多次创建对象浪费内存空间的问题。