原型

 原型要解决的问题

上图中,通过构造函数可以创建一个用户对象
这种做法有一个严重的缺陷,就是每个用户对象中都拥有一个sayHi方法,对于每个用户而言,sayHi方法是完全一样的,没必要为每个用户单独生成一个。

要解决这个问题,必须学习原型

原型是如何解决的

  1. 原型

   每个函数都会自动附带一个属性prototype,这个属性的值是一个普通对象,称之为原型对象

  1. 实例
    instance,通过new产生的对象称之为实例。
    > 由于JS中所有对象都是通过new产生的,因此,严格来说,JS中所有对象都称之为实例

  2. 隐式原型
    每个实例都拥有一个特殊的属性__proto__,称之为隐式原型,它指向构造函数的原型

  3. 显示原型
    构造函数指向原型对象的属性prototype
    这一切有何意义?

当访问实例成员时,先找自身,如果不存在,会自动从隐式原型中寻找
这样一来,我们可以把那些公共成员,放到函数的原型中,即可被所有实例共享

补充

隐式原型是 “从创建方式角度的叫法”,对象原型是 “从归属角度的叫法”,两者本质是同一个引用

原型链

什么是原型链

所有的对象都是通过new 函数的方式创建的

var u1 = new User('邓', '旭明'); // 对象 u1 通过 new User 创建
var u2 = { // 对象 u2 通过 new Object 创建
  firstName: '莫',
  lastName: '妮卡'
}
// 等效于
var u2 = new Object();
u2.firstName = '莫';
u2.lastName = '妮卡';

上面的代码形成的原型图如下

原型对象本身也是一个对象,默认情况下,是通过new Object创建的,因此,上面的两幅原型图是可以发生关联的

Object.prototype.__proto__比较特殊,它固定指向null

可以看出,u1的隐式原型形成了一个链条,称之为原型链

当读取对象成员时,会先看对象自身是否有该成员,如果没有,就依次在其原型链上查找

完整的链条

Function.prototype === Function.__proto__ 成立的本质是:Function 作为一个函数,必须遵循 “所有函数的隐式原型指向 Function.prototype” 的规则

对开发的影响

在原型上更改会产生多大影响

更改构造函数的原型会对所有原型链上有该构造函数的原型的对象产生影响

学会利用原型链判断类型

  1. instanceof关键字【常用】

   object instanceof constructor
   // 判断object的原型链中,是否存在constructor的原型

  1. Object.getPrototypeOf()【不常用】

   Object.getPrototypeOf(object);
   // 返回object的隐式原型

学会创建空原型的对象

  1. 利用Object.create()

   js    Object.create(target);    // 返回一个新对象,新对象以target作为隐式原型    

  1. 利用Object.setPrototypeOf()

   js    Object.setPrototypeOf(obj, prototype);    // 设置obj的隐式原型为prototype