一、什么是面向对象
对象并不是计算机领域凭空造出来的概念,它是顺着人类思维模式产生的一种抽象,面向对象编程也被认为是:更接近人类思维模式的一种编程范式。
对象有如下几个特征:
- 对象具有唯一标识性:即使完全相同的两个对象,也并非同一个对象。各种语言的对象唯一标识性都是用内存地址来体现的
- 对象有状态:同一对象可能处于不同状态之下。
- 对象具有行为:对象的状态,可能因为它的行为产生变迁
在JavaScript中,任何不同的 JavaScript 对象其实是互不相等的。关于对象的“状态和行为”,JavaScript 中的行为和状态都能用属性来抽象。
JavaScript还有其独有的特点:对象具有高度的动态性,这是因为 JS 赋予了使用者在运行时为对象添改状态和行为的能力。
JavaScript有两种属性:数据属性和访问器属性。
数据属性:
- value:就是属性的值。
- writable:决定属性能否被赋值。
- enumerable:决定 for in 能否枚举该属性。
- configurable:决定该属性能否被删除或者改变特征值。
访问器属性:(创建对象时可以使用get和set关键字来创建访问器属性)
- getter:函数或 undefined,在取属性值时被调用。
- setter:函数或 undefined,在设置属性值时被调用。
- enumerable:决定 for in 能否枚举该属性。
- configurable:决定该属性能否被删除或者改变特征值。
二、JavaScript的原型系统
在不同的编程语言中,设计者也利用各种不同的语言特性来抽象描述对象。最为成功的流派是使用“类”的方式来描述对象,这诞生了诸如 C++、Java 等流行的编程语言。这个流派叫做基于类的编程语言。还有一种就是基于原型的编程语言,它们利用原型来描述对象,比如JavaScript。
- “基于类”的编程提倡使用一个关注分类和类之间关系开发模型。
- “基于原型”的编程看起来更为提倡程序员去关注一系列对象实例的行为,而后才去关心如何将这些对象,而不是将它们分成类。
从 ES6 开始,JavaScript 提供了 class 关键字来定义类,这样的方案仍然是基于原型运行时系统的模拟。
JavaScript 的原型:如果所有对象都有私有字段 [[prototype]],就是对象的原型;读一个属性,如果对象本身没有,则会继续访问对象的原型,直到原型为空或者找到为止。
从 ES6 以来,JavaScript 提供了一系列内置函数,以便更为直接地访问操纵原型。三个方法分别为:
- Object.create 根据指定的原型创建新对象,原型可以是null;
- Object.getPrototypeOf 获得一个对象的原型。
- Object.setPrototypeOf 设置一个对象的原型。
在 ES3 和之前的版本中,“类”的定义是一个私有属性 [[class]],其访问方式是 Object.prototype.toString。
在 ES5 开始,[[class]] 私有属性被 Symbol.toStringTag 代替,Object.prototype.toString 的意义从命名上不再跟 class 相关。
new 操作在创建对象的时候具体做了哪些事情:
- 以构造器的 prototype 属性(注意与私有字段 [[prototype]] 的区分)为原型,创建新对象;
- 将 this 和调用参数传给构造器,执行;
- 如果构造器返回的是对象,则返回,否则返回第一步创建的对象。
new 这样的行为,试图让函数对象在语法上跟类变得相似,但是,它客观上提供了两种方式,一是在构造器中添加属性,二是在构造器的 prototype 属性上添加属性。
ES6 中引入了 class 关键字,并且在标准中删除了所有 [[class]] 相关的私有属性描述,类的概念正式从属性升级成语言的基础设施,从此,基于类的编程方式成为了 JavaScript 的官方编程范式。我们通过 get/set 关键字来创建 getter,通过括号和大括号来创建方法,数据型成员最好写在构造器里面。