JavaScript原型(一)

72 阅读3分钟

prototype

概念:给其他对象提供共享属性的对象。也就是说prototype自己也是一个对象,只是被赋予了某个职能。

就如实现发布/订阅模式时,我们将subscriber称为订阅者,publisher称为发布者。并不是他们与其他对象有什么本质区别,只是一种约定。

同理,当某个对象为其他对象承担了共享属性的职能时,它就成了该对象的prototype,失去该职能也就不再是该对象的prototype

也就是我们在说prototype时,实际上表示的是两个对象的某种关系,比如A对象为B对象提供属性访问权限。所有对象都可以作为另一个对象的prototype

一个对象如何为另外一个对象提供属性访问?

在JavaScript规范中,明确描述了所有对象都有一个隐式的引用,它被称为这个对象的prototype原型。

QQ截图20220921102546.png

如上如所示,我们只申明了一个对象,但是在控制台可以发现它有__proto__属性,这意味着申明的a隐式的引用了另外一个对象的属性,置于__proto__属性中。

__proto__历史问题

ECMAScript 规范描述 prototype 是一个隐式引用,但之前的一些浏览器,已经私自实现了__proto__这个属性,使得可以通过a.__proto__ 这个显式的属性访问,访问到被定义为隐式属性的 prototype

QQ截图20220921103740.png 由于部分浏览器提前开了__proto__的口子,使得可以通过a.__proto__直接访问到原型,通过a.__proto__ = antherObj 直接设置原型。所以ECMAScript 2015规范,将__proto__属性纳入规范的一部分。

  • 可以通过Object.getPrototypeOf(obj)间接访问指定对象的prototype
  • 可以通过Object.setPrototypeOf(obj, anotherObj)间接设置指定对象的prototype

虽然在对象的prototype上有__proto__属性,实际上它是一个accessor property(访问器属性),在get方法里面调用getPrototypeOf,在set方法里面调用setPrototypeOf

扩展:访问器属性是什么?

对于JavaScript来说,属性并非只是简单的名称和值,JavaScript用一组特征attribute来描述属性property

  • 数据属性

QQ截图20220921140901.png

value:就是属性的值。
writable:决定属性能否被赋值。
enumerable:决定for in能否枚举该属性。
configurable:决定该属性能否被删除或者改变特征值。

  • 访问器(getter/setter)属性

个人理解:访问器属性,实际就是对对象的某个属性,进行取值,设置值,以及其他一些情况的操作。

QQ截图20220921143057.png

getter:函数或undefined,在取属性值时被调用。
setter:函数或undefined,在设置属性值时被调用。
enumerable:决定for in能否枚举该属性。
configurable:决定该属性能否被删除或者改变特征值。

prototype chain 原型链

概念:因为prototype本身也是对象,所以它也有自己的隐式引用,有自己的prototype对象。如此就构成了对象的原型==>原型==>原型的链条,直到某个对象的隐式引用为null,整个链条终止。

原型继承方式

  • 显示继承
  • 隐式继承

显示继承

前文有提到,具体的方式如下图

640.png 实际显示继承有两种方式

  • Object.setPropertyOf
  • Object.create

两者的差别主要

  • Object.setPropertyOf给我两个对象,我把其中一个设置为另一个的原型
  • Object.create,给我一个对象,它将作为我创建的新对象的原型。
  • 所以当我们已经拥有两个对象时,要构建原型关联,可以通过Object.setPrototypeOf来处理。
  • 当我们只有一个对象,想以它为原型,创建新对象,则通过Object.create来处理。

隐式继承

const user = {
    name:'Tom',
    age:12
}

这种创建方式叫做对象字面量,这种创建方式,实际有两层隐式行为

  • 隐式的通过new Object()创建对象
  • 隐式的进行原型继承