关闭

Nashorn 引擎中对javascript Object的实现

148人阅读 评论(1) 收藏 举报

public abstract class ScriptObject{

              /** __proto__ special property name */
    public static final String PROTO_PROPERTY_NAME   = "__proto__";

   /** Map to property information and accessor functions. Ordered by insertion. */
    private PropertyMap map;

    /** objects proto. */
    private ScriptObject proto;


    /** objects proto. */
    private ScriptObject proto;


  /**
     * ECMA 8.12.2 [[GetProperty]] (P)
     *
     * @param key property key
     *
     * @return Returns the fully populated Property Descriptor of the named property
     * of this object, or undefined if absent.
     */
    public Object getPropertyDescriptor(final String key) {
        final Object res = getOwnPropertyDescriptor(key);


        if (res != UNDEFINED) {
            return res;
        } else if (getProto() != null) {
            return getProto().getOwnPropertyDescriptor(key);
        } else {
            return UNDEFINED;
        }
    }

}


public class NativeObject{

    /**
     * ECMA 15.2.3.5 Object.create ( O [, Properties] )
     *
     * @param self  self reference
     * @param proto prototype object
     * @param props properties to define
     * @return object created
     */
    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
    public static Object create(final Object self, final Object proto, final Object props) {
        if (proto != null) {
            Global.checkObject(proto);
        }


        // FIXME: should we create a proper object with correct number of
        // properties?
        final ScriptObject newObj = Global.newEmptyInstance();
        newObj.setProto((ScriptObject)proto);
        if (props != UNDEFINED) {
            NativeObject.defineProperties(self, newObj, props);
        }


        return newObj;
    }


 /**
     * ECMA 15.2.3.6 Object.defineProperty ( O, P, Attributes )
     *
     * @param self self reference
     * @param obj  object in which to define a property
     * @param prop property to define
     * @param attr attributes for property descriptor
     * @return object
     */
    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
    public static Object defineProperty(final Object self, final Object obj, final Object prop, final Object attr) {
        Global.checkObject(obj);
        ((ScriptObject)obj).defineOwnProperty(JSType.toString(prop), attr, true);
        return obj;
    }


    /**
     * ECMA 5.2.3.7 Object.defineProperties ( O, Properties )
     *
     * @param self  self reference
     * @param obj   object in which to define properties
     * @param props properties
     * @return object
     */
    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
    public static Object defineProperties(final Object self, final Object obj, final Object props) {
        Global.checkObject(obj);


        final ScriptObject sobj     = (ScriptObject)obj;
        final Object       propsObj = Global.toObject(props);


        if (propsObj instanceof ScriptObject) {
            final Object[] keys = ((ScriptObject)propsObj).getOwnKeys(false);
            for (final Object key : keys) {
                final String prop = JSType.toString(key);
                sobj.defineOwnProperty(prop, ((ScriptObject)propsObj).get(prop), true);
            }
        }
        return sobj;
    }


    /**
     * ECMA 15.2.3.8 Object.seal ( O )
     *
     * @param self self reference
     * @param obj  object to seal
     * @return sealed object
     */
    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
    public static Object seal(final Object self, final Object obj) {
        if (obj instanceof ScriptObject) {
            return ((ScriptObject)obj).seal();
        } else if (obj instanceof ScriptObjectMirror) {
            return ((ScriptObjectMirror)obj).seal();
        } else {
            throw notAnObject(obj);
        }
    }




    /**
     * ECMA 15.2.3.9 Object.freeze ( O )
     *
     * @param self self reference
     * @param obj object to freeze
     * @return frozen object
     */
    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
    public static Object freeze(final Object self, final Object obj) {
        if (obj instanceof ScriptObject) {
            return ((ScriptObject)obj).freeze();
        } else if (obj instanceof ScriptObjectMirror) {
            return ((ScriptObjectMirror)obj).freeze();
        } else {
            throw notAnObject(obj);
        }
    }


