zoukankan      html  css  js  c++  java
  • Javascript中Function,Object,Prototypes,__proto__等概念详解

    http://anykoro.sinaapp.com/2012/01/31/javascript%E4%B8%ADfunctionobjectprototypes__proto__%E7%AD%89%E6%A6%82%E5%BF%B5%E8%AF%A6%E8%A7%A3/

    http://www.cnblogs.com/youxin/p/3219175.html

    Javascript中Function,Object,Prototypes,__proto__等概念是在JavaScript中很常用,但又总是不清不楚的概念。今天主要是解释他们之间的概念和关系,帮助我们更好的理解Javascript。
    我们本次的解释,主要通过下图

    Javascript的Prototype,Function,Object,__proto__关系示意图

    粗看该图,估计你不一定能看明白。不过接下来让我逐行向你解释。
    【第一行】

    • 最左侧:意思是,有两个对象f1和f2,他们是通过new Foo()出来的。
    • 中间:Foo()就是最左侧用到的Foo()
    • 最右侧:表示,函数的prototype属性,对是函数的,不是对象的,站点要注意!

    现在知道了各个区块的意思,接下来解释各条线是什么意思。
    1、__proto__的虚线:该条线表示通过f1.__proto__可以访问到Foo.prototype,其实两者是等价的,我们可以通过以下代码验证。

    1
    2
    3
    4
    5
    6
    7
    function Foo(){
     
    }
     
    var f1=new Foo();
     
    alert(f1.__proto__==Foo.prototype);//true

    2、prototype实线:表示通过Foo.prototype可以找到Foo.prototype。这里没有写错,这么写虽然看似有些废话,但是是要体现出流向的。
    3、constructor实现:表示通过Foo.prototype.constructor可以找到Foo。验证代码如下:

    1
    2
    3
    4
    5
    function Foo(){
     
    }
     
    alert(Foo==Foo.prototype.constructor);//true

    其中的意义在于f1.__proto__.constructor等于Foo
    至此第一行结束了。

    【插播】
    在讲解下面第二行和第三行前,有两个很重要的概念需要深刻理解。否则理解下面的内容是举步维艰的。
    Function和Object

    function Object(){[native code]}//Javascript自带,不是自定义的,可以近似认为是基类

    function Function(){[native code]}//Javascript自带,不是自定义的,可以近似认为是基类

    这里的这两个function,分别走两个方向,
    Object作为了众多object(实例,new出来的)的基类型
    Function作为众多function(主要是那些function出来的,就是定义出来的函数)的基类型

    在开始下面更细致的解释先,我们约定一些内容,Object代表这里所说的Object,object代表实例对象
    ,Function代表这里说的Function,function是关键字。对于Object与object的区别很好理解,一个是function,一个是new出来。

    现在让我们思考两个问题:
    第一个,当我们扩展Object原型时,new出来的Function,是否会被扩展?
    第二个,当我们扩展Function原型时,由于Object也是个Function,那么其实例object是否会被扩展?

    先看第一个问题,上代码:

    扩展Object原型
    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12
    13
    14
    15
    16
    17
    18
    Object.prototype.test4extend="123";//扩展Object的原型
     
    alert("Function:"+Function.test4extend);//在Function中出现了test4extend属性
     
    alert("Object:"+Object.test4extend);//在Object中出现了test4extend属性,此时Object还是个Function
     
    var obj=new Object;
    alert("Object instance:"+obj.test4extend);//在obj中扩展了test4extend,此时的obj是object
     
    function Foo()
    {
     
    }
     
    var foo = new Foo;
    alert("foo object:"+foo.test4extend);//foo对象上扩展上了test4extend属性
     
    alert("Foo Function:"+Foo.test4extend);//函数上也扩展上了test4extend属性

    注释已经写得很清晰了,通过以上几点我们很容易发现以下几点:
    1、Object扩展了所有的object(obj,foo)。
    与object扩展自Object是相符的。在这里更加验证了。
    2、Object扩展了Function
    这点说明Function扩展自Object,说明Object比Function更底层些。
    3、Object扩展了自身的属性,即Object.test4extend也是可以的。
    这点说明,Object扩展了Function,又因为Object本身又是通过function定义出来的,所以会受到Function影响,所以,反过来Function又扩展了Object。

    接下来看看第二个问题:

    扩展Function原型
    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12
    13
    14
    15
    16
    17
    18
    Function.prototype.test4extend="123";//扩展Function的原型
     
    alert("Function:"+Function.test4extend);//在Function中出现了test4extend属性
     
    alert("Object:"+Object.test4extend);//在Object中出现了test4extend属性,注意此时Object是个Function
     
    var obj=new Object;
    alert("Object instance:"+obj.test4extend);//在obj中没有扩展上test4extend,此时的obj是object
     
    function Foo()
    {
     
    }
     
    var foo = new Foo;
    alert("foo object:"+foo.test4extend);//foo对象上没有扩展上test4extend
     
    alert("Foo Function:"+Foo.test4extend);//Function扩展上了test4extend属性

    这说明Function只管没有被实例化得,被实例化的,他是没有办法管的。与Object不同,Object是无论是否实例化都管的。

    有了上面的基础,我们来看看第二行和第三行

    【第二行】

    这里的Object就是我们前面插播的Object。

    对于prototype实线和constructor实线和第一行的情况是一样的。这里主要要讲解虚线。

    对于中间栏上部的__proto__(即function Object()上面的__proto__):此代表o1.__proto__可以找到Object.prototype,两者等价。我们前面说了这里的Object是泛指的,对应的关系式范式的,所以可以认为第一行中的__proto__是这个关系的实例。

    对于右侧上面的__proto__虚线代表,Foo.prototype.__proto相当于Object.prototype(这里只是属性等相同,但并不是Object)

    对于最右边侧面的__proto__虚线代表:f1.__proto__.__proto__.__proto__和Object.prototype.__proto__都是null的。如果直接是由Object,new出来的话,就会少一个__proto__为o1.__proto__.__proto__为null

    第二行结束

    【第三行】

    同样实线就不说了,主要说虚线。

    先看最左侧的__proto__虚线,表示Foo.__proto__相当于Function.prototype,这里和Object情况差不多,只是属性一致而已,并不是指真正的那个Function。

    中间的下部的__proto__虚线,代表Function.__proto__等于Function.prototype,这里可是真的就是,和前面的相当于不同。
    验证代码:

    1
    alert(Function.__proto__===Function.prototype);//true

    右侧左上的__proto__虚线,代表Object.__proto__等于Function.prototype,这里可是真的就是,和前面的相当于不同。
    验证代码:

    1
    alert(Object.__proto__===Function.prototype);//true

    右侧右上的__proto__虚线,代表Function.prototype.__proto__相当于Object.prototype,只是属性一致而已,并不是真的。

    上面的两行红字,也体现了,我们在插播中说的,Object和Function之间,你中有我,我中有你的关系的形成原因。

    第三行结束。

    看完上面的图,估计你差不多理清了。现在我们准备来做最后的总结。
    只是这里又要插播一些了,先让我们总结下__proto__和prototype的区别和关系。
    对于区别:
    从实际效果上来说,可以认为__proto__是用来扩展Function的,扩展出来的函数,可以直接调用,不需要new出对象才能用,同时对象是不会扩展通过__proto__扩展的方法或属性的。

    扩展__proto__
    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12
    13
    14
    15
    16
    17
    18
    //Object.prototype.test="prototype test property found";
    //alert("Object:"+Object.test);
    //上面两句不能用,因为他们会影响Function,Function又会影响Object。前文已经说明
     
    function Foo()
    {
     
    }
     
    Foo.__proto__.test="__proto__ test property found";//通过__proto__扩展
    Foo.__proto__.addextend=function(){alert("Foo add extend by __proto__");}
     
    Foo.addextend();//可以执行
     
    var foo=new Foo;
    alert("Foo:"+Foo.test);//可以访问
    alert(foo.addextend);//未定义
    alert("Foo instance:"+foo.test);//未定义

    对于prototype来说,它是针对对象的,也就是Function是无法使用的,只有new出来的才能有效。

    扩展prototype
    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12
    13
    14
    15
    16
    17
    //Object.prototype.test="prototype test property found";
    //alert("Object:"+Object.test);
    //上面两句不能用,因为他们会影响Function,这样就会影响测试Function。前文已经说明
     
    function Foo()
    {
     
    }
    Foo.prototype.test="prototype test property found";
    Foo.prototype.addextend=function(){alert("Foo add extend by prototype");}
     
    alert(Foo.addextend());//未定义
     
    var foo=new Foo;
    alert("Foo:"+Foo.test);//无法访问
    foo.addextend();//可以执行
    alert("Foo instance:"+foo.test);//找到了

    简单来说就是__proto__扩展出来,只有函数可以直接访问,prototype扩展出来的,只有对象才能直接访问。

    对于关系:
    首先要明确
    在Object中__proto__是Function,prototype是Object。
    在Function中__proto__是Function,prototype也是Function。
    现在让我们再来结合第三行的图看一看。有如下关系。
    Function.__proto__就是(===)Function.prototype
    Object.__proto__就是(===)Function.prototype
    先看类型,等号两边都是一致的。
    所以,我们可以有如下结论:
    1、Function的__proto__和prototype就是一个,扩展任何一个都是相同的效果。
    2、Object的__proto__就是Function.prototype。当我们扩展Object.__proto__时,就相当于扩展了Function.prototype和__proto__,反之亦然。

    结合前面__proto__和prototype区别的分析,我们可以进一步的解释出,Object和Function之间关系的形成原因。
    当Function.prototype.test4extend="123";扩展Function的原型时,因为Function.prototype=Object.__proto__,又因为Function.prototype=Function.__proto__。所以Object.test4extend就存在了。

    而对于Object.prototype.test4extend="123"扩展Object的原型时Function.test4extend存在,则实实在在的说明了Function扩展自Object的。
    同时下面补一段代码,这段代码,体现了使用Object.__proto__扩展原型的情况:

    通过__proto__扩展Object
    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12
    13
    14
    15
    16
    17
    18
    Object.__proto__.test4extend="123";//扩展Object的原型
     
    alert("Function:"+Function.test4extend);//在Function中出现了test4extend属性
     
    alert("Object:"+Object.test4extend);//在Object中出现了test4extend属性,此时Object还是个Function
     
    var obj=new Object;
    alert("Object instance:"+obj.test4extend);//未定义
     
    function Foo()
    {
     
    }
     
    var foo = new Foo;
    alert("foo object:"+foo.test4extend);//未定义
     
    alert("Function:"+Foo.test4extend);//函数上也扩展上了test4extend属性

    Ok。。。总算可以进入最终总结了。问题比较复杂,说的比较多,写得真累啊。
    【总结】
    Function扩展自Object,但是Function对Object又有影响,这是通过Object.__proto__就是(===)Function.prototype建立的联系。记住这个联系后,我们还要记住__proto__和prototype的区别,前者扩展的只可以被Function直接调用,后者扩展的只可以通过其实例调用。另外,还要注意__proto__和prototype的链的概念,这是因为,他们可以互相关联,访问到Function或Ojbect的内容。

    收工!!好累

     
  • 相关阅读:
    [DB] 数据库的连接
    JS leetcode 翻转字符串里的单词 题解分析
    JS leetcode 拥有最多糖果的孩子 题解分析,六一快乐。
    JS leetcode 搜索插入位置 题解分析
    JS leetcode 杨辉三角Ⅱ 题解分析
    JS leetcode 寻找数组的中心索引 题解分析
    JS leetcode 移除元素 题解分析
    JS leetcode 最大连续1的个数 题解分析
    JS leetcode 两数之和 II
    JS leetcode 反转字符串 题解分析
  • 原文地址:https://www.cnblogs.com/daishuguang/p/3584545.html
Copyright © 2011-2022 走看看