# 原型

# prototype

每一个函数都具有prototype属性,即原型

function F() {}
console.log(F.prototype); // {constructor: ƒ}

这个prototype属性返回的是一个对象,是构造函数所创建实例的原型对象。

function F() {}
console.log(new F().__proto__ === F.prototype); // true

# constructor

每一个原型都有个constructor指向关联的构造函数

function F() {}
console.log(F === F.prototype.constructor); // true
console.log(F === new F().constructor); // true,由于实例没有constructor属性,则向上找原型的constructor属性

# __proto__

每一个对象都有__proto__属性,即隐式原型,指向创建该对象的函数的prototype

Object.prototype.__proto__ === null; // 比较特殊
Function.__proto__ === Function.prototype; // Function也是对象,也是函数,所以会被Function创建
Function.prototype.__proto__ === Object.prototype;

// Object.getPrototypeOf(foo) 根据实例对象获取原型对象

# 继承

  1. 原型链继承: 引用值共享问题
  2. 构造函数继承: 无法拿到原型上的方法
  3. 组合继承: 调用两次构造函数
  4. 寄生组合继承:Object.create

两种不好的使用:

// Bar.prototype会直接引用Foo.prototype,一旦修改Bar.prototype.name,则会修改Foo.prototype对象
Bar.prototype = Foo.prototype;

// 引用值共享问题。
Bar.prototype = new Foo();

目前比较好的:

// ES6 之前需要抛弃默认的 Bar.prototype.相当于Bar.prototype.__proto__ = Foo.prototype
// Object.create()的参数就是指向生成对象的原型
Bar.ptototype = Object.create(Foo.prototype);
// 一种polyfill
if (!Object.create) {
    Object.create = function(o) {
    function F(){} F.prototype = o;
    return new F();
    };

// ES6 开始可以直接修改现有的
Bar.prototype Object.setPrototypeOf( Bar.prototype, Foo.prototype );