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;
}