zoukankan      html  css  js  c++  java
  • JavaScript中的prototype和__proto__细致解析

    最近在学js,体会了一点点它的灵活性。对于初学者的我,总是被它的灵活感到晕头转向,最近发现了一点东西想与大家分享。

    JavaScript中的prototype和_proto_:

    我们先了解一点js中的基础知识,首先我们先看一段js代码:

    1 var object = new Object;
    2 console.log("object:", object);
    3 object.member1 = "abcd";
    4 
    5 var obj = {};
    6 obj.member1 = 10;
    7 console.log("obj:", obj);
    8 console.log(window);

    输出结果:

    对于上面输出结果,我总结了几点:

    1.js的对象事实上是关联数组;
    2.js对象中的成员的增加,可以通过直接赋值即可。
    3.“值”是由键值对组成。

    我们再来看一段代码(真是不得不说代码是最值得信赖的。)

    1 var Klass = function() {}; 
    2 var Fun = new Function(); 
    3 Klass.mem = 10; 
    4 Fun.mem = true;
    5 
    6 var klass = new Klass;  //klass是Klass的一个对象。
    7 console.log(klass instanceof Klass);
    8 console.log(window);

    输出结果:

    首先,我们不得不承认,js中的一个function,拥有三个身份:对象、函数、类。

    上述代码(var klass = new Klass;)的执行过程是:

    1.申请一个Klass的对象klass实例空间;

    2.将空间首地址赋值给对象klass;

    3.执行Klass的构造方法;这个构造方法就是函数本身;

    4.这个构造方法在执行时,是有前缀的(有对象的),而这个对象就是Klass;那么,构造方法中的this就是klass。

    (第四点用Java语言讲是最合适不过了,Java中的类都有构造方法,构造方法中的this相当于new出来的对象实例,不管有多少个实例,他们都是this。)

    下面进行主题:
    继续看代码:
    function Fun() {
       this.num = 22;
    };
    var fun = new Fun;
    var func = new Fun;
    console.log(window);
    console.log("Fun:", Fun);
    console.log("fun:", fun);
    console.log("func:", func);
    var Klass = function() {}; // Klass是类
    var Fun = new Function(); //Fun是类
    console.log("Klass:", Klass);
    console.log("Fun:", Fun);

    结果:

    1.从结果可以看到:类Fun、 Klass、Fun显示有prototype成员,而对象klass和func没有prototype成员。

    所以只有类(函数)才有prototype成员,这个成员被称为“原型对象”,它指向一个空间,称为原型空间。
    2.还有结结果:fun和func有num成员,但是类没有。这就证实了我们刚刚的说法:
    (var fun = new Fun;var func = new Fun;的执行过程)再强调一遍:

    1.申请一个对象实例空间;

    2.将空间首地址赋值给对象fun和func;

    3.执行Klass的构造方法;这个构造方法就是函数本身;

    4、这个构造方法在执行时,是有前缀的(有对象的),而这个对象就是fun和func;那么,构造方法中的this就是fun和func
    (第四点用Java语言讲是最合适不过了,Java中的类都有构造方法,构造方法中的this相当于new出来的对象实例,不管有多少个实例,他们都是this。)
     
    console.log("Fun.prototype:", Fun.prototype);

    从以上代码和结果,我们可以看到:类的原型本身也是对象(object),那么,既然是对象,就可以增加成员:

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

    上上面的代码和结果,我们可以更加坚定的得出结论是:

    所以只有类(函数)才有prototype成员,对象不存在prototype成员。这也是检验对象是否是函数的一种判断方法。

    1 console.log("fun.member:", fun.member);
    2 console.log("func.member:", func.member);
    3 console.log("fun.__proto__:",fun.__proto__);
    4 console.log("func.__proto__:", func.__proto__);

    从上面的代码和结果我们可以看到:

    我们并没有给fun和func增加过__proto__成员,输出结果却有,而我们仔细一点打开Fun类的成员prototype,

    他们三个的输出结果居然一模一样,所以,我给出一个结论:对象__proto__这个隐藏的成员,这个隐藏成员指向prototype所指向的原型空间

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

    给对象func的__proto__成员增加一个成员member,即__proto__指向prototype原型空间,所以有了member成员。

    但是我们从结果可以看出:类不能直接访问原型对象的member成员,只能通过prototype访问其原型对象的member成员。

    我再总结一点关于js中的左值和右值的不同处理过程:

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

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

    1 console.log("Function:", Function);
    2 console.log("Object.__proto__:", Object.__proto__);
    3 console.log("Object.__proto__ === Function.prototype:", Object.__proto__ === Function.prototype);

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

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

    从上面的代码可以看出:

    Function的原型空间prototype的__proto__成员指向Object的原型空间,显示的是相同的结果。

    最后稍微的总结一下:

    1、只有类(函数)才有prototype成员,这个成员被称为“原型对象”,它指向一个空间,称为原型空间;
    2、类的原型本身也是对象,可以增加成员;
    3、对象不存在prototype成员,这是检验对象是否是函数的一种判断方法;
    4、对象存在__proto__这个隐藏的成员,这个成员指向prototype所指向的原型空间;
    5、通过类(函数)不能直接访问其原型的成员,必须通过prototype访问原型成员。

    画出手工图:

    补充一点:

    1、在类构造方法中,用this定义的成员,可以等效为Java的public成员;
    2、在类.prototype中定义的成员,可以等效为Java的public staitc成员,即,该类的所有对象共享同一副本;
    3、对原型成员的标准访问方法是:类.prototype.成员。

    4、以上若有错误请指正!

  • 相关阅读:
    是否是轮回(续)
    夜雨做成秋
    53分
    浮生六记 一成长星和月
    企业信息化常见缩略语汇总
    是否是轮回
    对信号集操作函数的使用方法和顺序
    fcntl.h
    关于linux信号量的基本使用
    linux 共享内存
  • 原文地址:https://www.cnblogs.com/youdiaodaxue16/p/9853134.html
Copyright © 2011-2022 走看看