基础知识

prototype__proto__的区分

个人对两个概念的理解

  • prototype存在的意义?
    疑问来自于:prototype是每个函数的模板,储存了函数的属性和方法,那为什么我们不可以直接在函数中加上方法属性,为什么非要如下对构造函数进行书写呢:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    function Person(name){
    this.name = name;
    }
    Person.prototype.sayhello = function(){console.log("hello");};

    const Bob = new Person("Bob");
    const Alice = new Person("Alice");
    Bob.sayhello();
    //此时Bob和Alice都会继承父类Person的prototype里的方法以及自带的name属性。

    解答:
    若是按照如下书写,不使用prototype:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    function Person(name){
    this.name = name;
    this.sayhello = function(){
    console.log("hello");
    }
    }
    const BOb = new Person("Bob");
    const Alice = new Person("Alice");
    Bob.sayhello();
    console.log(Alice.sayhello === Bob.syahello);//输出false,因为它们为独立函数

    那么每次实例化一个新的对象,都会在该对象内部实例化一个新的方法,会导致内存大大浪费,如上述代码。
    所以,我们会使用prototype属性给原型构造函数设定属性和方法,以便在重复实例化对象的时候出现不必要的内存浪费,并且还可以继承原型构造函数的方法。
    如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    // 父类(人类)
    function Person(name) {
    this.name = name;
    }
    Person.prototype.sayHello = function() {
    console.log(`我是 ${this.name}`);
    };

    // 子类(学生类)
    function Student(name, grade) {
    // 继承父类属性
    Person.call(this, name);
    this.grade = grade;
    }
    // 继承父类方法(关键!)
    Student.prototype = Object.create(Person.prototype);
    Student.prototype.constructor = Student;

    // 添加子类专属方法
    Student.prototype.study = function() {
    console.log(`${this.name} 在学习`);
    };

    const alice = new Student("Alice", 90);
    alice.sayHello(); // 继承自 Person 的方法
    alice.study(); // 子类专属方法

    这里就可以看出构造函数的方法属性一条龙继承下来。

  • 对于__proto__

    该属性是每个对象的固有属性!(非标准,ES6 后被 Object.getPrototypeOf 取代)
    而刚刚说的prototype只有构造函数才具有该属性。
    每个对象的__proto__属性即指向了其原型构造函数的prototype属性,即其中的属性和方法。
    使用如下代码:

    1
    console.log(Bob.__proto__);

    因为Bob.__proto__会指向Person.prototype,所以输出的仅为:

    1
    2
    3
    4
    {
    sayHello: function() { console.log("hello"); },
    constructor: Person
    }

    不会包含 this.name = namethis.name 是实例属性,直接存储在 BobAlice 对象中,不会出现在原型链

区分

属性 类型 存在对象 用途 访问方式
prototype 函数属性 仅函数对象 定义新对象的原型 Function.prototype
__proto__ 对象属性 所有对象 指向当前对象的原型,即当前对象原型的prototype Object.__proto__(不推荐)

如下代码即可很快区分:

1
2
3
4
5
6
7
8
function Foo() {}
const foo = new Foo();

//Foo 的原型链
FooFoo.prototypeObject.prototypenull

// foo 的原型链
foo → Foo.prototypeObject.prototypenull
  • 关键点
    • foo.__proto__ === Foo.prototype(新对象的 __proto__ 指向构造函数的 prototype)。
    • Foo.prototype.__proto__ === Object.prototype(函数的 prototype 默认继承自 Object.prototype)。
  • 特别注意:
    • prototype 是函数用来定义新对象原型的“模板”。不是对象的上级原型!