    /**
     * ECMA 15.2.3.10 Object.preventExtensions ( O )
     *
     * @param self self reference
     * @param obj  object, for which to set the internal extensible property to false
     * @return object
     */
    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
    public static Object preventExtensions(final Object self, final Object obj) {
        if (obj instanceof ScriptObject) {
            return ((ScriptObject)obj).preventExtensions();
        } else if (obj instanceof ScriptObjectMirror) {
            return ((ScriptObjectMirror)obj).preventExtensions();
        } else {
            throw notAnObject(obj);
        }
    }


    /**
     * ECMA 15.2.3.11 Object.isSealed ( O )
     *
     * @param self self reference
     * @param obj check whether an object is sealed
     * @return true if sealed, false otherwise
     */
    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
    public static Object isSealed(final Object self, final Object obj) {
        if (obj instanceof ScriptObject) {
            return ((ScriptObject)obj).isSealed();
        } else if (obj instanceof ScriptObjectMirror) {
            return ((ScriptObjectMirror)obj).isSealed();
        } else {
            throw notAnObject(obj);
        }
    }


    /**
     * ECMA 15.2.3.12 Object.isFrozen ( O )
     *
     * @param self self reference
     * @param obj check whether an object
     * @return true if object is frozen, false otherwise
     */
    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
    public static Object isFrozen(final Object self, final Object obj) {
        if (obj instanceof ScriptObject) {
            return ((ScriptObject)obj).isFrozen();
        } else if (obj instanceof ScriptObjectMirror) {
            return ((ScriptObjectMirror)obj).isFrozen();
        } else {
            throw notAnObject(obj);
        }
    }


    /**
     * ECMA 15.2.3.13 Object.isExtensible ( O )
     *
     * @param self self reference
     * @param obj check whether an object is extensible
     * @return true if object is extensible, false otherwise
     */
    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
    public static Object isExtensible(final Object self, final Object obj) {
        if (obj instanceof ScriptObject) {
            return ((ScriptObject)obj).isExtensible();
        } else if (obj instanceof ScriptObjectMirror) {
            return ((ScriptObjectMirror)obj).isExtensible();
        } else {
            throw notAnObject(obj);
        }
    }


    /**
     * ECMA 15.2.3.14 Object.keys ( O )
     *
     * @param self self reference
     * @param obj  object from which to extract keys
     * @return array of keys in object
     */
    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
    public static Object keys(final Object self, final Object obj) {
        if (obj instanceof ScriptObject) {
            final ScriptObject sobj = (ScriptObject)obj;
            return new NativeArray(sobj.getOwnKeys(false));
        } else if (obj instanceof ScriptObjectMirror) {
            final ScriptObjectMirror sobjMirror = (ScriptObjectMirror)obj;
            return new NativeArray(sobjMirror.getOwnKeys(false));
        } else {
            throw notAnObject(obj);
        }
    }

}



在JavaScript中最难以理解的就是Object对象,在Object中可以存储属性。

在Nashorn中ScriptObject 中有PropertyMap 来存储所有管理的属性。PropertyMap实质是PropertyHashMap.

public final class PropertyHashMap implements Map <String, Property> { }  

通过String 作为键,通过Property 作为值。

public abstract class Property {

         /** Property key. */
    private final String key;


    /** Property flags. */
    protected int flags;


    /** Property field number or spill slot. */
    private final int slot;


    /**
     * Constructor
     *
     * @param key   property key
     * @param flags property flags
     * @param slot  property field number or spill slot
     */
    Property(final String key, final int flags, final int slot) {
        assert key != null;
        this.key   = key;
        this.flags = flags;
        this.slot  = slot;
    }

}

同时Property 可以通过PropertyDescriptor 来描述。

public interface PropertyDescriptor {


    /** Type: generic property descriptor - TODO this should be an enum */
    public static final int GENERIC  = 0;


    /** Type: data property descriptor - TODO this should be an enum */
    public static final int DATA     = 1;


    /** Type: accessor property descriptor - TODO this should be an enum */
    public static final int ACCESSOR = 2;


    /** descriptor for configurable property */
    public static final String CONFIGURABLE = "configurable";


