分享

学习SpiderMonkey60的心得笔记(三)数据类型转换

 Dark_f 2022-02-10
SpiderMonkey内的JS中只有一种数据类型,就是JS::Value。
(1)SpiderMonkey对JS数据类型的判断
我们看Mozilla在SpiderMonkey的JSAPI用户手册中怎么说的呢?
https://developer.mozilla.org/en-US/docs/Mozilla/Projects/SpiderMonkey/JSAPI_Cookbook
      // JavaScript
      var v = computeSomeValue(); //dark-f: 表明v是ComputeSomeValue()得到的某种类型的变量
     //dark-f:e.g. var v = add(3, 6); //(function add(a, b){return a+b;})
     var isString = typeof v === "string"; //dark-f:如果上面的v是string的话, 则isString这个boolean型的值为true
     var isNumber = typeof v === "number";   //dark-f:如同上面解释,v是number型
     var isNull = v === null;       //dark-f:v是null型
     var isBoolean = typeof v === "boolean"; //dark-f:v是boolean型
     var isObject = typeof v === "object" && v !== null; //dark-f:v是object型
     var isSymbol = typeof v === "symbol";
     var isFunction = typeof v === "function";
     var isUndefined = typeof v === "undefined";
 
上面是JS脚本语言,那么SpiderMonkey用什么JSAPI来判断js数据类型呢?同样看上面的手册
      /* JSAPI */
     JS::RootedValue v(cx, ComputeSomeValue()); //dark-f:表明v是由ComputeSomeValue()得到的
     //------------------------
     bool isString = v.isString();
     bool isNumber = v.isNumber();
     bool isInt32 = v.isInt32(); // NOTE: internal representation, not numeric value
     bool isNull = v.isNull();
     bool isBoolean = v.isBoolean();
     bool isObject = v.isObject(); // NOTE: not broken like typeof === "object" is :-)
     bool isSymbol = v.isSymbol();
     bool isFunction = v.isObject() && JS::IsCallable(&v.toObject());
     bool isUndefined = v.isUndefined();
 
SpiderMonkey提供了这样一些JSAPI来判断JS数据类型:
    . isString();
    . isNumber();
    . isInt32();
    . isNull();
    . isBoolean();
    . isObject();
    . isSymbol();
    . JS::IsCallable(&v.toObject());
 
SpiderMonkey还提供了这样一些JSAPI来设定JS数据:(同样看上面的手册)
如果JS脚本是下面这样的:
     // JavaScript
     var v;
    v = 0;
    v = 0.5;
    v = someString;
    v = null;
    v = undefined;
    v = false;
    v = {};
    v = new Symbol(someString);
 
那么在SpiderMonkey里,就可以利用这样一些JSAPI做到:
     /* JSAPI */
    JS::RootedValue v(cx);
    JS::RootedString someString(cx, JS_NewStringCopyZ(cx, "my string"));
    JS::RootedObject obj(cx, JS_NewPlainObject(cx));
    JS::RootedSymbol symbol(cx, JS::NewSymbol(cx, someString));
 
    v.setInt32(0);           // or: v = JS::Int32Value(0);
    v.setDouble(0.5);        // or: v = JS::DoubleValue(0.5);
    v.setString(someString); // or: v = JS::StringValue(someString);
    v.setNull();             // or: v = JS::NullValue();
    v.setUndefined();        // or: v = JS::UndefinedValue();
    v.setBoolean(false);     // or: v = JS::BooleanValue(false);
    v.setObject(*obj);   // or: v = JS::ObjectValue(*obj);
    v.setSymbol(symbol);  // or: v = JS::SymbolValue(symbol);
    v.setNaN();     // { setDouble(JS::GenericNaN()); }
    v.setMagic(JSWhyMagic why);
    v.setObjectOrNull(JSObject* arg);
 
也即,SpiderMonkey有如下的JSAPI来设定JS::Value的数值:
     . setInt32();
     . setDouble();
     . setString();
     . setNull();
     . setUndefined();
     . setBoolean();
 
