Js中 constructor, prototype, __proto__ 详解

Souleigh ✨
• 阅读 1060

本文为了解决以下问题:

__proto__(实际原型)和prototype(原型属性)不一样!!! constructor属性(原型对象中包含这个属性,实例当中也同样会继承这个属性) prototype属性(constructor.prototype原型对象) __proto__属性(实例指向原型对象的指针)

首先弄清楚几个概念:

什么是对象? 若干属性的集合

什么是原型? 原型是一个对象,其他对象可以通过它实现继承。

哪些对象有原型? 所有的对象在默认情况下都有一个原型,因为原型本身也是对象,所以每个原型自身又有一个原型(只有一种例外,默认的对象原型在原型链的顶端) 任何一个对象都可以成为原型

接下来就是最核心的内容:

constructor 属性

constructor属性始终指向创建当前对象的构造函数。

    var arr=[1,2,3];
    console.log(arr.constructor); //输出 function Array(){}
    var a={};
    console.log(arr.constructor);//输出 function Object(){}
    var bool=false;
    console.log(bool.constructor);//输出 function Boolean(){}
    var name="hello";
    console.log(name.constructor);//输出 function String(){}
    var sayName=function(){}
    console.log(sayName.constrctor)// 输出 function Function(){}

    //接下来通过构造函数创建instance
    function A(){}
    var a=new A();
    console.log(a.constructor); //输出 function A(){}

以上部分即解释了任何一个对象都有constructor属性,指向创建这个对象的构造函数.

prototype属性

注意:prototype是每个函数对象都具有的属性,被称为原型对象,而proto属性才是每个对象才有的属性。一旦原型对象被赋予属性和方法,那么由相应的构造函数创建的实例会继承prototype上的属性和方法。

    //constructor : A
    //instance : a
    function A(){}
    var a=new A();

    A.prototype.name="xl";
    A.prototype.sayName=function(){
        console.log(this.name);
    }

    console.log(a.name);// "xl"
    a.sayName();// "xl"

    //那么由constructor创建的instance会继承prototype上的属性和方法

constructor属性和prototype属性

每个函数都有prototype属性,而这个prototype的constructor属性会指向这个函数。

    function Person(name){
        this.name=name;
    }
    Person.prototype.sayName=function(){
        console.log(this.name);
    }

    var person=new Person("xl");

    console.log(person.constructor); //输出 function Person(){}
    console.log(Person.prototype.constructor);//输出 function Person(){}
    console.log(Person.constructor); //输出 function Function(){}

如果我们重写(重新定义)这个Person.prototype属性,那么constructor属性的指向就会发生改变了。

    Person.prototype={
        sayName:function(){
            console.log(this.name);
        }
    }

    console.log(person.constructor==Person); //输出 false (这里为什么会输出false后面会讲)
    console.log(Person.constructor==Person); //输出 false

    console.log(Person.prototype.constructor);// 输出 function Object(){}  
    //这里为什么会输出function Object(){}
    //还记得之前说过constructor属性始终指向创建这个对象的构造函数吗?

    Person.prototype={
        sayName:function(){
            console.log(this.name);
        }
    }
    //这里实际上是对原型对象的重写:
    Person.prototype=new Object(){
        sayName:function(){
            console.log(this.name);
        }
    }
    //看到了吧。现在Person.prototype.constructor属性实际上是指向Object的。

    //那么我如何能将constructor属性再次指向Person呢?
    Person.prototype.constructor=Person;

接下来解释为什么,看下面的例子。

    function Person(name){
        this.name = name;
    } 
    var personOne=new Person("xl"); 
    Person.prototype = {
        sayName: function(){
            console.log(this.name);
        }
    };
    var personTwo = new Person('XL');
    console.log(personOne.constructor == Person); //输出true
    console.log(personTwo.constructor == Person); //输出false   
    //大家可能会对这个地方产生疑惑?为何会第二个会输出false,personTwo不也是由Person创建的吗?这个地方应该要输出true啊?
    //这里就涉及到了js里面的原型继承
    //这个地方是因为person实例继承了Person.prototype原型对象的所有的方法和属性,包括constructor属性。当Person.prototype的constructor发生变化的时候,相应的person实例上的constructor属性也会发生变化。所以第二个会输出false;
    //当然第一个是输出true,因为改变构造函数的prototype属性是在personOne被创建出来之后。

proto和prototype属性

    function Person(name){
        this.name=name;
    }
    Person.prototype.sayName=function(){
        console.log(this.name);
    }
    var person=new Person("xl");
    person.sayName(); //输出 "xl"

    //constructor : Person
    //instance : person