    /** descriptor for enumerable property */
    public static final String ENUMERABLE = "enumerable";


    /** descriptor for writable property */
    public static final String WRITABLE = "writable";


    /** descriptor for value */
    public static final String VALUE = "value";


    /** descriptor for getter */
    public static final String GET = "get";


    /** descriptor for setter */
    public static final String SET = "set";


    /**
     * Check if this {@code PropertyDescriptor} describes a configurable property
     * @return true if configurable
     */
    public boolean isConfigurable();


    /**
     * Check if this {@code PropertyDescriptor} describes an enumerable property
     * @return true if enumerable
     */
    public boolean isEnumerable();


    /**
     * Check if this {@code PropertyDescriptor} describes a wriable property
     * @return true if writable
     */
    public boolean isWritable();


    /**
     * Get the property value as given by this {@code PropertyDescriptor}
     * @return property value
     */
    public Object getValue();


    /**
     * Get the {@link UserAccessorProperty} getter as given by this {@code PropertyDescriptor}
     * @return getter, or null if not available
     */
    public ScriptFunction getGetter();


    /**
     * Get the {@link UserAccessorProperty} setter as given by this {@code PropertyDescriptor}
     * @return setter, or null if not available
     */
    public ScriptFunction getSetter();


    /**
     * Set whether this {@code PropertyDescriptor} describes a configurable property
     * @param flag true if configurable, false otherwise
     */
    public void setConfigurable(boolean flag);


    /**
     * Set whether this {@code PropertyDescriptor} describes an enumerable property
     * @param flag true if enumerable, false otherwise
     */
    public void setEnumerable(boolean flag);


    /**
     * Set whether this {@code PropertyDescriptor} describes a writable property
     * @param flag true if writable, false otherwise
     */
    public void setWritable(boolean flag);


    /**
     * Set the property value for this {@code PropertyDescriptor}
     * @param value property value
     */
    public void setValue(Object value);


    /**
     * Assign a {@link UserAccessorProperty} getter as given to this {@code PropertyDescriptor}
     * @param getter getter, or null if not available
     */
    public void setGetter(Object getter);


    /**
     * Assign a {@link UserAccessorProperty} setter as given to this {@code PropertyDescriptor}
     * @param setter setter, or null if not available
     */
    public void setSetter(Object setter);


    /**
     * Fill in this {@code PropertyDescriptor} from the properties of a given {@link ScriptObject}
     *
     * @param obj the script object
     * @return filled in {@code PropertyDescriptor}
     *
     */
    public PropertyDescriptor fillFrom(ScriptObject obj);


    /**
     * Get the type of this property descriptor.
     * @return property descriptor type, one of {@link PropertyDescriptor#GENERIC}, {@link PropertyDescriptor#DATA} and {@link PropertyDescriptor#ACCESSOR}
     */
    public int type();


    /**
     * Wrapper for {@link ScriptObject#has(Object)}
     *
     * @param key property key
     * @return true if property exists in implementor
     */
    public boolean has(Object key);
}


