zoukankan      html  css  js  c++  java
  • JS对象进阶理解prototype、proto、constructor

    JS中最复杂的莫过于prototype、proto和constructor之间的三角关系,搞清楚它们之间的关系对理解JS这门语言很重要,下面是我画的一张关系图,本文以该图为例解释它们之间的关系。

    基本概念

    function People(){};
    var p1 = new People;
    var o1 = new Object;
    var f1 = new Function;
    

    【构造函数】用来初始化实例对象的函数是构造函数。图中浅绿色的People()、Object()、Function()函数是构造函数。

    【实例对象】通过构造函数的new操作符创建的对象是实例对象。图中橘黄色的p1、o1和f1都是实例对象。

    【prototype】prototype是构造函数的属性,指向实例的原型对象。同一个构造函数的实例对象拥有相同的原型对象,所以可以使用原型对象实现继承。

    function People(){};
    var p1 = new People;
    var o1 = new Object;
    var f1 = new Function;
    
    People.prototype === p1.__proto__; // true
    Object.prototype === o1.__proto__; // true
    Function.prototype === f1.__proto__; // true
    

    【constructor】constructor是原型对象的属性,指向对应的构造函数。

    function People(){};
    People.prototype.constructor === People; // true
    
    Object.prototype.constructor === Object; // true
    Function.prototype.constructor === Function; // true
    

    由于实例对象可以继承原型对象的属性和方法,所以实例对象也有constructor属性,指向对应的构造函数。

    function People(){};
    var p1 = new People;
    p1.constructor === People; // true
    
    var f1 = new Function;
    f1.constructor === Function; // true
    
    var o1 = new Object;
    o1.constructor === Object; // true
    

    【proto】 proto是实例对象的属性,指向对应的原型对象。

    function People(){};
    var p1 = new People;
    var f1 = new Function;
    var o1 = new Object;
    
    p1.__proto__ === People.prototype; // true
    f1.__proto__ === Function.prototype; // true
    o1.__proto__ === Object.prototype; // true
    

    详细说明

    第一部分

    People.prototype不仅是实例对象的原型对象,它自身也是一个实例对象,这也是为什么它有proto属性的原因。既然是实例对象肯定有对应的构造函数和原型对象:它的原型对象是Object.prototype;它的构造函数是People()。

    function People(){};
    
    var p1 = new People;
    People.prototype.__proto__ === Object.prototype; // true
    

    People.prototype作为原型对象时,自身拥有constructor属性,所以它会覆盖继承自原型对象Object.prototype的constructor属性。

    function People(){};
    
    var p1 = new People;
    People.prototype.hasOwnProperty('constructor'); // true
    People.prototype.constructor === People; // true
    

    Function.prototype和上面类似,当Function.prototype作为实例对象时它的原型对象也是Object.prototype;构造函数是Function()。

    Function.prototype.__proto__=== Object.prototype // true
    Function.prototype.constructor === Function // true
    

    Object.prototype也和上面类似,不仅是实例对象的原型对象,它自身也是一个实例对象。那么Object.prototype作为实例对象时,它的原型对象和构造函数是什么呢?答案:原型对象是null,构造函数是Object()。或许这也是为什么typeof null === 'object'

    // Object.prototype作为实例对象
    Object.prototype.__proto__ === null; // true
    
    // Object.prototype作为原型对象
    Object.prototype.constructor === Object; // true
    

    第二部分

    在JavaScript中,函数是Function类型的实例,所以函数也是对象。如果把函数People、函数Function和函数Object都看做实例,它们的构造函数都是Function(),它们的原型对象都是Function.prototype。

    function People(){};
    People.__proto__ === Function.prototype;// true
    Object.__proto__ === Function.prototype;// true
    Function.__proto__ === Function.prototype;// true
    

    实例对象People、Function和Object本身没有constructor属性,它们继承了原型对象Function.prototype的constructor属性。

    function People(){};
    People.constructor === Function;// true
    Object.constructor === Function;// true
    Function.constructor === Function;// true
    
    Function.hasOwnProperty('constructor') // false
    Object.hasOwnProperty('constructor') // false
    People.hasOwnProperty('constructor') // false
    

    所有函数都可以看做是构造函数Function()的new操作的实例化对象,所以它们的原型对象都是Function.prototype。

    Function.__proto__ === Function.prototype;// true
    Object.__proto__ === Function.prototype;// true
    People.__proto__ === Function.prototype;// true
    

    总结

    如果要解释原型、原型链和继承,一定要画图

    // 原型和原型链
    var People = function () {};
    
    var p1 = new People(); // {__proto__: {}}
    
    console.log(p1.__proto__ === People.prototype)
    
    console.log(People.prototype.__proto__ === Object.prototype)
    
    console.log(Object.prototype.__proto__ === null)
    
    
    // 继承:p1 先去构造函数People上找toString,找不到会沿着原型链去Object上找,这就是继承
    console.log(p1.toString); //  ƒ toString() { [native code] }
    

    使用new调用函数的时候,主要做了三个工作:创建实例对象、调用内部的constructor函数初始化this绑定、实例原型绑定

    优秀文章首发于聚享小站,欢迎关注!
  • 相关阅读:
    字符串案例1
    字符串1
    标准类制作
    构造方法
    封装
    成员变量和局部变量
    类和对象的案例

    案例
    方法的参数传递
  • 原文地址:https://www.cnblogs.com/yesyes/p/15352073.html
Copyright © 2011-2022 走看看