四、深入JSContext类
看到这,你已经学会最基础的OC与JS互相问好(交互)。下面我们再来深入看下JSContext中的属性和方法。
创建JSContext对象有如下两种方式:
//创建一个新的JS运行环境
- (instancetype)init;
//创建一个新的JS运行环境 并关联到某个虚拟机对象上
- (instancetype)initWithVirtualMachine:(JSVirtualMachine *)virtualMachine;
执行JS代码有如下两个方法:
//执行JS代码 结果将封装成JSValue对象返回
- (JSValue *)evaluateScript:(NSString *)script;
//作用同上
- (JSValue *)evaluateScript:(NSString *)script withSourceURL:(NSURL *)sourceURL NS_AVAILABLE(10_10, 8_0);
下面的属性和方法可以获取到JS运行环境中的一些信息:
//当前的JS运行环境 当JS调用OC方法时,在OC方法中可以用此方法获取到JS运行环境
+ (JSContext *)currentContext;
//获取当前执行的JS函数,当JS调用OC方法时,在OC方法中可以用此方法获取到执行的函数
+ (JSValue *)currentCallee;
//获取当前执行的JS函数中的this指向的对象
+ (JSValue *)currentThis;
//获取当前执行函数的参数列表,当JS调用OC方法时,在OC方法中可以用此方法获取到执行的函数的参数列表
+ (NSArray *)currentArguments;
//获取当前JS运行环境的全局对象
@property (readonly, strong) JSValue *globalObject;
//当运行的JavaScript代码抛出了未捕获的异常时,这个属性会被赋值为抛出的异常
@property (strong) JSValue *exception;
//设置为一个异常捕获的block,如果异常被此block捕获,exception属性就不再被赋值了
@property (copy) void(^exceptionHandler)(JSContext *context, JSValue *exception);
//当前运行环境所关联的虚拟机
@property (readonly, strong) JSVirtualMachine *virtualMachine;
//当前运行环境名称
@property (copy) NSString *name;
//获取当前JS运行环境全局对象上的某个属性
- (JSValue *)objectForKeyedSubscript:(id)key;
//设置当前JS运行环境全局对象上的属性
- (void)setObject:(id)object forKeyedSubscript:(NSObject <NSCopying> *)key;
//将C语言环境的JS运行环境转换为OC环境的JS运行环境
+ (JSContext *)contextWithJSGlobalContextRef:(JSGlobalContextRef)jsGlobalContextRef;
//C语言环境的JS运行上下文
@property (readonly) JSGlobalContextRef JSGlobalContextRef;
五、深入JSValue类
JSValue是JavaScript与Objective-C之间的数据桥梁。在Objective-C中调用JS脚本或者JS调用OC方法都可以使用JSValue来传输数据。其中属性和方法示例如下:
//所对应的JS运行环境
@property (readonly, strong) JSContext *context;
//在指定的JS运行环境中创建一个JSValue对象
+ (JSValue *)valueWithObject:(id)value inContext:(JSContext *)context;
//创建布尔值
+ (JSValue *)valueWithBool:(BOOL)value inContext:(JSContext *)context;
//创建浮点值
+ (JSValue *)valueWithDouble:(double)value inContext:(JSContext *)context;
//创建32位整型值
+ (JSValue *)valueWithInt32:(int32_t)value inContext:(JSContext *)context;
//创建32位无符号整形值
+ (JSValue *)valueWithUInt32:(uint32_t)value inContext:(JSContext *)context;
//创建空的JS对象
+ (JSValue *)valueWithNewObjectInContext:(JSContext *)context;
//创建空的JS数组
+ (JSValue *)valueWithNewArrayInContext:(JSContext *)context;
//创建JS正则对象
+ (JSValue *)valueWithNewRegularExpressionFromPattern:(NSString *)pattern flags:(NSString *)flags inContext:(JSContext *)context;
//创建JS错误信息
+ (JSValue *)valueWithNewErrorFromMessage:(NSString *)message inContext:(JSContext *)context;
//创建JS null值
+ (JSValue *)valueWithNullInContext:(JSContext *)context;
//创建JS undefined值
+ (JSValue *)valueWithUndefinedInContext:(JSContext *)context;
JavaScript中的数据类型和Objective-C的数据类型还是有着很大的差异,其中对应关系如下:
Objective-C JavaScript
nil undefined
NSNull null
NSString string
NSNumber number boolean
NSDictionary Object
NSArray Array
NSDate Date
Block Function
id Object
Class Object
下面这些方法可以将JSValue值转换为Objective-C中的数据类型:
//将JSValue转换为OC对象
- (id)toObject;
//将JSValue转换成特定OC类的对象
- (id)toObjectOfClass:(Class)expectedClass;
//将JSValue转换成布尔值
- (BOOL)toBool;
//将JSValue转换成浮点值
- (double)toDouble;
//将JSValue转换成32位整型值
- (int32_t)toInt32;
//将JSValue转换成32位无符号整型值
- (uint32_t)toUInt32;
//将JSValue转换成NSNumber值
- (NSNumber *)toNumber;
//将JSValue转换成NSString值
- (NSString *)toString;
//将JSValue转换成NSDate值
- (NSDate *)toDate;
//将JSValue转换成NSArray值
- (NSArray *)toArray;
//将JSValue转换成NSDictionary值
- (NSDictionary *)toDictionary;
//获取JSValue对象中某个属性的值
- (JSValue *)valueForProperty:(NSString *)property;
//设置JSValue对象中某个属性的值
- (void)setValue:(id)value forProperty:(NSString *)property;
//删除JSValue对象中的某个属性
- (BOOL)deleteProperty:(NSString *)property;
//判断JSValue对象中是否包含某个属性
- (BOOL)hasProperty:(NSString *)property;
//定义JSValue中的某个属性 这个方法和JavaScript中Object构造函数的defineProperty方法一致
/*
第2个参数设置此属性的描述信息 可以设置的键值如下:
NSString * const JSPropertyDescriptorWritableKey;//设置布尔值 是否可写
NSString * const JSPropertyDescriptorEnumerableKey;//设置布尔值 是否可枚举
NSString * const JSPropertyDescriptorConfigurableKey;//设置布尔值 是否可配置
NSString * const JSPropertyDescriptorValueKey;//设置此属性的值
NSString * const JSPropertyDescriptorGetKey;//设置此属性的get方法
NSString * const JSPropertyDescriptorSetKey;//设置此属性的set方法
以上set、get方法的键和value、可写性的键不能同时存在,其语法是JavaScript保持一致
*/
- (void)defineProperty:(NSString *)property descriptor:(id)descriptor;
//获取JS数组对象某个下标的值
- (JSValue *)valueAtIndex:(NSUInteger)index;
//设置JS数组对象某个下标的值
- (void)setValue:(id)value atIndex:(NSUInteger)index;
//判断此对象是否为undefined
@property (readonly) BOOL isUndefined;
//判断此对象是否为null
@property (readonly) BOOL isNull;
//判断此对象是否为布尔值
@property (readonly) BOOL isBoolean;
//判断此对象是否为数值
@property (readonly) BOOL isNumber;
//判断此对象是否为字符串
@property (readonly) BOOL isString;
//判断此对象是否为object对象
@property (readonly) BOOL isObject;
//判断此对象是否为数组
@property (readonly) BOOL isArray;
//判断此对象是否为日期对象
@property (readonly) BOOL isDate;
//比较两个JSValue是否全相等 对应JavaScript中的===
- (BOOL)isEqualToObject:(id)value;
//比较两个JSValue对象的值是否相等 对应JavaScript中的==
- (BOOL)isEqualWithTypeCoercionToObject:(id)value;
//判断某个对象是否在当前对象的原型链上
- (BOOL)isInstanceOf:(id)value;
//如果JSValue是Function对象 可以调用此方法 和JavaScript中的call方法一致
- (JSValue *)callWithArguments:(NSArray *)arguments;
//如果JSValue是一个构造方法对象 可以调用此方法 和JavaScript中使用new关键字一致
- (JSValue *)constructWithArguments:(NSArray *)arguments;
//用此对象进行函数的调用 当前对象会被绑定到this中
- (JSValue *)invokeMethod:(NSString *)method withArguments:(NSArray *)arguments;
//将CGPoint转换为JSValue对象
+ (JSValue *)valueWithPoint:(CGPoint)point inContext:(JSContext *)context;
//将NSRange转换为JSValue对象
+ (JSValue *)valueWithRange:(NSRange)range inContext:(JSContext *)context;
//将CGRect转换为JSValue对象
+ (JSValue *)valueWithRect:(CGRect)rect inContext:(JSContext *)context;
//将CGSize转换为JSValue对象
+ (JSValue *)valueWithSize:(CGSize)size inContext:(JSContext *)context;
//转换成CGPoint数据
- (CGPoint)toPoint;
//转换成NSRange数据
- (NSRange)toRange;
//转换成CGRect数据
- (CGRect)toRect;
//转换为CGSize数据
- (CGSize)toSize;
//将C风格的JSValueRef对象转换为JSValue对象
+ (JSValue *)valueWithJSValueRef:(JSValueRef)value inContext:(JSContext *)context;
其实在JavaScriptCore框架中还有一个JSManagerValue类,这个的主要作用是管理内存。虽然我们在编写Objective-C代码时有强大的自动引用技术(ARC技术),我们一般无需关心对象的内存问题,在编写JavaScript代码时也有强大的垃圾回收机制(这种机制下甚至连循环引用都不是问题),但是在OC和JS混合开发时,就很容易出现问题了,比如一个JS垃圾回收机制释放掉的对象OC中却还在用,反过来也是一样。JSManagerValue对JSValue进行了一层包装,它可以保证在适合时候使用这个对象时对象都不会被释放,其中方法如下:
//创建JSVlaue对象的包装JSManagerValue
+ (JSManagedValue *)managedValueWithValue:(JSValue *)value;
+ (JSManagedValue *)managedValueWithValue:(JSValue *)value andOwner:(id)owner;
- (instancetype)initWithValue:(JSValue *)value;
//获取所包装的JSValue对象
@property (readonly, strong) JSValue *value;