JavaScriptCore入门
一、Objective-C中执行JavaScript代码
#import <JavaScriptCore/JavaScriptCore.h>
int main(int argc, char *argv[]) {
JSContext *context = [[JSContext alloc] init];
JSValue *result = [context evaluateScript:@"1 + 2"];
NSLog(@"1 + 2 = %d", [result toInt32]); // 1 + 2 = 3
return 0;
}二、Objective-C中调用JavaScript函数
#import <JavaScriptCore/JavaScriptCore.h>
int main(int argc, char *argv[]) {
JSContext *context = [[JSContext alloc] init];
[context evaluateScript:@"function sum(a, b){ return a + b; }"];
JSValue *sum = context[@"sum"];
JSValue *result = [sum callWithArguments:@[@1, @2]];
NSLog(@"sum(1, 2) = %d", [result toInt32]); // sum(1, 2) = 3
return 0;
}三、创建JavaScript变量
#import <JavaScriptCore/JavaScriptCore.h>
int main(int argc, char *argv[]) {
JSContext *context = [[JSContext alloc] init];
JSValue *intVar = [JSValue valueWithInt32:123 inContext:context];
context[@"bar"] = intVar;
JSValue *result = [context evaluateScript:@"bar++"];
NSLog(@"bar = %d", [result toInt32]); // bar = 123
return 0;
}更简单的方式:
#import <JavaScriptCore/JavaScriptCore.h>
int main(int argc, char *argv[]) {
JSContext *context = [[JSContext alloc] init];
[context evaluateScript:@"var bar = 123;"];
NSLog(@"bar = %@", context[@"bar"]); // bar = 123
return 0;
}四、监控JavaScript的异常
#import <JavaScriptCore/JavaScriptCore.h>
int main(int argc, char *argv[]) {
JSContext *context = [[JSContext alloc] init];
context.exceptionHandler = ^(JSContext *ctx, JSValue *exception) {
NSLog(@"%@", exception); // ReferenceError: Can't find variable: name
};
[context evaluateScript:@"name.firstName = Eric"];
return 0;
}五、JavaScript中调用Objective-C函数
#import <JavaScriptCore/JavaScriptCore.h>
int main(int argc, char *argv[]) {
JSContext *context = [[JSContext alloc] init];
context[@"sum"] = ^(int a, int b) {
return a + b;
};
JSValue *result = [context evaluateScript:@"sum(1, 2)"];
NSLog(@"sum(1, 2) = %d", [result toInt32]); // sum(1, 2) = 3
return 0;
}六、函数内部为JSContext定义新的变量
#import <JavaScriptCore/JavaScriptCore.h>
int main(int argc, char *argv[]) {
JSContext *context = [[JSContext alloc] init];
context[@"sum"] = ^(int a, int b) {
JSContext *ctx = [JSContext currentContext];
ctx[@"foo"] = @123;
return a + b;
};
JSValue *result = [context evaluateScript:@"sum(1, 2)"];
NSLog(@"sum(1, 2) = %d", [result toInt32]); // sum(1, 2) = 3
NSLog(@"foo = %@", context[@"foo"]); // foo = 123
return 0;
}不能使用context[@"foo"] = @123,必须使用[JSContext currentContext]来获取当前的context,此时获取到的context和context[@"sum"]中的context相同。
七、JavaScript中调用Objective-C函数时动态传参
#import <JavaScriptCore/JavaScriptCore.h>
int main(int argc, char *argv[]) {
JSContext *context = [[JSContext alloc] init];
context[@"count"] = ^() {
NSArray *array = [JSContext currentArguments];
return array.count;
};
JSValue *result = [context evaluateScript:@"count(1, 2)"];
NSLog(@"count(1, 2) = %d", [result toInt32]); // count(1, 2) = 2
JSValue *result2 = [context evaluateScript:@"count(1, 2, 3, 4, 5, 6)"];
NSLog(@"count(1, 2, 3, 4, 5, 6) = %d", [result2 toInt32]); // count(1, 2, 3, 4, 5, 6) = 6
return 0;
}八、JavaScript中操作Objective-C的类
(1)Point3D.h
#import <Foundation/Foundation.h>
#import <JavaScriptCore/JavaScriptCore.h>
@protocol Point3DExport <JSExport>
@property double x;
@property double y;
@property double z;
- (double)length;
@end
@interface Point3D : NSObject <Point3DExport> {
JSContext *context;
}
- (id)initWithContext:(JSContext *)ctx;
@end(2)Point3D.m
#import "Point3D.h"
@implementation Point3D
@synthesize x;
@synthesize y;
@synthesize z;
- (id)initWithContext:(JSContext *)ctx {
if (self == [super init]) {
context = ctx;
context[@"Point3D"] = [Point3D class];
}
return self;
}
- (double)length {
return sqrt(self.x * self.x + self.y * self.y + self.z * self.z);
}
@end(3)调用示例
#import <JavaScriptCore/JavaScriptCore.h>
#import "Point3D.h"
int main(int argc, char *argv[]) {
JSContext *context = [[JSContext alloc] init];
Point3D *point3D = [[Point3D alloc] initWithContext:context];
point3D.x = 1;
point3D.y = 2;
point3D.z = 3;
context[@"point3D"] = point3D;
JSValue *result = [context evaluateScript:@"point3D.x = 4;point3D.y = 5;point3D.z = 6;point3D.length()"];
NSLog(@"point3D.length() = %f", [result toDouble]); // point3D.length() = 8.774964
return 0;
}这里Point3D的定义中遵循了JSExport协议,协议中定义了属性(x、y、z)和方法(length)用来暴露给JavaScript,从而使JavaScript可以使用这些属性(x、y、z)和方法(length)。
九、将JavaScript提取到单独的JS文件中
(1)test.js
var foo = function(a) {
return "I'm foo in JS. Value is " + a;
};
function bar(a) {
return "I'm bar in JS. Value is " + a;
};
foo(123);
bar(456);(2)调用示例
#import <JavaScriptCore/JavaScriptCore.h>
void loadScript(JSContext *context, NSString *fileName) {
NSString *filePath = [NSString stringWithFormat:@"%@/JS/%@", [[NSBundle mainBundle] resourcePath], fileName];
NSString *script = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
[context evaluateScript:script];
}
int main(int argc, char *argv[]) {
JSContext *context = [[JSContext alloc] init];
loadScript(context, @"test.js");
return 0;
}十、给JavaScript添加console.log功能
(1)Console.h
#import <Foundation/Foundation.h>
#import <JavaScriptCore/JavaScriptCore.h>
@protocol ConsoleExport <JSExport>
- (void)log;
@end
@interface Console : NSObject <ConsoleExport> {
JSContext *context;
}
- (id)initWithContext:(JSContext *)ctx;
@end(2)Console.m
#import "Console.h"
@implementation Console
- (id)initWithContext:(JSContext *)ctx {
if (self == [super init]) {
context = ctx;
context[@"Console"] = [Console class];
}
return self;
}
- (void)log {
NSArray *args = [JSContext currentArguments];
NSLog(@"%@", [args componentsJoinedByString:@","]);
}
@end(3)test.js
var foo = function(a) {
return "I'm foo in JS. Value is " + a;
};
function bar(a) {
return "I'm bar in JS. Value is " + a;
};
console.log(foo(123)); // I'm foo in JS. Value is 123
console.log(bar(456)); // I'm bar in JS. Value is 456(4)调用示例
#import <JavaScriptCore/JavaScriptCore.h>
#import "Console.h"
void loadScript(JSContext *context, NSString *fileName) {
NSString *filePath = [NSString stringWithFormat:@"%@/JS/%@", [[NSBundle mainBundle] resourcePath], fileName];
NSString *script = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
[context evaluateScript:script];
}
int main(int argc, char *argv[]) {
JSContext *context = [[JSContext alloc] init];
context[@"console"] = [[Console alloc] initWithContext:context];
loadScript(context, @"test.js");
return 0;
}十一、完善JavaScript的console功能
(1)mock-console.js
(function(){
console.debug = console.info = console.warn = console.error = console.log;
var timer = {};
console.time = function(name) {
timer[name] = Date.now();
};
console.timeEnd = function(name) {
var timeStart = timer[name];
if (!timeStart)
return;
var timeElapsed = Date.now() - timeStart;
console.log(name + ":" + timeElapsed + "ms");
delete timer[name];
};
console.log("=== mock console ok ===");
})();(2)test.js
console.log(Date.now()); // 1433760502752
console.time("sum");
var sum = 0;
for (var i = 0; i < 1E5; i++) {
sum += i;
}
console.info(sum); // 4999950000
console.timeEnd("sum"); // sum:32ms(3)调用示例
int main(int argc, char *argv[]) {
JSContext *context = [[JSContext alloc] init];
context[@"console"] = [[Console alloc] initWithContext:context];
loadScript(context, @"mock-console.js");
loadScript(context, @"test.js");
return 0;
}十二、JavaScript获取硬件信息
(1)test.js
console.log(language()); // en console.log(deviceInfo()); // iPhone Simulator,iPhone OS
(2)调用示例
#import <JavaScriptCore/JavaScriptCore.h>
#import <UIKit/UIKit.h>
#import "Console.h"
void loadScript(JSContext *context, NSString *fileName) {
NSString *filePath = [NSString stringWithFormat:@"%@/JS/%@", [[NSBundle mainBundle] resourcePath], fileName];
NSString *script = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
[context evaluateScript:script];
}
void prepareLanguage(JSContext *context) {
context[@"language"] = ^() {
NSString *language = [NSLocale preferredLanguages][0];
return language;
};
}
void prepareDeviceInfo(JSContext *context) {
context[@"deviceInfo"] = ^() {
NSString *deviceName = [[UIDevice currentDevice] name];
NSString *systemName = [[UIDevice currentDevice] systemName];
return @[deviceName, systemName];
};
}
int main(int argc, char *argv[]) {
JSContext *context = [[JSContext alloc] init];
context[@"console"] = [[Console alloc] initWithContext:context];
prepareLanguage(context);
prepareDeviceInfo(context);
loadScript(context, @"test.js");
return 0;
}更深入的学习,可以参考官方的源码,注释写的很详细。