(2)SpiderMonkey对数据类型的转换
那么怎么让JS中的数据,C/C++能看的明白呢?这就必须在这两种数据之间存在转换方法。
在SpiderMonkey60编译完成后的include目录下的js目录内有一个Value.h头文件,这里列出了各种转换JSAPI方法。
     bool toBoolean() const { return value().toBoolean(); }
     double toNumber() const { return value().toNumber(); }
     int32_t toInt32() const { return value().toInt32(); }
     double toDouble() const { return value().toDouble(); }
     JSString* toString() const { return value().toString(); }
     JS::Symbol* toSymbol() const { return value().toSymbol(); }
     JSObject& toObject() const { return value().toObject(); }
     JSObject* toObjectOrNull() const { return value().toObjectOrNull(); }
例如:在c++里,如果有一个JS::Value变量rval,是int32型的,要把这个变量的值显示出来,可以这样:
      printf("The value is %d\n", rval.toInt32());
在Mozilla的JSAPI参考中(地址如下)
https://developer.mozilla.org/en-US/docs/Mozilla/Projects/SpiderMonkey/JSAPI_reference

The following functions convert JS values to various types. They can be safely applied to JS::Value of any type.
They may return new objects. For example, JS_ValueToObject(cx, s) where s is a string creates a new String wrapper object.
These functions may call JavaScript methods. For example, JS_ValueToString(cx, obj) may call obj.toString().
     . JS::ToBoolean (Added in SpiderMonkey 17)
     . JS::ToUint16 (Added in SpiderMonkey 17)
     . JS::ToInt32 (Added in SpiderMonkey 17)
     . JS::ToUint32 (Added in SpiderMonkey 17)
     . JS::ToInt64 (Added in SpiderMonkey 17)
     . JS::ToUint64 (Added in SpiderMonkey 17)
     . JS::ToNumber (Added in SpiderMonkey 17)
     . JS::ToString (Added in SpiderMonkey 31)
     . JS::OrdinaryToPrimitive (Added in SpiderMonkey 38)
     . JS_ValueToConstructor
     . JS_ValueToFunction
     . JS_ValueToObject
     . JS_ValueToSource
它们的语法如下:(在js目录里的conversion.h这个头文件里)
    bool
    JS::ToBoolean(JS::HandleValue v);
    bool
    JS::ToUint16(JSContext *cx, JS::HandleValue v, uint16_t *out);
    bool
    JS::ToInt32(JSContext *cx, JS::HandleValue v, int32_t *out);
    bool
    JS::ToUint32(JSContext *cx, JS::HandleValue v, uint32_t *out);
    bool
    JS::ToInt64(JSContext *cx, JS::HandleValue v, int64_t *out);
    bool
    JS::ToUint64(JSContext *cx, JS::HandleValue v, uint64_t *out);
    bool
    JS::ToNumber(JSContext *cx, JS::HandleValue v, double *out);
 #include "js/Conversions.h" // as of SpiderMonkey 38; previously in jsapi.h
    JSString*
    JS::ToString(JSContext *cx, JS::HandleValue v);
 /*
  * ES6 draft 20141224, 7.1.1, second algorithm.
  *
  * Most users shouldn't call this -- use JS::ToBoolean, ToNumber, or ToString
  * instead.  This will typically only be called from custom convert hooks that
  * wish to fall back to the ES6 default conversion behavior shared by most
  * objects in JS, codified as OrdinaryToPrimitive.
  */
 extern JS_PUBLIC_API bool OrdinaryToPrimitive(JSContext* cx, HandleObject obj,
              JSType type,
              MutableHandleValue vp);
             
下面的JSAPI来自jsapi.h文件 
 /* Don't want to export data, so provide accessors for non-inline Values. */
    JS::Value
    JS_GetNaNValue(JSContext* cx);
    JS::Value
    JS_GetNegativeInfinityValue(JSContext* cx);
    JS::Value
    JS_GetPositiveInfinityValue(JSContext* cx);
    JS::Value
    JS_GetEmptyStringValue(JSContext* cx);
    JSString*
    JS_GetEmptyString(JSContext* cx);
    bool
    JS_ValueToObject(JSContext* cx, JS::HandleValue v, JS::MutableHandleObject objp);
    JSFunction*
    JS_ValueToFunction(JSContext* cx, JS::HandleValue v);
    JSFunction*
    JS_ValueToConstructor(JSContext* cx, JS::HandleValue v);
    JSString*
    JS_ValueToSource(JSContext* cx, JS::Handle<JS::Value> v);
    bool
    JS_DoubleIsInt32(double d, int32_t* ip);
    JSType
    JS_TypeOfValue(JSContext* cx, JS::Handle<JS::Value> v);

    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多