【重学前端】JavaScript对象:基于原型的面向对象

188 阅读3分钟

什么是原型?

【重学JS】JavaScript对象:具有高度动态性的属性集合中提到过:在不同的编程语言中,设计者利用各种语言特性来抽象描述对象。

JavaScript就是基于原型的编程语言,利用原型来描述对象。Java是基于类的方式来描述对象。

“基于类”的编程提倡使用一个关注分类和类之间的关系开发模型。在这类语言中,总是先有类,再从类去实例化一个对象。类和类之间又可能会形成继承、组合等关系。类又往往与语言的类型系统整合,形成一定编译时的能力。

与此相对,“基于原型”的编程看起来更为提倡程序员去关注一系列对象实例的行为,而后才去关心如何将这些对象,划分到最近的使用方式相似的原型对象,而不是将它们分成类。基于原型的面向对象系统通过“复制”的方式来创建新的对象。一些语言的实现中,还允许复制一个空对象。这实际上就是创建一个全新的对象。

原型系统的“复制操作”有两种实现思路:

  • 一个是并不真的去复制一个原型对象,而是使得新对象持有一个原型的引用;
  • 另一个是切实地复制对象,从此两个对象再无关联。

显然,JavaScript选择了前一种方式。

JavaScript的原型

原型系统可以说:

  • 如果所有对象都有私有字段[[prototype]],就是对象的原型;
  • 读一个属性,如果对象本身没有,则会继续访问对象的原型,直到原型为空或者找到为止。

从ES6开始,JavaScript提供了一系列内置函数,以便更为直接地访问操纵原型。三个方法分别为:

  • Object.create根据指定地原型创建新对象,原型可以是null;
  • Object.getPrototypeof获得一个对象的原型;
  • Object.setPrototypeof设置一个对象的原型。

new的实现原理

new运算接受一个构造器和一组调用参数,实际上做了几件事:

  • 以构造器的prototype属性为原型,创建新对象;
  • 将this和调用参数传给构造器,执行;
  • 如果构造器返回的是对象,则返回,否则返回第一步创建的对象。
function myNew(fn, ...args) {
    let obj = Object.create(fn.prototype);
	let res = fn.call(obj, ...args);
	if (res && (typeof res === 'object' || typeof res === 'function')) {
		return res;
	}
	return obj;
}

new 客观上提供了两种方式,一是在构造器中添加属性,二是在构造器的prototype属性上添加属性。

ES6的class

ES6中引入了 class 关键字,并且在标准中删除了所有[[class]]相关的额私有属性描述,类的概念正式从属性升级成语言的基础设施,从此,基于类的编程方式成为了JavaScript的官方编程范式。