首先给构造函数的原型对象Person.prototype赋给sayName方法,由构造函数Person创建的实例person会继承原型对象上的sayName方法。

为什么会继承原型对象的方法?

因为ECMAscript的发明者为了简化这门语言,同时又保持继承性,采用了链式继承的方法。 由constructor创建的每个instance都有个__proto__属性,它指向constructor.prototype。那么constrcutor.prototype上定义的属性和方法都会被instance所继承。

    function Person(name){
        this.name=name;
    }
    Person.prototype.sayName=function(){
        console.log(this.name);
    }

    var personOne=new Person("a");
    var personTwo=new Person("b");

    personOne.sayName(); // 输出  "a"
    personTwo.sayName(); //输出 "b"

    console.log(personOne.__proto__==Person.prototype); // true
    console.log(personTwo.__proto__==Person.prototype); // true

    console.log(personOne.constructor==Person); //true
    console.log(personTwo.constructor==Person); //true
    console.log(Person.prototype.constructor==Person); //true

    console.log(Person.constructor); //function Function(){}
    console.log(Person.__proto__.__proto__);
点赞
收藏
评论区
推荐文章
刚刚好 刚刚好
4个月前
css问题
1、在IOS中图片不显示(给图片加了圆角或者img没有父级)<div<imgsrc""/</divdiv{width:20px;height:20px;borderradius:20px;overflow:h
晴空闲云 晴空闲云
4个月前
css中box-sizing解放盒子实际宽高计算
我们知道传统的盒子模型,如果增加内边距padding和边框border,那么会撑大整个盒子,造成盒子的宽度不好计算,在实务中特别不方便。boxsizing可以设置盒模型的方式,可以很好的设置固定宽高的盒模型。盒子宽高计算假如我们设置如下盒子:宽度和高度均为200px,那么这会这个盒子实际的宽高就都是200px。但是当我们设置这个盒子的边框和内间距的时候,那
艾木酱 艾木酱
3个月前
快速入门|使用MemFire Cloud构建React Native应用程序
MemFireCloud是一款提供云数据库,用户可以创建云数据库,并对数据库进行管理,还可以对数据库进行备份操作。它还提供后端即服务,用户可以在1分钟内新建一个应用,使用自动生成的API和SDK,访问云数据库、对象存储、用户认证与授权等功能,可专
Stella981 Stella981
1年前
JavaScript学习总结(十七)——Javascript原型链的原理
一、JavaScript原型链ECMAScript中描述了原型链的概念,并将原型链作为实现继承的主要方法。其基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法。在JavaScript中,用__proto__属性来表示一个对象的原型链。当查找一个对象的属性时,JavaScript会向上遍历原型
Stella981 Stella981
1年前
JavaScript 学习笔记八 继承与引用
functionlogs(obj){document.write(obj"<br/");}//打印log日志//继承//继承可以通过原型链来实现//解释器会在对象中查找该属性,如果//没有找到,则在其内部对象prototype对象上搜索,由于prototype对象与对象本身的结/
Stella981 Stella981
1年前
JavaScript Prototype
定义和用法prototype属性使您有能力向对象添加属性和方法。实例在本例中,将展示如何使用prototype属性来向对象添加属性:<scripttype"text/javascript"functionemployee(name,job,born){this.n
Wesley13 Wesley13
1年前
JS函数高级
原型与原型链所有函数都有一个特别的属性:prototype:显式原型属性所有实例对象都有一个特别的属性:__proto__:隐式原型属性显式原型与隐式原型的关系函数的prototype:定义函数时被自动赋值,值默认为{},即用为原型对象
Wesley13 Wesley13
1年前
JS原型、原型链深入理解
原型是JavaScript中一个比较难理解的概念,原型相关的属性也比较多,对象有”prototype”属性,函数对象有”prototype”属性,原型对象有”constructor”属性。原型是JavaScript中一个比较难理解的概念,原型相关的属性也比较多,对象有”prototype”属性,函数对象有”prototype”属性,原型对
Stella981 Stella981
1年前
Javascript 构造函数和类
1.构造函数构造函数的名称一般都是首字母大写挂载在this上面的属性为实例属性,实例属性再每个实例间都是独立的原型链属性通过prototype添加,他是所有实例共享的类方法/静态属性只能由构造函数本身访问当实例属性和原型链上的属性重名时,优先访问实例属性,没有实例属性再访问原型属性大多数浏览器的ES5实现之中,每一个对象都有\_\_pr
helloworld_28799839 helloworld_28799839
4个月前
常用知识整理
Javascript判断对象是否为空jsObject.keys(myObject).length0经常使用的三元运算我们经常遇到处理表格列状态字段如status的时候可以用到vue