现在的位置: 首页 > 综合 > 正文

JavaScript原型机制详解

2018年02月19日 ⁄ 综合 ⁄ 共 4024字 ⁄ 字号 评论关闭

C/C++模拟实现JavaScript原型机制

    为了更加深入的理解JavaScript原型机制,我们现在用伪代码来实现或者说模拟该机制,也许我的理解有所谬误,如果果真如此,还希望不吝赐教。

一、原型机制设计

        在JavaScript中,有两个祖先一样的对象:Function.prototype和 Object.prototype

         (1)
Object.prototype
:这个对象是所有对象的根,它自己没有爹妈,是女娲造出来的。

         (2) Function.prototype:这个对象是所有构造器的根,它事实上也没爹妈,也是女娲造出来的。只不过其内部维护者Object.prototype的引用。

        事实上所有对象都维护者一个{prototype}属性,这是一个内部的私有属性,无法通过对象来访问。不过在firefox等浏览器中提供了一个共有属性__proto__来访问这个私有属性。在Js中公有属性名和私有属性名可以相同。但是C/C++中不可以,我们需要做些许改变。而这个女娲分别派出了两位大使MetaObject
MetaConstructor,这是C/C++中的类。他们分别负责产生Object.prototypeFunction.prototype,(采用单体模式)

1、Object.prototype

         (1)通用属性

                  
1.Constructor
对创建对象的函数(构造器)的引用(指针),这里为Object,主要是为了Object.prototype也属于Object类型;设计的需要,实际上不是Object构造的。

               2.Prototype:私有的prototype属性,也就是__proto__的值,这里为null。

         (2)通用方法

                  1. hasOwnProperty(property):判断对象是否有某个特定的属性。必须用字符串指定该属性 (例如,

o.hasOwnProperty(”name”))。

                2. isPrototypeOf(object):判断该对象是否为另一个对象的原型。

                3. propertyIsEnumerable(property):判断给定的属性是否可以用for…in语句进行枚举。

                4. toString():返回对象的原始字符串表示。对于Object类,ECMA-262没有定义这个值,所以不同的ECMAScriipt实现具有不同的值。

                5. valueOf():返回最适合该对象的原值。对于许多类,该方法返回的值都与toString()的返回值相同。

              毕竟Js是动态语言,而C/C++是静态语言,我们实现的只是框架而不涉及到具体细节。

2、Function.prototype

           (1)通用属性

                 1.  0...n属性:这是arguments取参数时的索引,0——n

                 2. arguments属性:存储存进来所有参数,相当于可变参数参数列表。

                 3. callee属性:引用当前函数对象,用于函数递归,特别是在匿名函数中特别有用。

                 4. caller属性:返回调用某个函数的函数对象。

                 5.constructor属性:Function.prototype的构造器是Function.

                 6.length属性:当创建一个函数的实例时,函数的 length 属性由脚本引擎初始化为该函数定义中的参数数目。

                 7.prototype属性:内部{Prototype}——也即__proto__,为Object.prototype。

           (2)通用方法

                     1.apply方法:这个方法允许你使用一个函数,就好像该函数是其他某个对象的函数方法一样。

                2.call方法:同apply,只不过参数的传递形式不同。

                3.toString方法:将对象转换成字符串。

                4.valueOf方法:自己查吧。

                  我们在此只提供接口并不实现。

二、数据结构

1.MetaObject——单体模式生成Object.prototype

MetaObject
{
public:
   static constructor = Object; //事实上并非Object所构造,只不过是为了使Object.prototype属于Object类
   static __proto__ = {Prototype};
private:
   static {Prototype} = null; //假设私有共有变量不冲突public: //一堆接口
}

2. MetaConstructor——单体模式生成Function.prototype

MetaConstructor
{
public:
   static constructor = Function; //实际并非Function所构造,只是为了Function.prototype类型为Function
   static  prototype = undefinded;    //之所以未定义是因为它不会当成构造器来使用
   static __proto__ = {Prototype};
private:
   static {Prototype} = Object.prototype;
public: 
//一堆接口
}

3.Function——用户可使用的函数构造器的基类

Function
{
public:
    static  constructor = Function;
    static  prototype  = Function.prototype;
    static  __proto__ = {Prototype};
private:
    static  {Prototype}  = Function.prototype;
}

4.Object——对象基类构造器

Object
{
public:
       static  constructor = Function;
       static  prototype = Object.prototype;
       static  __proto__ = {Prototype};
private:
       static  {Prototype}  = Function.prototype;
}

有个统一的公式:若有个对象obj,构造它的的构造器为Constructor,那么:obj.__proto__ = Constructor.prototype;

三、原型链

如有三个类,也即A,B,C(其实就是构造器——函数对象)如B继承A,C继承B,那么就等价于

function A(){};   //A.prototype = Object.prototype,  A.__proto__ = Function.prototype
function B(){};   //类推
function C(){};   //类推
B.protype = new A();
C.prototype = new B();
var c = new C();

c中维护者一个B的实例,而这个B的实例中又维护者一个A的实例的引用。等价于:

function A(){};
function B(){};
function C(){};
var a = new A();
B.prototype = a;
var b = new B();
C.prototype = b;
c = new C();

也就是c中维护者一个B的实例b的引用,而b中维护者一个A的实例a的引用。说白了这里的继承其实也就是共享对象,而且可以形成共享链。画成图如下:
(a)没有继承之前:

function A(){};
function B(){};
function C(){};
var a = new A();
var b = new B();
var c = new C();

结构如图:

(b)继承之后:

function A(){};
function B(){};
function C(){};
var a = new A();
B.prototype = a;
var b = new B();
C.prototype = b;
c = new C();

        由此更加能够表示,其实所谓的继承就是对象共享,是一种链式的间接访问,比如B知道a的地址,那么B的所有子孙也就知道a的地址,自然也就能访问。但是每个B的子孙知道的是同一个a,而不是a的副本。同理C知道b(B的一个实例)的地址,那么C的所有实例也知道b的地址,而b又知道a的地址。所以c(C的一个实例)能够访问b,通过b又能访问a。如果我们把对象看成一个集合的话,那么b={....,&a},c={...,b={...,a}}; 也就是a的引用&a属于b,且包含于b;b的引用&b属于c,也包含于c。原型链的表示为:
                               b.__proto__ = a;c.__proto__ = b;c.__proto__.__proto__ = a;
       按C/C++的角度来讲,其实所谓的对象共享就是拥有某一个对象的指针。如B继承自对象a,那么相当于B中有一个指针Pointer,那就是B.Pointer = &a;这样B就共享了a了,也就是所谓的继承,在我看来这顶多算伪继承。

         本文本来想通过C/C++模拟实现该机制,结果发现并非一件易事,那么就留待以后来实现吧。

参考文献:http://www.blogjava.net/heavensay/archive/2013/10/20/405440.html(强烈推荐)

           

抱歉!评论已关闭.