1. 基础
本文一共提到三种属性:
- [[prototype]] (proto)
- prototype
- constructor
对象含有proto和constructor。
函数也是一种对象,除了proto和constructor外还含有prototype。
本文中采用如下代码作为讲解例子:
function Foo() {...};
let f1 = new Foo();
本文部分图片来源csdn博主:码飞_CC。
2. [[prototype]] (proto)
2.1 含义
首先看图
__proto__属性为对象所拥有,因此可以看到图中__proto__都是由一个对象(函数)指向他们的原型对象(父对象)。
2.2 作用
当访问一个对象的属性时,如果该对象中没找到这个属性,就通过__proto__的指向从它的原型对象中找,如果还找不到就继续往上找,以此类推,一直到原型链的顶端null为止。
若到了null还继续向上则相当于在null上取值,会报错,这么一条通过__proto__连接的从初始对象到null的一条链称为原型链。
3. prototype
3.1 含义
首先看图
prototype属性只有函数才有!它由函数指向对象。
它的含义是函数的原型对象,也就是这个函数所创建的对象的原型对象(看图即可明白,有点拗口)。由此可得:
f1.__proto__ === Foo.prototype
3.2 作用
使得该函数所创建的对象可以找到公用的属性或方法。
如:
let f1 = new Foo();
let f2 = new Foo();
f1和f2这两个对象都可以通过proto来连接到Foo.prototype这个它们的原型对象来共享属性或方法。
任何函数在创建时,都会默认创建该函数的prototype对象。
4. constructor
首先看图
constructor属性为对象所拥有,它是从一个对象(函数)指向一个函数,含义就是指向该对象的构造函数。
每个对象都有constructor,但是这个属性可能是自己显式定义的也可能是继承得来的。如果单从含有这个属性来讲,那么只有prototype对象才有。因此有:
Foo.prototype.constructor() === Foo();
Function()这个对象(函数)比较特殊,它的构造函数就是自己,而所有的函数和对象的constructor终点都是Function(),也就是所有函数和对象都是由Function()构造函数得来。
5.总结
首先看图
-
__proto__从对象(函数)指向对象,作用是当访问一个对象的属性时,如果该对象内部不存在这个属性,那么就会去它的__proto__属性所指向的那个对象(父对象)里找,直到__proto__属性的终点null。这样也就构成了一条原型链。
-
prototype从函数指向对象,作用就是让该函数所实例化的对象们都可以找到公用的属性和方法,即f1.proto === Foo.prototype
-
constructor从对象(函数)指向函数,含义就是指向该对象的构造函数,所有对象(函数)最终的构造函数都指向Function()。
6.一些额外例子
6.1 不要随便重写原型
在实例化前先定义好原型,实例对象可以通过原型链找到sayName()方法
function Person() { }
Person.prototype = {
constructor: Person,
name: "yoimiya",
age: 29,
job: "Software Engineer",
sayName() {
console.log(this.name);
}
};
let friend = new Person();
friend.sayName(); // yoimiya
在实例化后才重写原型,会导致实例获取不到新原型的属性和方法,因为实例的__proto__仍然指向旧原型。
function Person() { }
let friend = new Person();
Person.prototype = {
name: "yoimiya",
age: 29,
job: "Software Engineer",
sayName() {
console.log(this.name);
}
};
friend.sayName(); // 报错
如图