原型与原型链

  • 面向对象编程很重要的一个方面,就是对象的继承。A对象通过继承B对象,就能直接拥有B对象的所有属性和方法。这对于代码的复用是非常有用的。

  • 大部分面向对象的编程语言,都是通过“类”来实现对象的继承,JavaScript语言的继承则是通过“原型对象”(prototype)。

prototype__proto__

  • prototype原型对象的作用
    看一段代码
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    //构造函数
    function person(name){
    this.name = name;
    }
    //生成对象
    var jack = new person('jack');
    console.log(jack); //打印结果为 person{name: 'jack'}
    consoloe.log(jack.name); //打印结果为jack

    console.log(jack.gender); //打印结果为 undefined

    //为构造函数的原型对象添加属性
    person.prototype.gender = 'male';

    console.log(jack.gender); //打印结果为 male
  1. 以上代码构造了一个函数person
  2. 生成对象jack,对象jack的gender打印结果是undefined
  3. 将函数person的prototype原型对象的属性gender设为 ‘male’
  4. 此时原本对象jack中没有的属性gender,打印出的值为 ‘male’
  5. 由于设置prototype的gender属性这个动作,实现了属性的共享
  6. 因此每个构造函数都有一个prototype原型对象

JavaScript继承机制的设计思想就是,prototype原型对象的所有属性和方法,都能被实例对象共享.也就是说,如果属性和方法定义在原型上,那么实例对象就能共享,不仅节省了内存,还体现了实例对象之间的联系.

  • __proto__属性
    看一段代码

    1
    2
    3
    4
    5
    6
    var n1 = 1;
    var n2 = new Number(1);

    console.log(n1); //打印结果为 1
    console.log(n2); //打印结果为 Number {1}
    console.log(n1.toString()); //打印结果为 '1'

    __proto__

  1. 声明n1为普通类型数字1,声明n2为数字函数构造1
  2. 仅从打印结果来看,n1是普通类型没有属性,只有对象有属性,但是在toString的过程中,JavaScript会将数字(简单类型)转化为对象(复杂类型),并从复杂类型中寻找toString()对应的值
  3. 不必要给每个对象一个toString和valueOf,JavaScript的做法是把toString和valueOf放在一个公用属性对象里,然后让每个对象的__proto__存储这个公用属性对象
  4. 每个对象都有一个__proto__属性,并且指向它的prototype原型对象

  • 重要公式
    var 对象 = new 函数();
    对象.__proto__ === 函数.prototype;

    1
    2
    3
    4
    5
    //由公式可知
    Object.__proto__ === Function.prototype
    Function.__proto__ === Function.prototype
    Function.prototype.__proto__ === Object.prototype
    Object.prototype.__proto__ === null

    总结

    • 当new一个构造函数时,则创建了一个函数实例,那么 函数实例.__proto__ === 该构造函数.prototype
    • 所有函数都是有Function,那么 被构造出来的函数.__proto__ === Function.prototype
    • 所有构造函数的原型对象都是由Object构造出来的,那么 所有构造函数.prototype.__proto__ === Object.prototype

原型链

  • JavaScript规定,素有对象都有自己的原型对象(prototype)

  • 一方面任何一个对象,都可以充当其他对象的原型,另一方面原型对象也是对象,所以它有自己的原型,因此就会形成一个原型链:对象到原型,再到原型的原型

  • 如果一层层地上溯,所有对象的原型最终都可以上溯到Object.prototype,即Object构造函数的prototype属性.也就是说,所有对象都继承了Object.prototype的属性

  • Object.prototype的原型是null,由于null没有任何属性,原型链便到此为止

number ---> Number.prototype ---> Object.prototype ---> null

prototype