使用 JSValue
需要进行架构审查:本文档旨在支持针对 React Native 的“旧”或“遗留”架构的开发。它可能适用也可能不适用于新架构的开发,需要审查并可能需要更新。有关 React Native Windows 中 React Native 架构的信息,请参阅新旧架构。
有关 Windows 上原生开发的最新信息,请参阅原生平台:概述。
本文档和底层平台代码正在开发中。
JSValue
是一种原生的、不可变的、非变量值类型,旨在保存任何常用的 JS 类型:bool
、int
、double
、string
、数组和对象。它提供给希望使用与 Microsoft.ReactNative
提供的 WinRT ABI 表面兼容的 folly::dynamic
类型的原生开发者(编写原生模块或视图管理器)。
提供了两种 JSValue
实现:一种用于 Microsoft.ReactNative.Cxx
共享项目中的 C++ 开发者,另一种用于 Microsoft.ReactNative.SharedManaged
项目中的 C# 开发者。
本文档的目的是提供与
folly/dynamic.h
支持的场景等效的功能。
概述
以下是一些入门代码示例(假设使用了 using Microsoft.ReactNative.Managed;
)
JSValue twelve = 12; // creates a JSValue that holds an integer
JSValue str = "string"; // yep, this one is a String
// a few other types.
JSValue nul = JSValue.Null;
JSValue boolean = false;
// Arrays can be initialized with JSValueArray.
JSValueArray array = new JSValueArray() { "array ", "of", 4, " elements" };
Debug.Assert(array.Count == 4);
JSValueArray emptyArray = new JSValueArray();
Debug.Assert(emptyArray.Count == 0);
// JSValueArrays can be implicitly converted to JSValues, however
// like all JSValues they will be immutable. Accessing the contents
// via the AsArray() method will return an IReadOnlyList<JSValue>.
JSValue array2 = array;
Debug.Assert(array2.AsArray().Count == 4);
JSValue emptyArray2 = emptyArray;
Debug.Assert(emptyArray2.AsArray().Count == 0);
// Maps from strings to JSValues are called objects. The
// JSValueObject type is how you make an empty map from strings
// to JSValues.
JSValueObject map = new JSValueObject();
map["something"] = 12;
map["another_something"] = map["something"].AsInt32() * 2;
// JSValueObjects may be initialized this way
JSValueObject map2 = new JSValueObject()
{
{ "something", 12 },
{ "another_something", 24 },
};
// Like JSValueArrays, JSValueObjects can also be implicitly
// converted to JSValues, and likewise they will be immutable.
// Accessing the contents via the AsObject() method will return an
// IReadOnlyDictionary<string, JSValue>.
JSValue map3 = map;
Debug.Assert(map3.AsObject().Count == 2);
JSValue map4 = map2;
Debug.Assert(map4.AsObject().Count == 2);
运行时类型检查和转换
虽然大多数不支持的操作会导致编译错误,但 JSValue
上的一些操作需要在运行时检查存储的类型是否与操作兼容。某些操作可能会抛出运行时异常,或者在类型转换失败和返回默认值时产生意外行为。
希望更多示例能澄清这一点
JSValue dint = 42;
JSValue str = "foo";
JSValue anotherStr = str + "something"; // fine
JSValue thisDoesNotCompile = str + dint; // compilation error
可以为某些基本类型请求显式类型转换
JSValue dint = 12345678;
JSValue doub = dint.AsDouble(); // doub will hold 12345678.0
JSValue str = dint.AsString(); // str == "12345678"
JSValue hugeInt = long.MaxValue; // hugeInt = 9223372036854775807
JSValue hugeDoub = hugeInt.AsDouble(); // hugeDoub = 9.2233720368547758E+18
迭代和查找
您可以像遍历任何 C# 可枚举对象一样遍历 JSValueArray
。
JSValueArray array = new JSValueArray() { 2, 3, "foo" };
foreach (var val in array)
{
doSomethingWith(val);
}
您可以像遍历任何其他 IDictionary<string, JSValue>
一样遍历 JSValueObject
。
JSValueObject obj = new JSValueObject() { { "2", 3}, { "hello", "world" }, { "x", 4 } };
foreach (var kvp in obj)
{
// Key is kvp.Key, value is kvp.Value
processKey(kvp.Key);
processValue(kvp.Value);
}
foreach (var key in obj.Keys)
{
processKey(key);
}
foreach (var value in obj.Values)
{
processValue(value);
}
您可以使用 TryGetValue()
方法在 JSValueObject
中按键查找元素,该方法接受键,如果键存在则返回 true
,并通过 out 变量提供值。如果键不存在,则返回 false
,并且 out 变量将为 null。
JSValueObject obj = new JSValueObject() { { "2", 3}, { "hello", "world" }, { "x", 4 } };
if (obj.TryGetValue("hello", out JSValue value))
{
// value is "world"
}
if (obj.TryGetValue("no_such_key", out JSValue value2))
{
// this block will not be executed
}
// value2 is null
概述
以下是一些入门代码示例(假设使用了 #include "JSValue.h"
)
JSValue twelve = 12; // creates a JSValue that holds an integer
JSValue str = "string"; // yep, this one is a String
// a few other types.
JSValue nul = nullptr;
JSValue boolean = false;
// Arrays can be initialized with JSValueArray.
JSValueArray array = JSValueArray{ "array ", "of", 4, " elements" };
assert(array.size() == 4);
JSValueArray emptyArray = JSValueArray{};
assert(emptyArray.size() == 0);
// JSValueArrays can be explicitly converted to JSValues, however
// like all JSValues they will be immutable. Accessing the contents
// via the AsArray() method will return a const JSValueArray.
JSValue array2 = std::move(array);
assert(array2.AsArray().size() == 4);
JSValue emptyArray2 = std::move(emptyArray);
assert(emptyArray2.AsArray().size() == 0);
// Maps from strings to JSValues are called objects. The
// JSValueObject type is how you make an empty map from strings
// to JSValues.
JSValueObject map = JSValueObject{};
map["something"] = 12;
map["another_something"] = map["something"].AsInt32() * 2;
// JSValueObjects may be initialized this way
JSValueObject map2 = JSValueObject
{
{ "something", 12 },
{ "another_something", 24 },
};
// Like JSValueArrays, JSValueObjects can also be explicitly
// converted to JSValues, and likewise they will be immutable.
// Accessing the contents via the AsObject() method will return
// a const JSValueObject.
JSValue map3 = std::move(map);
assert(map3.AsObject().size() == 2);
JSValue map4 = std::move(map2);
assert(map4.AsObject().size() == 2);
运行时类型检查和转换
虽然大多数不支持的操作会导致编译错误,但 JSValue
上的一些操作需要在运行时检查存储的类型是否与操作兼容。某些操作可能会抛出运行时异常,或者在类型转换失败和返回默认值时产生意外行为。
希望更多示例能澄清这一点
JSValue dint = 42;
JSValue str = "foo";
JSValue thisDoesNotCompile = str + "something"; // compilation error
JSValue thisDoesNotCompile2 = str + dint; // compilation error
可以为某些基本类型请求显式类型转换
#ifdef max
#undef max
#endif
JSValue dint = 12345678;
JSValue doub = dint.AsDouble(); // doub will hold 12345678.0
JSValue str = dint.AsString(); // str == "12345678"
JSValue hugeInt = std::numeric_limits<int64_t>::max();
JSValue hugeDoub = hugeInt.AsDouble();
迭代和查找
您可以像遍历任何 C++ 序列容器一样遍历 JSValueArray
。
JSValueArray array = JSValueArray{ 2, 3, "foo" };
for (auto& val : array)
{
doSomethingWith(val);
}
您可以像遍历任何其他 C++ std::map
一样遍历 JSValueObject
。
JSValueObject obj = JSValueObject{ { "2", 3}, { "hello", "world" }, { "x", 4 } };
for (auto& pair : obj)
{
// Key is pair.first, value is pair.second
processKey(pair.first);
processValue(pair.second);
}
您可以使用 find()
方法在动态映射中按键查找元素,该方法返回一个迭代器。
JSValueObject obj = JSValueObject{ { "2", 3}, { "hello", "world" }, { "x", 4 } };
auto pos = obj.find("hello");
// pos->first is "hello"
// pos->second is "world"
auto pos = obj.find("no_such_key");
// pos == obj.end()
用于 JSON
与 folly::dynamic
不同,JSValue
没有内置的直接从 JSValue
解析或创建 JSON 字符串的机制。
性能
JSValue
对于在原生代码中操作大型复杂 JS 对象非常有用,让您能够随机访问所需的值。但是,请注意,这样做会带来性能损失,因为整个 JS 对象将在传递到您的代码之前解析为 JSValue
。
在您的外部原生代码中使用 JSValue
的性能开销是 Microsoft.ReactNative
自身内部使用 folly::dynamic
的性能开销之外的额外开销。数据通过高性能序列化接口从 Microsoft.ReactNative
导出,但将该数据重新读入 JSValue
意味着需要花费时间和内存来完全重新构建原始对象结构。
更多信息请参见 数据封送。