一直想写一写JavaScriptCore,因为在公司写了很多关于这方面的代码,今天腾出来时间好好说一说,对自己也是个巩固,如果能帮到别人那更好了,如有问题欢迎指出
比较常见的JS引擎有Google的V8(Android,Chrome),还有JSCore(Safari)。Safari的内核就是WebKit
先来看一看JavaScriptCore.h 主要用到的就是这几个类
JavaScriptCore.h
先写个Hello World吧😄
JSContext *jsContext = [[JSContext alloc] init];
JSValue *hello = [jsContext evaluateScript:@"'Hello World!'"];
NSLog(@"%@",[hello toString]);
这里面包含了JSCore中最重要的两个类,JSContext和JSValue
JSContext
JSContextJSContext对象代表一个JavaScript执行环境,我们使用JSContext在原生里去执行JS代码,执行过的JS都会存在当前的JSContext中。
我们调用JSContext可以在原生中执行各种JS代码,比如数值运算,对象创建,甚至可以通过JS操作各种原生的API去创建原生的视图等
jsContext[@"nslog"] = ^(NSString* message) {
NSLog(@"%@", message);
};
[jsContext evaluateScript:@"console.log = nslog;"];
上面是模拟实现原生的NSLog,这样我们在JS代码中使用console.log就会在原生的控制台中打印出内容啦
JSValue
JSValue.hJSValue简单点来讲就是JS里面的值,它可以用作Native和JS之间的类型互换,头文件里已经标明了几种类型
举几个例子
JSValue *number = [jsContext evaluateScript:@"1+1"];
NSLog(@"%d",[number toInt32]);
JSValue *arr = [jsContext evaluateScript:@"['ha','haha','hahaha']"];
NSLog(@"%@",[arr toArray]);
也可以这样使用
[jsContext evaluateScript:@"var num = 1 + 1"];
JSValue *number = jsContext[@"num"];
NSLog(@"%d",[number toInt32]);
[jsContext evaluateScript:@"var dic = {r:255,g:127,b:80}"];
JSValue *dic = jsContext[@"dic"];
NSLog(@"%@",[dic toDictionary]);
JSVirtualMachine
一个JSVirtualMachine的实例就是一个完整独立的JavaScript的执行环境,它主要用于实现JSCore的并发执行,以及内存管理
回到开头的HelloWorld,可以这么写
JSVirtualMachine *jvm = [[JSVirtualMachine alloc] init];
JSContext *jsContext = [[JSContext alloc] initWithVirtualMachine:jvm];
JSValue *hello = [jsContext evaluateScript:@"'Hello World!'"];
NSLog(@"%@",[hello toString]);
每个JSContext都属于一个虚拟机JSVirtualMachine,一个虚拟机可以包含多个JSContext。然而多个虚拟机之间是相对独立的,以此来实现JSCore的并发执行。
JSVirtualMachine *jvm = [[JSVirtualMachine alloc] init];
JSVirtualMachine *jvm2 = [[JSVirtualMachine alloc] init];
JSContext *jsContext = [[JSContext alloc] initWithVirtualMachine:jvm];
JSContext *jsContext2 = [[JSContext alloc] initWithVirtualMachine:jvm2];
// 串行队列
dispatch_queue_t queue = dispatch_queue_create("test", DISPATCH_QUEUE_SERIAL);
// 异步执行
dispatch_async(queue, ^{
[[NSThread currentThread] setName:@"thread--1"];
for (int i = 0; i < 3; i++) {
NSLog(@"串行异步1 %@ %@",[[jsContext evaluateScript:@"'thread---1'"] toString],[NSThread currentThread]);
}
});
dispatch_async(queue, ^{
[[NSThread currentThread] setName:@"thread--2"];
for (int i = 0; i < 3; i++) {
NSLog(@"串行异步2 %@ %@",[[jsContext2 evaluateScript:@"'thread---2'"] toString],[NSThread currentThread]);
}
});
JSExport
JSExport可以将native完整提供给JS环境
native类实现JSExport协议 将想要提供的属性或方法提供出来
@protocol NativeExport <JSExport>
@property (nonatomic,copy) NSString *str;
- (void)method;
- (void)method2:(NSString *)str;
@end
// 在类中实现该协议
@interface NativeObject : NSObject<NativeExport>
@end
实现该方法
- (void)method {
NSLog(@"call native");
}
- (void)method2:(NSString *)str {
NSLog(@"%@",str);
}
将类对象注入到JS环境中,JS可以随意定义一个变量来接收它
jsContext[@"native"] = [[NativeObject alloc] init];
调用一下试试
[jsContext evaluateScript:@"native.method()"];
[jsContext evaluateScript:@"native.method2('hello')"];
控制台
如果要在提供的native类里面注入,也可以这么写,不过要记得释放
@implementation NativeObject
- (instancetype)init {
if (self = [super init]) {
jsContext[@"native"] = self;
}
return self;
}
@end
//要记得释放它
- (void)closeContext {
self.jsContext[@"native"] = nil;
}
网友评论