none
关于javascript的prototype的一点小东西,各位帮忙改改错误 RRS feed

  • 常规讨论

  • 不是专业从业者,但是最近要上javascript的课程,感觉里面的prototype有点迷惑,就抱着谷歌浏览器尝试了几个小时(实在没动力去看javascript引擎源代码),写了一个小教程,准备上课用的,也不知道对不对,这儿人气旺,大家帮忙看看对不对,给改改,给人讲错了实在不好意思,我的邮箱sdeven95@live.cn。

    一、Javascript的对象层次
    Javascript没有类的概念,只有函数和对象。
    其实Javascript的顶层对象是Function,它是一切之源,类似
         function myfunc(message) { console.log(message);}
    之类的,可以转化为
        myfunc = new Function("message", "console.log(message);"}
    实际上,Object也是用Function来定义的,类似
       Object = new Function(){...};
    所以,实际上Object也是一个函数。

    Javascript世界的一切都源于Function和Object两个函数。
    你能否理解下面这些描述:
       (1)使用new Function(),如
    myFunc = new Function("message","console.log(message)");
    建立的thing(东西)是函数,而其他情况,如
    pureObj = new Object(); myObj = new myFunc();
    建立的thing都是对象。
      (2)函数可以建立对象,如
    new Function(); new Object(); new myFunc();
    都是对的,但是对象不能再用于建立对象,如
    new pureObj(); new myObj();
    都是不允许的
    (3)函数间可以使用原型技术(prototype)按层次串联起来

    继续往下看,看你能不能找到答案

    二、函数和对象,到底什么区别?
    一个是
         myFunc = new Function("message","console.log(message)");
    另一个是
        pureObj = new Object(); 
    到底什么区别?
    我们先看第二个,简单一些。
    new Object()的主要任务可能是:
    (1)在内存建立一个数组;
    (2)为数组增加一个constructor元素,并设置为Object的引用
    (3)为数组增加一个__proto__元素,设置为Object.prototype的引用
    (4)返回数组的引用,并将其设置为this指针引用
    第一个任务要更多一些:
    (1)在内存建立一个数组
    (2)为数组增加一个constructor元素,并设置为Function的引用
    (3)为数组增加一个__proto__元素,设置为Function.prototype的引用
    (4)为数组增加一个prototype元素,并使用new Object()初始化(建立存储数组,增加constructor和__proc__元素等,见上)
    (5)为函数参数和代码分配存储空间并编译

    猜一猜,下面语句执行哪些任务?
    myobj = new myFunc();
    (1)在内存建立一个数组
    (2)为数组增加一个constructor元素,并设置为myFunc的引用
    (3)为数组增加一个__proto__元素,设置为myFunc.prototype的引用
    (4)为数组增加一个prototype元素,并使用new Object()初始化(建立存储数组,增加constructor和__proc__元素等,见上)
    (5)返回数组引用,将其设置为this指针,将this指针传递给myFunc,执行myFunc的内部代码

    从上面的讨论可以看出,Object实际上就是一个数组,而Function是
    “Object(或Array)+一段执行代码+数组中建立一个prototype元素(或域)”,
    用Object生成的数组不定义prototype元素(但是Object自身包含prototype属性,因为它是使用Function定义的,是一个函数)。

    下面看一看实际执行的情况:
    1 new Function();
       var myFunc= new Function("message","console.log(message);");
    相应的:
       myFunc.constructor  //返回 function Function() { [native code] }
       myFunc instanceof Function //返回true
       Function.prototype.isPrototypeOf(myFunc) //返回true
       myFunc.__proto__ //返回function Empty() {}(就是Function.prototype, 默认设置为一个空函数)
    注意:
      它包含代码,可以执行:myFunc("ok"); //返回ok
      它包含原型域:myFunc.prototype; //返回Object {}(默认设置为一个空对象)
      原型域的域指针:myFunc.prototype.__proto__; //返回Object {}(默认为一个空对象)
    2 new Object();
       pureObj = new Object();
    相应的:
       pureObj.constructor //返回function Object() { [native code] }
       pureObj instanceof Object; //返回true
       Object.prototype.isPrototypeOf(pureObj); //返回true
       原型域指针:pureObj.__proto__ //返回Object {}(就是Object.prototype,默认设置为一个空对象)

    但是(相对Function):
       它没有执行代码:pureObj(); //返回TypeError: object is not a function
       它没有定义原型域:pureObj.prototype //返回undefined
    3 new myFunc();
       myObj = new myFunc();
    相应的:
       myFunc.constructor //返回function Function() { [native code] }
       myObj instanceof myFunc; //返回true
       myFunc.prototype.isPrototypeOf(myObj);//返回true
       myObj.__proto__ //返回Object {}(因为myFunc.prototype没有加内容,实际上就是对myFunc.prototype的引用)

    同样(相对Function):
       它没有执行代码:myObj(); //返回TypeError: object is not a function
       它没有定义原型域:myObj.prototype //返回undefined

    问题: pureObj = new Object()不会出错,但是myObj = new pureObj()会出错,现在明白为什么了么?
    答案:Object是个函数,它是用 new Function()定义的,引擎内的代码应该类似:
    Object = new Function(){...};
    所以new能完成四个任务,正常执行,
    而pureObj是个对象,它没有代码可执行,也没prototype域,新生对象的__proto__指针也不知道该怎么办。

    三、函数串联
    看下面的例子:
    s1 = function(firstName){
       if(arguments.length>=1) {this.firstName=firstName;}
    }

    s1.prototype.showFirstName=function(){
       if(this.firstName!=undefined) { console.log(this.firstName);}
    }

    s1.prototype.sex="male";

    s2 = function(lastName, firstName){
       if(arguments.length>=1) { 
           this.lastName=lastName; 
           if(arguments.length>=2) 
             { s1.call(this, firstName); }
       }
    }
    s2.prototype = new s1();

    s2.prototype.showLastName=function() {
       if(this.lastName!=undefined){ console.log(this.lastName);}
    }
    s2.prototype.age=18;

    s = new s2("Harry", "Smith");
    t = new s2("Washton");

    通过__proto__指针,我们把函数s1,函数s2和对象s(或t)串联起来了,从s观察,层次关系为:
    s2 {lastName: "Harry", firstName: "Smith", showLastName: function, age: 18, showFirstName: function…}
       firstName: "Smith"
       lastName: "Harry"
       __proto__: s1
          age: 18
          showLastName: function () {
       __proto__: Object
          constructor: function (firstName){
          sex: "male"
          showFirstName: function (){
          __proto__: Object
    也就是说,s的__proto__指向了s2.prototype,而s2.prototype.__proto__指向了s1.prototype,但使用属性或者方法时候,比如s.sex,会遵循这样一个过程:
    (1)s.sex != undefined,是停止,否则继续;
    (2)s._proto_.sex(也就是s2.prototype) != undefined,是停止,否则继续
    (3)s._proto_._proto__.sex(也就是s1.prototype) != undefined, 是停止,否则继续
    ...........
    该过程一直继续,直到碰到一个空对象(hasOwnProperty()返回false),如果找到则返回sex属性的值,否则返回undefined。

    函数串联经常用来实现类似面向对象编程里面的层次继承关系,上面的例子自我感觉是比较规范的写法,注意函数内代码的写法。


    • 已编辑 sdeven95 2013年3月19日 8:19
    2013年3月19日 8:19