prototype

只有函数有prototype属性

let a = {}let b = function () { }console.log(a.prototype) // undefinedconsole.log(b.prototype) // { constructor: function(){...} }

其实Object是一个全局对象,也是一个构造函数,以及其余根本类型的全局对象也都是构造函数:

function outTypeName(data, type) {    let typeName =  Object.prototype.toString.call(data)    console.log(typeName)}outTypeName(Object) //[object Function]outTypeName(String) // [object Function]outTypeName(Number) // [object Function]

为什么只有函数有prototype属性

JS通过new来生成对象,然而仅靠构造函数,每次生成的对象都不一样。

有时候须要在两个对象之间共享属性,因为JS在设计之初没有类的概念,所以JS应用函数的prototype来解决这部分须要被共享的属性,通过函数的prototype来模仿类:

当创立一个函数时,JS会主动为函数增加prototype属性,值是一个有constructor的对象。

以下是共享属性prototype的栗子:

function People(name) {    this.name = name}People.prototype.age = 23 // 岁数// 创立两个实例let People1 = new People('OBKoro1')let People2 = new People('扣肉')People.prototype.age = 24 // 长大了一岁console.log(People1.age, People2.age) // 24 24

People1People2的原型是People.prototype

原型链

__proto__Object.getPrototypeOf(target): 对象的原型

__proto__是对象实例和它的构造函数之间建设的链接,它的值是:构造函数的`prototype。

也就是说:__proto__的值是它所对应的原型对象,是某个函数的prototype

Object.getPrototypeOf(target)全等于__proto__

它是ES6的规范,兼容IE9,支流浏览器也都反对。

不要再应用__proto__:

  • __proto__属性没有写入 ES6 的注释,而是写入了附录。
  • 起因是它实质上是一个外部属性,而不是一个正式的对外的 API,只是因为浏览器广泛支持,才被退出了 ES6
  • 规范明确规定,只有浏览器必须部署这个属性,其余运行环境不肯定须要部署,而且新的代码最好认为这个属性是不存在的
  • 所以无论从语义的角度,还是从兼容性的角度,都不要应用这个属性,应该应用:Object.getPrototypeOf(target)(读操作)、Object.setPrototypeOf(target)(写操作)、Object.create(target)(生成操作)代替

构造函数是什么

所谓的构造函数,实际上就是通过关键字new来调用的函数:

let newObj = new someFn() // 结构调用函数

原型继承就是利用结构调用函数的个性

SubType.prototype = new SuperType();  // 原型继承:SubType继承SuperTypeSubType.prototype.constructor = SubType // 从新指定constructor指向 不便找到构造函数// 挂载SuperType的this和prototype的属性和办法到SubType.prototype上
  • 结构调用的第二点:将新对象的Object.getPrototypeOf(target)指向函数的prototype
  • 结构调用的第三点:该函数的this会绑定在新创建的对象上。(所以父类this申明的属性被所有子类实例共享)
  • 新对象赋值给SubType.prototype

原型链是什么

来看个例子:

function foo() { }const newObj = new foo() // 结构调用foo 返回一个新对象const newObj__proto__ = Object.getPrototypeOf(newObj) // 获取newObj的原型对象newObj__proto__ === foo.prototype // true 验证newObj的原型指向fooconst foo__proto__ = Object.getPrototypeOf(foo.prototype) // 获取foo.prototype的原型foo__proto__ === Object.prototype // true foo.prototype的原型是Object.prototype

能够用以下三句话来了解原型链

  1. 每个对象都领有一个原型对象: newObj的原型是foo.prototype
  2. 对象的原型可能也是继承其余原型对象的: foo.prototype也有它的原型Object.prototype
  3. 一层一层的,以此类推,这种关系就是原型链

原型链的起点: Object.prototype

Object.prototype是原型链的起点,所有对象都是从它继承了办法和属性。

Object.prototype没有原型对象

const proto = Object.getPrototypeOf(Object.prototype) // null