所谓工厂函数,就是指这些内建函数都是类对象,当你调用他们时,实际上是创建了一个“类实例”。
我们首先通过new关键字创建了一个对象,obj就相当于Object的实例。我们通过类实例化了一个对象,然后给这个对象相应的属性,最后返回对象。我们可以通过调用这个函数来创建对象,这样的话,实际上工厂函数也很好理解了:
1,它是一个函数。
2,它用来创建对象。
3,它像工厂一样,“生产”出来的函数都是“标准件”(拥有同样的属性)
JavaScript项目有一个趋势,变得难以测试和重构,因为我们经常鼓励使用复杂的抽象层。原型和类实现一个简单的想法使用复杂和不人性的工具,如 new 和 this ,即使现在,这仍然引起各种各样的困惑,几年后他们被添加到语言。
构造函数与工厂函数之间差异:1.工厂函数需要创建对象,以及必须有返回值2.工厂函数针对的都是Object的对象模型,而构造函数可以匹配自定义的对象模型即前者不论创建什么都只有一个xx instanceof Object而后者根据自定义名而定类型,如上举例所示3.构造函数弊端,如果在全局中定义相同的局部变量,容易造成全局污染,因为this.xx如果在局部获取不到,就会去全局中获取4.构造函数可以重写,可以在全局中添加新属性和方法Person.prototype = {},但工厂函数只能在局部添加各自适用场合:构造函数:适应用于大型项目,属性以及方法时常变换的项目工厂函数:适应用于小型项目,或者正在制作过程还没有成型的项目Java用ScriptEngine解析脚本javax.script,始于JDK1.6,不过现在只有sun实现的JavaScript的解析器,难道是因为主要用来解析js语法所以归类到JEE的范畴?不过基本足够了,一般的用途主要是能解析通用的表达式就好,比如X >= 1(X作为参数传入)这样的表达式,也能利用js的函数语法,创造一个就像Java的函数一样存在于内存中随时可以被调用的函数,更可以将js中的对象直接转换成java对象。
Script主要类及接口
ScriptEngineManager、ScriptEngine、CompiledScript和Bindings 4个类或接口
ScriptEngineManager是一个工厂的集合,可以通过name或tag的方式获取某个脚本的工厂并生成一个此脚本的ScriptEngine,目前只有javascript的工厂。通过工厂函数得到了ScriptEngine之后,就可以用这个对象来解析脚本字符串了,直接调用Object obj = ScriptEngine.eval(String script)即可,返回的obj为表达式的值,比如true、false或int值。
CompiledScript可以将ScriptEngine解析一段脚本的结果存起来,方便多次调用。只要将ScriptEngine用Compilable接口强制转换后,调用compile(String script)就返回了一个CompiledScript对象,要用的时候每次调用一下CompiledScript.eval()即可,一般适合用于js函数的使用。
Bindings的概念算稍微复杂点,我的理解Bindings是用来存放数据的容器。它有3个层级,为Global级、Engine级和Local级,前2者通过ScriptEngine.getBindings()获得,是唯一的对象,而Local Binding由ScriptEngine.createBindings()获得,很好理解,每次都产生一个新的。Global对应到工厂,Engine对应到ScriptEngine,向这2者里面加入任何数据或者编译后的脚本执行对象,在每一份新生成的Local Binding里面都会存在。
ScriptEngine代码示例
先来看一段JS
var arrclass = new Array()
arrclass.push(new Class(20000,"计算机-软件开发"))
arrclass.push(new Class(30000,"计算机-网络/通讯"))
arrclass.push(new Class(10000,"计算机-硬件开发"))
arrclass.push(new Class(40000,"计算机-管理"))
arrclass.push(new Class(50000,"计算机-品质管理/技术支持"))
arrclass.push(new Class(320000,"电子/电器/半导体/仪器仪表"))
java代码实现解析
public void parseJS() {
//1、通过Http请求获取js的String数据,格式如上
String jsData = getJsData("url")
//2、观察js结构,自定义Class,push到数组中,java中需要定义跟js中的Class的声明
String clazz = "function Class(classId, className){ this.classId=classIdthis.className=className}"
//3、初始化ScriptEngine
ScriptEngine engine = new ScriptEngineManager().getEngineByName("javascript")
//4、js中未定义返回对象,这里需要将Class数据转换成字符串的数组返回,个人觉得很别扭,不知道是理解错误还是确实如此?
//如果不这样做则直接在js后加上arrclass,cScript.evel()则返回NativeObject对象的数组
String fun = "var result = new Array() for(var i=0i <arrclass.lengthi++){result.push(new Array(arrclass[i].classId,arrclass[i].className))}result"
Compilable compilable = (Compilable) engine
//4、使用NativeArray获取数据
CompiledScript cScript
try {
cScript = compilable.compile(clazz + jsData + fun)
NativeArray na = (NativeArray) cScript.eval()
for (int i = 0i <na.getLength()i++) {
NativeArray nv = (NativeArray) na.get(i, null)
System.out.println(nv.get(0, null).toString() + " " + nv.get(1, null).toString())
}
} catch (ScriptException ex) {
ex.printStackTrace()
}
}
java代码中执行js计算
public void js() {
// 创建脚本引擎管理器
ScriptEngineManager sem = new ScriptEngineManager()
// 创建一个处理JavaScript的脚本引擎
ScriptEngine engine = sem.getEngineByExtension("js")
try {
// 执行js公式
engine.eval("if(6>5){flag=true}else{flag =false}")
} catch (ScriptException ex) {
ex.printStackTrace()
}
//看看我们预期的反馈结果 true
System.out.println(engine.get("flag"))
}
Java解析JS另一大引擎-Rhino
Rhino是完全用Java编写的JavaScript的开放源代码实现。它通常是嵌入到Java应用程序提供给最终用户的脚本。它被镶嵌在J2SE6作为默认的Java脚本引擎。
使用Rhino来解析,感觉一切都很清晰明朗.
public void parseJS() {
//1、通过Http请求获取js的String数据,格式如上
String jsData = getJsData("url")
//2、定义跟js中的Class的声明
String clazz = "function Class(classId, className){ this.classId=classIdthis.className=className}"
//3、初始化Context
Context cx = Context.enter()
Scriptable scope = cx.initStandardObjects()
Object result = cx.evaluateString(scope, clazz + jsData + "arrclass", "arrclass", 1, null)
System.out.println(NativeJSON.stringify(cx, scope, result, null, null))
Context.exit()
}