javascript-原型和原型链

loading 2022年10月25日 233次浏览

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(); // 报错

如图