博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
constructor, prototype, __proto__ 详解
阅读量:6247 次
发布时间:2019-06-22

本文共 4520 字,大约阅读时间需要 15 分钟。

本文为了解决以下问题:

  • __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属性,而这个prototypeconstructor属性会指向这个函数。

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    //prototype : Person.prototype

首先给构造函数的原型对象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__); // Object{}

图片描述

参考文章:

转载地址:http://axlia.baihongyu.com/

你可能感兴趣的文章
zoj 1010 Area 判断线段是否相交(把线段扩充一倍后 好处理) + 多边形求面积...
查看>>
sublime text ctrl+b
查看>>
时间复杂度几个概念
查看>>
poj 1273 Drainage Ditches(最大流入门)
查看>>
for语句
查看>>
网页总结
查看>>
我用过的那些电脑 -- 致逝去的美好时光
查看>>
SQLiteOpenHelper学习
查看>>
Tomcat路径下目录的介绍
查看>>
TopCoder SRM 628 DIV 2
查看>>
实验吧_简单的sql注入_1、2、3
查看>>
BZOJ3779重组病毒LCT
查看>>
T-SQL (一)
查看>>
词法分析
查看>>
安装laravel框架
查看>>
Linux 目录结构
查看>>
第二次实验
查看>>
R中,求五数,最小值、下四分位数、中位数、上四分位数、最大值
查看>>
【python-Day3】
查看>>
接上一篇——上海有哪些值得加入的互联网公司
查看>>