了解原型

无论何时,只有创立一个函数,就会依照特定的规定为这个函数创立一个prototype属性(指向原型对象)。默认状况下,所有原型对象主动取得一个名为constructor的属性,指回与之关联的构造函数。
在定义构造函数时,原型对象默认只会取得constructor属性,其余的所有办法都继承自Object。每次调用构造函数创立一个新实例,这个实例的外部[[Prototype]]指针就会被赋值为构造函数的原型对象。脚本中没有拜访这个[[Prototype]]个性的规范形式,但Firefox/Safari/Chrome会在每个对象裸露__proto__属性,通过这个属性能够拜访对象的原型。

实例与构造函数原型有间接的分割,但实例与构造函数之间没有

这种关系不好可视化,但能够通过上面的代码来了解原型的行为

    function Person() {}    // 申明之后,构造函数就有了一个与之关联的原型对象    console.log(typeof Person.prototype);    console.log(Person.prototype)    // 如前所述,构造函数有一个prototype属性    // 援用其原型对象,而这个原型对象有一个constructor属性,援用这个构造函数    // 换句话说,两者循环援用    console.log(Person.prototype.constructor === Person)  // true    // 失常的原型链都会终止于Object的原型对象    // Object原型的原型是null    console.log(Person.prototype.__proto__ === Object.prototype) // true    console.log(Person.prototype.__proto__.constructor === Object) // true    console.log(Person.prototype.__proto__.__proto__ === null) // true    let person1 = new Person()    let person2 = new Person()    // 构造函数、原型对象和实例时3个齐全不同的对象    console.log(person1 !== Person) // true    console.log(person1 !== Person.prototype) // true    console.log(Person.prototype !== Person) // true    // 实例通过__proto__链接到原型对象,它理论指向暗藏个性[[Prototype]]    // 构造函数通过prototype属性链接到原型对象    // 实例与构造函数没有间接分割,与原型对象有间接分割    console.log(person1.__proto__ === Person.prototype) // true    console.log(person1.__proto__.constructor === Person) // true        // 同一个构造函数创立的两个实例,共享同一个原型对象    console.log(person1.__proto__ === person2.__proto__) // true        // instanceof 查看实例的原型链中是否蕴含指定构造函数的原型    console.log(person1 instanceof Person) // true    console.log(person1 instanceof Object) // true    console.log(Person.prototype instanceof Object) // true


下面的图片展现了Person构造函数、Person的原型对象和Person现有两个实例之间的关系。
留神:Person.prototype指向原型对象,而Person.prototype.constructor指回Person构造函数。
原型对象蕴含constructor属性和其余起初增加的属性。
Person的两个实例person1和person2都只有一个外部属性指回Person.prototype,而且两者都与构造函数没有间接分割。
另外要留神,尽管这两个实例都没有属性和办法,但person1.sayName()都能够失常调用,这是因为对象属性查找机制的起因。
尽管不是所有实现都对外暴漏了[[Prototype]],但能够应用isPrototypeOf()办法确定两个对象之间的这种关系,实质上,isPrototypeOf()会在传入参数的[[Prototype]]指向调用它的对象时返回true,如下所示

    console.log(Person.prototype.isPrototypeOf(person1) // true    console.log(Person.prototype.isPrototypeOf(person2)) // true

这里通过原型对象调用isPrototypeOf()办法查看了person1和person2.因为这两个例子外部都有链接指向Person.prototype,所以后果都返回true。
ESMAScript的Object类型有一个办法叫Object.getPrototypeOf(),返回参数的外部个性[[Prototype]]的值。例如:

    console.log(Object.getPrototypeOf(person1) === Peron.prototype // true    console.log(Object.getPrototypeOf(person1).name // '66'

第一行代码简略确认了Object.getPrototypeOf()返回的对象就是传入对象的原型对象。第二行代码则获得了原型对象上name属性的值,即'66'。应用Object.getPrototypeOf()能够不便地获得一个对象的原型,而这在通过原型实现继承时显得尤为重要。
能够通过Object.create()来创立一个新对象,同时为其指定原型:

    let biped = {        numLegs: 2    }    let person = Object.create(biped)    person.name = '66'    console.log(person.name) // '66'    console.log(person.numLegs) // 2    console.log(Object.getPrototypeOf(person) === biped) // true

原型层级

TODO...