prototype
prototype是函数特有的属性,每个函数的prototype属性指向了一个对象,这个对象正是调用该构造函数而建立的实例的原型。下面例子中person1和person2就是Person的实例。
举个例子:
function Person(){}
Person.prototype.name = 'Tom';
var person1 = new Person();
var person2 = new Person();
console.log(person1) //===> Tom
console.log(person2) //===> Tom
什么是原型?
每个一JavaScript对象(null除外)在创建的时候就会与之关联另一个对象,这个就像就是我们所说的原型,每个对象都会从原型** 继承 ** 属性。
让我们用一张图表示构造函数和实例原型之间的关系:
上图中Person.prototype 表示实例原型。
_proto_
每一个JavaScript对象(除了null)都具有的一个属性,叫做_proto_,这个属性会指向该对象的原型
举个例子:
function Person(){}
var person = new Person();
console.log(person._proto_ === Person.prototype); // ture
更新关系图:
实例对象和构造函数都可以指向原型。
重要提示:
绝大部分的浏览器都支持这个非标准的方法访问原型,然而它并不存在于Proson.prototype中,实际上,它都是来自于Object.prototype,与其说是一个属性,不如说是一个getter/setter,当使用obj._proto_ 时,可以理解成返回了Objiect.getPrototypeOf(obj)
constructor
原型指向构造函数倒是有的,这就要讲到第三个属性:constructor,每个原型都有一个 constructor 属性指向关联的构造函数。
function Person() {
}
console.log(Person === Person.prototype.constructor); // true
更新关系图如下:
根据上述可以得出一下结论:
functino Person(){}
var person = new Person()
console.log(person ._proto_ === Person.prototype) // true
console.log(person.constructor === Person) // true
console.log(Person.prototype.constructor === Person) // true
console.log(Object.getPrototypeOf(person) === Person.prototype) // true
需要注意:
其实person中并没有constructor属性,当不能读取constructor属性时,会从person的原型也就是Person.prototype中读取,也就是说。
person.constructor === Person.prototype.constructor
实例的原型
当读取实例的属性时,如果找不到就会查找与对象关联的原型中的属性,如果还是查不到,就去找原型的原型。也就是顺着原型链查找,直到顶层为止。
举个例子:
fuction Person(){}
Person.prototype.name = 'Tom';
var person = new Person()
person.name = 'kelly'
console.log(person.name) // 'kelly'
delete person.name
console.log(person.name) // 'Tom'
这个例子可以说明当个实例person添加了name属性时,打印person.name的时候,结果就是kelly。当删除person的name属性时,打印person.name时就会顺着person._proto_(原型链)去查找。正好Perosn.prototype(person的原型)中有name属性,返回结果Tom。
如果原型中没有查找到,就会查找原型的原型。
原型的原型
原型也是对象,既然是对象就会有原型。
原型对象就是通过Object构造函数生产的,实例的_proto_指向构造函数的prototype。
跟新关系图如下:
原型链
上图中相互关联的原型组成的链状结构就是原型链。也就是黄色的这条线。
最终指向null
最后 最后
来一张可以说明一起的图例: