原型与原型链

原型(公用属性)

在 javascript 中,函数都是对象,可以有属性。 每个函数都有一个特殊的属性叫作原型(prototype),这个属性会指向函数的原型对象。JavaScript 的原型对象中,还包含了一个 constructor 属性,这个属性对应创建所有指向改原型的实例的构造函数。

每个对象都有 __proto__ 属性,但只有函数对象才有 prototype 属性。

在使用构造函数生成实例的时候,prototype 属性会成为该对象实例的原型。constructor 指向该实例的构造函数(prototype 属性所在的函数)。

上述代码中,Foo 为构造函数,p1p2 是该构造函数的实例对象,Fooprototype 属性就是这两个实例的原型对象,所以它们都可以使用.age 方法,这个方法在两个实例的__proto__属性中。constructor 属性指向含有该原型的构造函数 Foo

实例对象.__proto__ === 函数.prototype


原型对象的属性不是实例对象自身的属性。只要修改原型对象,变动就立刻会体现在所有实例对象上。这是因为实例对象其实没有age属性,都是读取原型对象的age属性。当实例对象本身没有某个属性或方法的时候,它会到原型对象去寻找该属性或方法。

如果某个实例对象自身就有某个属性或方法,它就不会再去原型对象寻找这个属性或方法,所以改变原型对象上的值也不会影响该实例。
构造函数生成的实例只有__proto__属性,没有prototype 属性。

原型链

  • 当我们访问对象的一个属性或方法时,它会先在对象自身中寻找,如果有则直接使用,如果没有则会去原型对象中寻找,如果找到则直接使用。如果没有则去原型的原型中寻找,直到找到Object对象的原型,Object对象的原型没有原型,如果在Object. prototype中依然没有找到,则返回undefined
    Object是JS中所有对象数据类型的根基,在Object.prototype上的__proto__属性指向null

  • 重要公式:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    var 对象 = new 函数()
    对象.__proto__ === 对象的构造函数.prototype

    // 推论
    var number = new Number()
    number.__proto__ = Number.prototype
    Number.__proto__ = Function.prototype // 因为 Number 是 Function 的实例

    var object = new Object()
    object.__proto__ = Object.prototype
    Object.__proto__ = Function.prototype // 因为 Object 是 Function 的实例

    var function = new Function()
    function.__proto__ = Function.prototype
    Function.__proto__ == Function.prototye // 因为 FunctionFunction 的实例!
  • __proto__prototype 的区别是什么?

    1. 不能断章取义,__proto__prototype 只是两个 key 而已。
    2. 我们一般研究对象的__proto__和函数的prototype
    3. 对象.__proto__ === 某函数.prototype
    4. 如果把函数看成对象,那么函数.__proto__ === Function.prototype
    5. 如果把 Function 看成对象,那么 Function.__proto__ === Function.prototype