四、深入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;