对象和类是面向对象的基础, 封装, 继承和多态是面向对象编程(OOP)的三大特性.
JavaScript提供了对象却缺乏类, 他不能和Java等语言一样显式的定义一个类. 但是JavaScript函数功能非常灵活, 我们可以使用构造函数和原型对象来实现类.
对象和类的概念
对象是面向对象编程中非常重要的一个概念, 一个对象是一个东西(某个人或者某件事)的描述.
对象包含特征和行为, 用OOP的术语来说, 特征是对象的属性, 行为是对象的方法.
类相当于一个模板, 基于这个模板可以创建不同的具体对象.
在JavaScript中一切都是基于对象的, 原型也是对象, JavaScript的继承和重用也是通过原型实现的.
构造函数
我们可以使用new Array()
创建一个数组, 使用new Object()
创建一个对象. Array()
和Object()
是JavaScript内置的两个构造函数, 尽管JavaScript没有提供类, 我们可以将Array和Object理解为”类”的概念.
构造函数也是函数, 定义构造函数和其它函数并没有语法上的区别. 唯一的区别就是构造函数的首字母应该大写, 这也是JavaScript的编程规范.
1 | // 定义Person()构造函数, 我们可以将它理解为Person类 |
foo实例对象和bar实例对象都是通过Person构造函数创建出来的, 但是修改其中一个的实例对象的属性和方法并不会影响的另一个实例对象的属性和方法.
constructor属性
当创建一个对象时, 一个特殊的属性就被JavaScript自动分配给这个对象了, 这个属性就是constructor属性. 当访问某个对象的constructor属性时, 就会返回创建这个对象的构造函数.
1 | function Person() { |
原型对象
在JavaScript中定义一个函数, 这个函数就会拥有prototype属性, 构造函数也不例外.
1 | function Person() { |
构造函数Person的prototype属性是一个对象, 他是属于函数的, 我们称这个属性为原型对象. 从Person类的角度出发, 可以理解为prototype属性是属于Person类的. 同时Person类的实例对象是没有prototype属性的, 上面代码中的
bingo.prototype
是undefined
, 说明prototype属性是共享的.
既然实例对象的prototype属性是一个对象, 那么我们就可以给这个对象添加属性和方法.
1 | function Person(name) { |
我们可以通过
hasOwnPrototype
方法查看对象是否包含某个属性或方法.
类的实现总结
- JavaScript没有类,但是构造函数可以实现类
- 按照JavaScript编程规范,构造函数的首字母应该大写
- 在创建对象时,JavaScript为这个对象分配了一个
constructor
属性,constructor
属性是对象构造函数的引用 - 函数在定义时拥有了
prototype
属性,prototype
属性也是一个对象 - prototype属性上的属性和方法是共享的,定义在
prototype
属性的属性和方法可以被类的实例对象使用 - 如果属性或者方法能够定义在
prototype
属性上,就不要定义在构造函数中,使用prototype
可以减少内存开销