• 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绑定、实例原型绑定

    优秀文章首发于聚享小站,欢迎关注!
  • 相关阅读:
    Go 语言简介(下)— 特性
    Array.length vs Array.prototype.length
    【转】javascript Object使用Array的方法
    【转】大话程序猿眼里的高并发架构
    【转】The magic behind array length property
    【转】Build Your own Simplified AngularJS in 200 Lines of JavaScript
    【转】在 2016 年做 PHP 开发是一种什么样的体验?(一)
    【转】大话程序猿眼里的高并发
    php通过token验证表单重复提交
    windows 杀进程软件
  • 原文地址:https://www.cnblogs.com/yesyes/p/15352073.html
Copyright © 2020-2023  润新知