现代JS学习笔记:原型与继承

Posted by Mars . Modified at

学习内容:《现代JavaScript教程》

1. 原型与继承

1.1 什么是原型

原型,通俗的理解就是一个东西最普通,最广泛,最标准,不带有任何特色的原始模型。

比如说橘子,可能它细分有很多品种:有八瓣的有十瓣的,有剥皮吃的有不剥皮吃的,有酸的有甜的。但是,所有的橘子通常讲都应该是分瓣的,都应该有皮,都应该是是树上结出来的,这就是橘子的原型具有的性质。橘子的原型就是一个最普通、最大众的橘子,所有的具体的橘子品种都应该含有橘子原型的特点,然后才是各个橘子自身的特点。 一个对象的原型理论上是这个对象高一层级类别的对象,所具有的属性相对这个对象应该更抽象化。这个对象是原型对象的一种特例。

1.2 原型继承

所有的对象,都有一个内置的,隐藏的[[prototype]]属性,它的值要么是一个对象,要么是null。

[[prototype]]属性是不直接访问的,需要通过对象的__proto__属性访问。

__proto__属性不是直接访问[[prototype]],而是一对getter/setter,用于读取或修改[[prototype]]。

对象obj的[[prototype]]属性值对象,就是该对象obj的原型对象。

★ 写入和删除从原型对象继承来的属性,不会对原型对象本身的属性产生影响,而是操作在继承的对象中。(当写入的属性在对象本身内部不存在,就会在本地新建一个属性,无论原型链中是否有这个属性。可以理解为这些继承来的属性都是只读的,写入还是在本地。)

for..in 循环会遍历到本身的属性和继承的属性。所有其他的键/值获取方法仅对对象本身起作用,不返回继承的属性。

对象在查询属性时,如果查询的不是对象自身的属性,对象就会自动沿着原型链向上寻找,直到找到最近的并返回。如果到了原型链顶端仍未找到,就返回undefined。

1.3 函数(构造函数)的prototype属性

  • 任何一个函数都自带一个键名为prototype的常规属性;
  • 这个属性值在使用new操作符操作函数时候,会自动成为生成新对象的原型[[prototype]]对象;
  • 一般用于构造函数,手动设置这个prototype属性可以变更构造实例对象的默认原型对象;
  • 普通非构造函数也自动带有这个属性,只不过默认的 “prototype” 是一个只有属性 constructor 的对象,属性 constructor 指向函数自身。(默认情况下,所有函数都有 F.prototype = {constructor:F},所以我们可以通过访问它的 “constructor” 属性来获取一个对象的构造器。)

1.4 原生的原型

  • Object()、Array()、Date()这类构造函数是JavaScript语言内部自带的,我们无需自己定义就能使用。
  • 这些原生的构造函数也存在自己的prototype属性,内部已经写好了各种有用的方法,比如toString方法。
  • 这样我们在创建一个对象或数组实例的时候,就自动继承了Object.prototype或Array.prototype,它们里面的方法就可以在我们创建的对象里使用了。
  • 规范规定:所有原生原型顶端都是 Object.prototype。也就是说,Object.prototype上端再没有其他原型对象,Object.prototype.__proto__会返回null
  • 其他原生原型的原型对象,都是Object.prototype,除了Object自身之外。例如: Array.prototype.__proto__== Object.prototype;
  • 基本数据类型,比如String、Number和Boolean,也有自己的原生构造函数。虽然基本数据类型变量本身没有属性,但是当试图访问一个基本类型变量的属性时,为了使这些基本类型也能使用一些方法,一个临时的包装器对象会被创建,使用的正是这些原生的构造函数。他们也有自己的prototype。比如Number.prototype对象里面就含有toFixed()方法。

!永远尽量不要更改原生原型。

例如Number.prototype.someFunction = ….这样的修改会直接传递到所有数字包装器对象上,所有人在这个对象上修改会互相影响,很容易出现错误。

1.5 直接访问原型的几种现代方法

  • Object.create(proto, [descriptors]) —— 利用给定的 proto 作为 [[Prototype]](可以是 null)和可选的属性描述来创建一个空对象。
  • Object.getPrototypeOf(obj) —— 返回对象 obj 的 [[Prototype]](与 proto 的 getter 相同)。
  • Object.setPrototypeOf(obj, proto) —— 将对象 obj 的 [[Prototype]] 设置为 proto(与 proto 的 setter 相同)。

Object 与 Function 的原型关系

Object 与 Function 的原型关系

Keywords: JavaScript
previousPost nextPost
已经有 1000000 个小伙伴看完了这篇推文。