JavaScript中的prototype和__proto__

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/weixin_38214171/article/details/83184612

这几天js的学习,不得不说,js真的很诡异,实在太灵活,对于我这个小白来说,只能从基础的模仿开始学习了。js来回都脱离不了“键值对”,其中灵活多变的使用,把我搞得是晕头转向。

JavaScript中的prototype和__proto__:

首先,先看一段简单的js代码:

function Fun() {
    this.num = 10;
};
var fun = new Fun;
var func = new Fun;
console.log("Fun:", Fun);
console.log("fun:", fun);
console.log("func:", func);

我定义了一个Fun(),(js中,一个function,有三个身份:函数,类,对象)。我把Fun()当做一个类,定义了fun和func对象。来看看执行结果吧:

 以上Fun显示有prototype成员,而fun和func对象没有prototype成员。所以,得出结论:只有类(函数)才有prototype成员,这个成员被称为“原型对象”,它指向一个空间,成为“原型空间”。

以上结果还显示出:fun和func有num成员,但Fun没有。这一点和var fun = new Fun和var fun = new Fun的执行过程有关,过程如下:

1、申请一个对象实例空间。

2、将空间首地址赋值给对象fun和func。

3、执行Fun的构造方法,这个构造方法,就是函数本身。

4、这个构造方法在执行的时候,是有前缀的(有对象调用此构造方法),这个对象,就是fun和func。

所以,函数Fun中的this就是fun或func,所以,fun和func显示有num成员。


console.log("Fun.prototype:", Fun.prototype);

 

 以上代码和结果显示,类的原型本身也是对象(Object),那么,既然是对象,就可以增加成员。


Fun.prototype.mem = "这是Fun.prototype的一个成员";
console.log("Fun.prototype:", Fun.prototype);
console.log("fun.prototype:", fun.prototype);

 

 以上代码和结果显示:给Fun.prototype增加一个成员mem。Fun.prototype显示有mem成员,而fun.prototype显示的是undefined。所以,这个说明对象不存在prototype成员,这是检验对象是否是函数的一种判断方法。(Fun是函数,类,对象;fun和func是对象)。


console.log("fun.member:", fun.member);
console.log("func.member:", func.member);
console.log("fun.__proto__", fun.__proto__);
console.log("func.__proto__:", func.__proto__);

 

 

 以上代码和结果显示:我们没有给fun和func增加过member成员,所以显示undefined很正常,可以理解。但是,也没有增加过__proto__成员,却显示了出来,而细细比对上面两个执行结果一下,发现:__proto__成员显示的结果和类Fun的prototype成员显示的结果一模一样!!!所以,得出结论:对象存在__proto__这个隐藏成员,这个隐藏成员指向prototype所指向的原型空间。


func.__proto__.member = 100;
console.log("Fun.member:", Fun.member);
console.log("Fun.prototype.member", Fun.prototype.member);

 

 给对象func的__proto__成员成员增加一个成员member,即__proto__指向的prototype原型空间也自然有了member成员。但是,发现:通过类(函数)不能直接访问原型对象的member成员,只能通过prototype访问其原型对象的member成员。


 js中对左值和右值的不同处理过程:

左值:

1、左值被看成空间,严格地说,左值也被看成“键”;
2、对于形如“xxx.成员”的左值,首先在xxx的键值对中查找,若存在,则,用=右侧的表达式的值覆盖其值;
3、若不存在,则,增加一个成员,再完成赋值。

 如:func.__proto__.member = 100;在func.__proto__的键值对中查找,没有找到member成员,则增加了一个func.__proto__成员,并赋值为100。

右值:
    1、右值被看成空间,严格地说,右值也被看成“键”;
    2、对于形如“xxx.成员”的右值,首先在xxx的键值对中查找,若存在,则,取出其值,并结束查找;
        若不存在,则,会自动沿着__proto__所指向的原型空间进行查找;
    3、prototype本身也是对象,也应该存在__proto__隐含成员;
    4、第2步的查找,会沿着这个隐含原型链,查找所有“祖先”原型空间中的“右值”;
    5、当遍历了所有原型空间,依然找不到这个“键”(右值),则,其值为undefined。

func.member = 12;
var a = fun.member;
var b = func.member;
console.log("fun.__proto__:", fun.__proto__);
console.log("a:",a);
console.log("b:",b);

 

 例如以上代码和结果:在fun的键值对中查找,不存在member成员,则沿着__proto__所指向的原型空间进行查找,结果显示,

 __proto__所指向的原型空间prototype也没有member,一直沿着这个隐含原型链,遍历了所有原型空间,都没有找到member,所以,a的值为undefined。而对于b,在func的键值对中查找,找到了member成员,则直接取出其值12并赋值。


console.log("Object.__proto__:", Object.__proto__);

 

 

 Object的__proto__成员的显示结果和Function的prototype成员显示一模一样,说明Object的__proto__成员指向Function的原型空间。


console.log("Function.__proto__:", Function.__proto__);
console.log("Function.prototype:", Function.prototype);

 

 Function的__proto__成员指向Function的原型空间。


console.log("Object.prototype.__proto__:", Object.prototype.__proto__);

 

 Object的原型空间prototype的__proto__成员指向null。


console.log("Function.prototype:", Function.prototype);
console.log("Object.prototype:", Object.prototype);

 

 

根据以上结果,发现Function的原型空间prototype的__proto__成员指向Object的原型空间,显示结果相同。

总结:

1、在类的构造方法中,用this定义的成员,在该类的生成对象中都可以使用,所以可以等效为java中的public成员(因为在对象的定义阶段,是对象执行了类的构造方法,所以这个this是该对象,自然而然,对象就拥有了构造方法中用this定义的成员)。

2、在类.prototype中定义的成员,可以等效为java中的public static成员。即该类的所有对象共享同一个副本(因为对象的__proto__成员指向类的prototype原型空间)。

3、对原型成员的标准访问方法是:类.prototype.成员。

4、针对上面一系列的分析和验证。对于以下图,自己的一些理解。

1): 只有类(函数)才有prototype成员,prototype原型空间里有这个类(函数)的构造方法constructor,该类(函数)的构造方法就是其本身,所以,里面又存在prototype成员······

2):每个对象都有__proto__隐藏成员,指向类(函数)的prototype原型空间。

3):prototype成员本身也是对象,所以,也有__proto__隐藏成员,指向其基类的原型空间。

4):Object的__proto__成员指向Function的原型空间,Function的__proto__成员指向Function的原型空间;Object的原型空间prototype的__proto__成员指向null,Function的原型空间prototype的__proto__成员指向Object的原型空间。

5):类空间的__proto__成员都指向Function的原型空间,原型空间prototype的__proto__成员指向其基类。

猜你喜欢

转载自blog.csdn.net/weixin_38214171/article/details/83184612
今日推荐