在ScriptObject对JavaScirpt 中Object方法实现如下:

 Object.getOwnPropertyDescriptor(obj, prop)

 The Object.getOwnPropertyDescriptor() method returns a property descriptor for an own property (that is, one directly present on an object, not present by dint of being along an object's prototype chain) of a given object.

  /**
     * ECMA 8.12.1 [[GetOwnProperty]] (P)
     *
     * @param key property key
     *
     * @return Returns the Property Descriptor of the named own property of this
     * object, or undefined if absent.
     */
    public Object getOwnPropertyDescriptor(final String key) {
        final Property property = getMap().findProperty(key);
        //用来存储全局对象
        final GlobalObject global = (GlobalObject)Context.getGlobalTrusted();
        //存在指定键的属性
        if (property != null) {
        	//get   set 方法定义
            final ScriptFunction get   = property.getGetterFunction(this);
            final ScriptFunction set   = property.getSetterFunction(this);
            //属性配置参数
            final boolean configurable = property.isConfigurable();
            final boolean enumerable   = property.isEnumerable();
            final boolean writable     = property.isWritable();

            if (property instanceof UserAccessorProperty) {
                return global.newAccessorDescriptor(
                    (get != null) ?
                        get :
                        UNDEFINED,
                    (set != null) ?
                        set :
                        UNDEFINED,
                    configurable,
                    enumerable);
            }

            return global.newDataDescriptor(getWithProperty(property), configurable, enumerable, writable);
        }
        
        final int index = getArrayIndex(key);
        final ArrayData array = getArray();

        if (array.has(index)) {
            return array.getDescriptor(global, index);
        }

        return UNDEFINED;
    }

 /**
     * ECMA 8.12.2 [[GetProperty]] (P)
     *
     * @param key property key
     *
     * @return Returns the fully populated Property Descriptor of the named property
     * of this object, or undefined if absent.
     */
    public Object getPropertyDescriptor(final String key) {
        final Object res = getOwnPropertyDescriptor(key);

        if (res != UNDEFINED) {
            return res;
        } else if (getProto() != null) {
            return getProto().getOwnPropertyDescriptor(key);
        } else {
            return UNDEFINED;
        }
    }

 /**
      * Add a new property to the object.
      *
      * @param key          property key
      * @param propertyDesc property descriptor for property
      */
    public final void addOwnProperty(final String key, final PropertyDescriptor propertyDesc) {
        // Already checked that there is no own property with that key.
        PropertyDescriptor pdesc = propertyDesc;

        final int propFlags = Property.toFlags(pdesc);

        if (pdesc.type() == PropertyDescriptor.GENERIC) {
            final GlobalObject global = (GlobalObject) Context.getGlobalTrusted();
            final PropertyDescriptor dDesc = global.newDataDescriptor(UNDEFINED, false, false, false);

            dDesc.fillFrom((ScriptObject)pdesc);
            pdesc = dDesc;
        }

        final int type = pdesc.type();
        if (type == PropertyDescriptor.DATA) {
            addOwnProperty(key, propFlags, pdesc.getValue());
        } else if (type == PropertyDescriptor.ACCESSOR) {
            addOwnProperty(key, propFlags,
                    pdesc.has(GET) ? pdesc.getGetter() : null,
                    pdesc.has(SET) ? pdesc.getSetter() : null);
        }

        checkIntegerKey(key);
    }

ScriptObject 对象如何抽象JavaScript Object对象:

public abstract class ScriptObject{

    /** Map to property information and accessor functions. Ordered by insertion. */
    //存储JavaScript  Object的所有属性
    private PropertyMap map;


    /** objects proto. */
    //存在Object对象的元属性
    private ScriptObject proto;


    /** Object flags. */
    private int flags;


    /** Area for properties added to object after instantiation, see {@link AccessorProperty} */
    public Object[] spill;


    /** Indexed array data. */
    //按照索引来存储属性
    private ArrayData arrayData;

}

其中ArrayData是通过索引来获取JavaScript  Object的属性。

public abstract class ArrayData {


    /** Minimum chunk size for underlying arrays */
    protected static final int CHUNK_SIZE = 16;


    /** Mask for getting a chunk */
    protected static final int CHUNK_MASK = CHUNK_SIZE - 1;


    /**
     * Immutable empty array to get ScriptObjects started.
     */
    public static final ArrayData EMPTY_ARRAY = new NoTypeArrayData();


    /**
     * Length of the array data. Not necessarily length of the wrapped array.
     */
    private long length;


    /**
     * Constructor
     * @param length Virtual length of the array.
     */
    protected ArrayData(final long length) {
        this.length = length;
    }

      public static ArrayData allocate(final Object array) {
        final Class<?> clazz = array.getClass();


        if (clazz == int[].class) {
            return new IntArrayData((int[])array, ((int[])array).length);
        } else if (clazz == long[].class) {
            return new LongArrayData((long[])array, ((long[])array).length);
        } else if (clazz == double[].class) {
            return new NumberArrayData((double[])array, ((double[])array).length);
        } else {
            return new ObjectArrayData((Object[])array, ((Object[])array).length);
        }
    }


}


在JavaScirpt中Function 也是第一类值。ScriptFunction 继承ScriptObject ,表示ScriptFunction拥有JavaScript Object对象的一切功能。

/**
 * Runtime representation of a JavaScript function.
 */
public abstract class ScriptFunction extends ScriptObject {

       /** The parent scope. */
    private final ScriptObject scope;


    private final ScriptFunctionData data;

}

jdk.nashorn.internal.objects.NativeObject  对象剖析。


1 -获取Object 对象的原型。Object.getPrototypeOf ( O )


  /**
     * ECMA 15.2.3.2 Object.getPrototypeOf ( O )
     * @param  self self reference
     * @param  obj object to get prototype from
     * @return the prototype of an object
     */
    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
    public static Object getPrototypeOf(final Object self, final Object obj) {
        if (obj instanceof ScriptObject) {
            return ((ScriptObject)obj).getProto();
        } else if (obj instanceof ScriptObjectMirror) {
            return ((ScriptObjectMirror)obj).getProto();
        } else {
            final JSType type = JSType.of(obj);
            if (type == JSType.OBJECT) {
                // host (Java) objects have null __proto__
                return null;
            }


            // must be some JS primitive
            throw notAnObject(obj);
        }
    }

2 -设置Object 对象的原型。 Object.setPrototypeOf ( O, proto )

 @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
    public static Object setPrototypeOf(final Object self, final Object obj, final Object proto) {
        if (obj instanceof ScriptObject) {
            ((ScriptObject)obj).setProtoCheck(proto);
            return obj;
        } else if (obj instanceof ScriptObjectMirror) {
            ((ScriptObjectMirror)obj).setProto(proto);
            return obj;
        }


        throw notAnObject(obj);
    }


3- 获取Object对象属性描述。 Object.getOwnPropertyDescriptor ( O, P )

 @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
    public static Object getOwnPropertyDescriptor(final Object self, final Object obj, final Object prop) {
        if (obj instanceof ScriptObject) {
            final String       key  = JSType.toString(prop);
            final ScriptObject sobj = (ScriptObject)obj;


            return sobj.getOwnPropertyDescriptor(key);
        } else if (obj instanceof ScriptObjectMirror) {
            final String       key  = JSType.toString(prop);
            final ScriptObjectMirror sobjMirror = (ScriptObjectMirror)obj;


            return sobjMirror.getOwnPropertyDescriptor(key);
        } else {
            throw notAnObject(obj);
        }
    }


4 -获取Object 对象所有属性名称。 Object.getOwnPropertyNames ( O )

 @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
    public static Object getOwnPropertyNames(final Object self, final Object obj) {
        if (obj instanceof ScriptObject) {
            return new NativeArray(((ScriptObject)obj).getOwnKeys(true));
        } else if (obj instanceof ScriptObjectMirror) {
            return new NativeArray(((ScriptObjectMirror)obj).getOwnKeys(true));
        } else {
            throw notAnObject(obj);
        }
    }

5 -创建新Object 对象。  Object.create ( O [, Properties] )

 @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
    public static Object create(final Object self, final Object proto, final Object props) {
        if (proto != null) {
            Global.checkObject(proto);
        }


        // FIXME: should we create a proper object with correct number of
        // properties?
        final ScriptObject newObj = Global.newEmptyInstance();
        newObj.setProto((ScriptObject)proto);
        if (props != UNDEFINED) {
            NativeObject.defineProperties(self, newObj, props);
        }


        return newObj;
    }

6 -定义Object 属性 。   Object.defineProperty ( O, P, Attributes )  和 Object.defineProperties ( O, Properties )

   @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
    public static Object defineProperty(final Object self, final Object obj, final Object prop, final Object attr) {
        Global.checkObject(obj);
        ((ScriptObject)obj).defineOwnProperty(JSType.toString(prop), attr, true);
        return obj;
    }

  @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
    public static Object defineProperties(final Object self, final Object obj, final Object props) {
        Global.checkObject(obj);


        final ScriptObject sobj     = (ScriptObject)obj;
        final Object       propsObj = Global.toObject(props);


        if (propsObj instanceof ScriptObject) {
            final Object[] keys = ((ScriptObject)propsObj).getOwnKeys(false);
            for (final Object key : keys) {
                final String prop = JSType.toString(key);
                sobj.defineOwnProperty(prop, ((ScriptObject)propsObj).get(prop), true);
            }
        }
        return sobj;
    }


7 . 设置Object 自身属性等,包括:seal、freeze、preventExtends、sealed、frozen等。 Object.seal ( O )

  @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
    public static Object seal(final Object self, final Object obj) {
        if (obj instanceof ScriptObject) {
            return ((ScriptObject)obj).seal();
        } else if (obj instanceof ScriptObjectMirror) {
            return ((ScriptObjectMirror)obj).seal();
        } else {
            throw notAnObject(obj);
        }
    }

8. 获取Object 对象所有属性名称。 Object.keys ( O )

 @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
    public static Object keys(final Object self, final Object obj) {
        if (obj instanceof ScriptObject) {
            final ScriptObject sobj = (ScriptObject)obj;
            return new NativeArray(sobj.getOwnKeys(false));
        } else if (obj instanceof ScriptObjectMirror) {
            final ScriptObjectMirror sobjMirror = (ScriptObjectMirror)obj;
            return new NativeArray(sobjMirror.getOwnKeys(false));
        } else {
            throw notAnObject(obj);
        }
    }

9.创建新对象   new Object([value]) and Object([value])

 @Constructor
    public static Object construct(final boolean newObj, final Object self, final Object value) {
        final JSType type = JSType.of(value);


        // Object(null), Object(undefined), Object() are same as "new Object()"


        if (newObj || (type == JSType.NULL || type == JSType.UNDEFINED)) {
            switch (type) {
            case BOOLEAN:
            case NUMBER:
            case STRING:
                return Global.toObject(value);
            case OBJECT:
            case FUNCTION:
                return value;
            case NULL:
            case UNDEFINED:
                // fall through..
            default:
                break;
            }


            return Global.newEmptyInstance();
        }


        return Global.toObject(value);
    }


10.  Object  toString() 方法   Object.prototype.toString ( )

 @Function(attributes = Attribute.NOT_ENUMERABLE)
    public static Object toString(final Object self) {
        return ScriptRuntime.builtinObjectToString(self);
    }

    /**
     * This is the builtin implementation of {@code Object.prototype.toString}
     * @param self reference
     * @return string representation as object
     */
    public static String builtinObjectToString(final Object self) {
        String className;
        // Spec tells us to convert primitives by ToObject..
        // But we don't need to -- all we need is the right class name
        // of the corresponding primitive wrapper type.


        final JSType type = JSType.of(self);


        switch (type) {
        case BOOLEAN:
            className = "Boolean";
            break;
        case NUMBER:
            className = "Number";
            break;
        case STRING:
            className = "String";
            break;
        // special case of null and undefined
        case NULL:
            className = "Null";
            break;
        case UNDEFINED:
            className = "Undefined";
            break;
        case OBJECT:
        case FUNCTION:
            if (self instanceof ScriptObject) {
                className = ((ScriptObject)self).getClassName();
            } else if (self instanceof JSObject) {
                className = ((JSObject)self).getClassName();
            } else {
                className = self.getClass().getName();
            }
            break;
        default:
            // Nashorn extension: use Java class name
            className = self.getClass().getName();
            break;
        }


        final StringBuilder sb = new StringBuilder();
        sb.append("[object ");
        sb.append(className);
        sb.append(']');


        return sb.toString();
    }

11   Object   toLocalString()       Object.prototype.toLocaleString ( )

 @Function(attributes = Attribute.NOT_ENUMERABLE)
    public static Object toLocaleString(final Object self) {
        final Object obj = JSType.toScriptObject(self);
        if (obj instanceof ScriptObject) {
            final InvokeByName toStringInvoker = getTO_STRING();
            final ScriptObject sobj = (ScriptObject)self;
            try {
                final Object toString = toStringInvoker.getGetter().invokeExact(sobj);


                if (Bootstrap.isCallable(toString)) {
                    return toStringInvoker.getInvoker().invokeExact(toString, sobj);
                }
            } catch (final RuntimeException | Error e) {
                throw e;
            } catch (final Throwable t) {
                throw new RuntimeException(t);
            }


            throw typeError("not.a.function", "toString");
        }


        return ScriptRuntime.builtinObjectToString(self);
    }


12  Object  valueOf()方法      Object.prototype.valueOf ( )

 @Function(attributes = Attribute.NOT_ENUMERABLE)
    public static Object valueOf(final Object self) {
        return Global.toObject(self);
    }


 /**
     * ECMA 9.9 ToObject implementation
     *
     * @param obj  an item for which to run ToObject
     * @return ToObject version of given item
     */
    public static Object toObject(final Object obj) {
        if (obj == null || obj == UNDEFINED) {
            throw typeError("not.an.object", ScriptRuntime.safeToString(obj));
        }


        if (obj instanceof ScriptObject) {
            return obj;
        }


        return instance().wrapAsObject(obj);
    }

    @Override
    public Object wrapAsObject(final Object obj) {
        if (obj instanceof Boolean) {
            return new NativeBoolean((Boolean)obj, this);
        } else if (obj instanceof Number) {
            return new NativeNumber(((Number)obj).doubleValue(), this);
        } else if (obj instanceof String || obj instanceof ConsString) {
            return new NativeString((CharSequence)obj, this);
        } else if (obj instanceof Object[]) { // extension
            return new NativeArray((Object[])obj);
        } else if (obj instanceof double[]) { // extension
            return new NativeArray((double[])obj);
        } else if (obj instanceof long[]) {
            return new NativeArray((long[])obj);
        } else if (obj instanceof int[]) {
            return new NativeArray((int[])obj);
        } else {
            // FIXME: more special cases? Map? List?
            return obj;
        }
    }


在Nashorn中ArrayData 是所有数组类的抽象。IntArrayData、LongArrayData、NumberArrayData、ObjectArrayData 为具体实现类。

在ScriptObject 类中存在ArrayData属性来存储数组。

而用来实现JavaScript  Array数组的NativeArray 也继承ScriptObject .所以,NativeArray具有对象的所有属性和方法。可以把JavaScript 的数组Array对象,看做键为有顺序的对象。

例如:

var a =[1,2,3];

console.log(Object.getOwenPropertyDescriptor(a,"1")) 来查询属性描述。


//JavaObject Array 本质也是Object对象。拥有Object所有方法
/**
 * Runtime representation of a JavaScript array. NativeArray only holds numeric
 * keyed values. All other values are stored in spill.
 */
@ScriptClass("Array")
public final class NativeArray extends ScriptObject {

}


但是,NativeArray中length属性比较特殊,可以通过Object.getOwnPropertyDescriptor(Array,"length");来获取length属性描述。 所以,NativeArray重写了defineOwnProperty()方法。



//用来存在JavaScript Object 的数组元素
/**
 *
 * ArrayData - abstraction for wrapping array elements
 */
public abstract class ArrayData {

    /** Minimum chunk size for underlying arrays */
    protected static final int CHUNK_SIZE = 16;

    /** Mask for getting a chunk */
    protected static final int CHUNK_MASK = CHUNK_SIZE - 1;

    /**
     * Immutable empty array to get ScriptObjects started.
     */
    public static final ArrayData EMPTY_ARRAY = new NoTypeArrayData();

    /**
     * Length of the array data. Not necessarily length of the wrapped array.
     */
    private long length;

}



0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:129715次
    • 积分:2610
    • 等级:
    • 排名:第14878名
    • 原创:120篇
    • 转载:4篇
    • 译文:21篇
    • 评论:11条
    最新评论