javascript教程和

您的位置: >>
在本片文章中,作者将向您讲述JavaScript中最鲜为人知的秘密。
  原文作者:  原文链接:  翻译编辑:
  数据类型和定义
  1. Null是个对象
  JavaScript众多类型中有个Null类型,它有个唯一的值null, 即它的字面量,定义为完全没有任何意义的值。其表现得像个对象,如下检测代码:
alert(typeof null); //弹出 'object'
  如下截图:
  尽管typeof值显示是"object",但null并不认为是一个对象实例。要知道,JavaScript中的值都是对象实例,每个数值都是Number对象,每个对象都是Object对象。因为null是没有值的,所以,很明显,null不是任何东西的实例。因此,下面的值等于false。
alert(null instanceof Object); //为 false
  译者注:null还有被理解为对象占位符一说
  2. NaN是个数值
  NaN本意是表示某个值不是数值,但是其本身却又是数值,且不等于其自身,很奇怪吧,看下面的代码:
alert(typeof NaN); //弹出 'Number'alert(NaN === NaN); //为 false
  结果如下截图:
  实际上NaN不等于任何东西。要确认某玩意是不是NaN只能使用isNaN.
  3. 无关键字的数组等同于false(关于Truthy和Falsy)
  下面是JavaScript另一个极品怪癖:
alert(new Array() == false); //为 true
  结果如下截图:
  想要知道这里发生了什么,你需要理解truthy和falsy这个概念。它们是一种true/flase字面量。在JavaScript中,所有的非Boolean型值都会内置一个boolean标志,当这个值被要求有boolean行为的时候,这个内置布尔值就会出现,例如当你要跟Boolean型值比对的时候。
  因为苹果不能和梨做比较,所以当JavaScript两个不同类型的值要求做比较的时候,它首先会将其弱化成相同的类型。false, undefined, null, 0, "", NaN都弱化成false。这种强制转化并不是一直存在的,只有当作为表达式使用的时候。看下面这个简单的例子:
var someVar =0;alert(someVar == false); //显示 true
  结果如下截图:
  上面测试中,我们试图将数值0和boolean值false做比较,因两者的数据类型不兼容,JavaScript自动强制转换成统一的等同的truthy和falsy,其中0等同于false(正如上面所提及的)。
  你可能注意到了,上面一些等同false的值中并没有空数组。只因空数组是个怪胚子:其本身实际上属于truthy,但是当空数组与Boolean型做比较的时候,其行为表现又属于falsy。不解?这是由原因的。先举个例子验证下空数组的奇怪脾气:
var someVar = []; //空数组alert(someVar == false); //结果 trueif (someVar) alert('hello'); //alert语句执行, 所以someVar当作true
  结果如下截图,连续弹出两个框框:
  译者注:之所以会有这种差异,根据作者的说法,数组内置toString()方法,例如直接alert的时候,会以join(&,&)的形式弹出字符串,空数组自然就是空字符串,于是等同false。具体可参见作者另外一篇文章,《Twisted logic: understanding truthy & falsy》。不过我个人奇怪的是,像空对象,空函数,弱等于true或者false的时候都显示false,为何?真的因为数组是个怪胎,需要特殊考虑吗?
  为避免强制转换在比较方面的问题,你可以使用强等于(===)代替弱等于(==)。
var someVar = 0;alert(someVar == false); //结果 true & 0属于falsyalert(someVar === false); //结果 false & zero是个数值, 不是布尔值
  结果如下截图(win7 FF4):
  如果你想深入探究JavaScript中类型强制转换等些特有的癖好,可以参见官方相关的文档规范:
  正则表达式
  4. replace()可以接受回调函数
  这是JavaScript最鲜为人知的秘密之一,v1.3中首次引入。大部分情况下,replace()的使用类似下面:
alert('10 13 21 48 52'.replace(/\d+/g, '*')); //用 * 替换所有的数字
  这是一个简单的替换,一个字符串,一个星号。但是,如果我们希望在替换发生的时候有更多的控制,该怎么办呢?我们只希望替换30以下的数值,该怎么办呢?此时如果仅仅依靠正则表达式是鞭长莫及的。我们需要借助回调函数的东风对每个匹配进行处理。
alert('10 13 21 48 52'.replace(/\d+/g, function(match) {
return parseInt(match) &30?'*' :}));
  当每个匹配完成的时候,JavaScript应用回调函数,传递匹配内容给match参数。然后,根据回调函数里面的过滤规则,要么返回星号,要么返回匹配本身(无替换发生)。
  如下截图:
  5. 正则表达式:不只是match和replace
  不少javascript工程师都是只通过match和replace和正则表达式打交道。但JavaScript所定义的正则表达式相关方法远不止这两个。
  其中值得一提的是test(),其工作方式类似match(),但是返回值却不一样:test()返回的是布尔型,用来验证是否匹配,执行速度高于match()。
alert(/\w{3,}/.test('Hello')); //弹出 'true'
  上面行代码用来验证字符串是否有三个以上普通字符,显然"hello"是符合要求的,所以弹出true。
  结果如下截图:
  我们还应注意RegExp对象,你可以用此创建动态正则表达式对象,例如:
function findWord(word, string) {
var instancesOfWord = string.match(new RegExp('\\b'+word+'\\b', 'ig'));
alert(instancesOfWord);}findWord('car', 'Carl went to buy a car but had forgotten his credit card.');
  这儿,我们基于参数word动态创建了匹配验证。这段测试代码作用是不区分大小选的情况下选择car这个单词。眼睛一扫而过,测试英文句子中只有一个单词是car,因此这里的演出仅一个单词。\b是用来表示单词边界的。
  结果如下截图:
  函数和作用域
  6. 你可以冒充作用域
  作用域这玩意是用来决定什么变量是可用的,独立的JavaScript(如JavaScript不是运行中函数中)在window对象的全局作用域下操作,window对象在任何情况下都可以访问。然而函数中声明的局部变量只能在该函数中使用。
var animal ='dog';function getAnimal(adjective) { alert(adjective+''+this.animal); }getAnimal('lovely'); //弹出 'lovely dog'
  这儿我们的变量和函数都声明在全局作用域中。因为this指向当前作用域,在这个例子中就是window。因此,该函数寻找window.animal,也就是'dog'了。到目前为止,一切正常。然而,实际上,我们可以让函数运行在不同的作用域下,而忽视其本身的作用域。我们可以用一个内置的称为call()的方法来实现作用域的冒充。
var animal ='dog';function getAnimal(adjective) { alert(adjective+''+this.animal); };var myObj = {animal: 'camel'};getAnimal.call(myObj, 'lovely'); //弹出 'lovely camel'
  call()方法中的第一个参数可以冒充函数中的this,因此,这里的this.animal实际上就是myObj.animal,也就是'camel'了。后面的参数就作为普通参数传给函数体。
  另外一个与之相关的是apply()方法,其作用于call()一样,不同之处在于,传递给函数的参数是以数组形式表示的,而不是独立的变量们。所以,上面的测试代码如果用apply()表示就是:
getAnimal.apply(myObj, ['lovely']); //函数参数以数组形式发送
  demo页面中,点击第一个按钮的结果如下截图:  点击第二个和第三个按钮的结果如下:
  7. 函数可以执行其本身
  下面这个是很OK的:
(function() { alert('hello'); })(); //弹出 'hello'
  这里的解析足够简单:声明一个函数,然后因为()解析立即执行它。你可能会奇怪为何要这么做(指直接屁股后面()调用),这看上去是有点自相矛盾的:函数包含的通常是我们想稍后执行的代码,而不是当下解析即执行的,否则,我们就没有必要把代码放在函数中。
  另外一个执行函数自身(self-executing functions (SEFs))的不错使用是为在延迟代码中使用绑定变量值,例如事件的回调(callback),超时执行(timeouts)和间隔执行(intervals)。如下例子:
var someVar ='hello';setTimeout(function() { alert(someVar); }, 1000);var someVar ='goodbye';
  Newbies在论坛里总问这里timeout的弹出为什么是goodbye而不是hello?答案就timeout中的回调函数直到其运行的时候才去赋值someVar变量的值。而那个时候,someVar已经被goodbye重写了好长时间了。
  SEFs提供了一个解决此问题的方法。不是像上面一样含蓄地指定timeout回调,而是直接将someVar值以参数的形式传进去。效果显著,这意味着我们传入并孤立了someVar值,保护其无论后面是地震海啸还是女朋友发飙咆哮都不会改变。
var someVar = 'hello';setTimeout((function(someVar) {returnfunction()
{ alert(someVar); }})(someVar), 1000);var someVar ='goodbye';
  风水轮流转,这次,这里的弹出就是hello了。这就是函数参数和外部变量的点差别了哈。
  例如,最后一个按钮点击后的弹出如下:
  浏览器
  8. FireFox以RGB格式读与返回颜色而非Hex
  直到现在我都没有真正理解为何Mozilla会这样子。为了有个清晰的认识,看下面这个例子:
&!--#somePara { color: #f90; }--&&p id="somePara"&Hello, world!&/p&&script&var ie = navigator.appVersion.indexOf('MSIE') !=-1;var p = document.getElementById('somePara');alert(ie ? p.currentStyle.color : getComputedStyle(p, null).color);&/script&
  大部分浏览器弹出的结果是ff9900,而FireFox的结果却是rgb(255, 153, 0),RGB的形式。经常,处理颜色的时候,我们需要花费不少代码将RGB颜色转为Hex。
  下面是上面代码在不同浏览器下的结果:
  其它杂七杂八
  9. 0.1 + 0.2 !== 0.3
  这个古怪的问题不只会出现在JavaScript中,这是计算机科学中一个普遍存在的问题,影响了很多的语言。标题等式输出的结果是0.00004。
  这是个被称为机器精度的问题。当JavaScript尝试执行(0.1 + 0.2)这行代码的时候,会把值转换成它们喜欢的二进制口味。这就是问题的起源,0.1实际上并不是0.1,而是其二进制形式。从本质上将,当你写下这些值的时候,它们注定要失去精度。你可能只是希望得到个简单的两位小数,但你得到的(根据Chris Pine的注解)是二进制浮点计算。好比你想把一段应该翻译成中文简体,结果出来的却是繁体,其中还是有差异是不一样的。
一般处理与此相关的问题有两个做法:
转换成整数再计算,计算完毕再转换成希望的小数内容
调整你的逻辑,设定允许范围为不是指定结果。
  例如,我们不应该下面这样:
var num1=0.1, num2=0.2, shouldEqual=0.3;alert(num1 + num2 == shouldEqual); //false
  而可以试试这样:
alert(num1 + num2 & shouldEqual - 0.001&& num1 + num2 & shouldEqual +0.001); //true
  10. 未定义(undefined)可以被定义(defined)
  我们以一个和风细雨的小古怪结束。听起来可能有点奇怪,undefined并不是JavaScript中的保留字,尽管它有特殊的意义,并且是唯一的方法确定变量是否未定义。因此:
var someValert(someVar == undefined); //显示 true
  目前为止,一切看上去风平浪静,正常无比,但剧情总是很狗血:
undefined ="I'm not undefined!";var someValert(someVar == undefined); //显示 false!
  这就是为什么jQuery源码中最外部的闭包函数要有个并没有传入的undefined参数,目的就是保护undefined不要被外部的些不良乘虚而入。
Web前端热门文章
Web前端最新文章本帖子已过去太久远了,不再提供回复功能。&&&&&&&&&&&&&&&&&&
posts - 34,comments - 53,trackbacks - 0
JavaScript中比较运算符'=='与'==='可能大家用的比较多的是&==&、对于&===&很多人可能很陌生、不常见、列出两者以及其他比较运算符的区别和大家进行分享:
假设给定 x=5:
运算符描述例子
&&&&&& 等于&&
&&&&&&&&&&&& &x==8 为 false
&&&&&& 全等(值和类型)
&&&&&&&&&&&&& x===5 为 true;x==="5" 为 false
&&&&&& 不等于
&&&&&&&&&&&&& x!=8 为 true
&&&&&& 大于
&&&&&&&&&&&&& x&8 为 false
&&&&&& 小于
&&&&&&&&&&&&& x&8 为 true
&&&&&& 大于或等于
&&&&&&&&&&&&& x&=8 为 false
&&&&&& 小于或等于
&&&&&&&&&&&&& x&=8 为 true
阅读(...) 评论()登录以解锁更多InfoQ新功能
获取更新并接收通知
给您喜爱的内容点赞
关注您喜爱的编辑与同行
966,690 九月 独立访问用户
语言 & 开发
架构 & 设计
文化 & 方法
您目前处于:
Nashorn——在JDK 8中融合Java与JavaScript之力
Nashorn——在JDK 8中融合Java与JavaScript之力
Oliver Zeigermann
0&他的粉丝
0&他的粉丝
日. 估计阅读时间:
:Facebook、Snapchat、Tumblr等背后的核心技术
相关厂商内容
相关赞助商
由于Nashorn随JDK 8而来,它还增加了简洁的支持。接下来,我们很快就会看到更多细节。
让我们从一个小例子开始。首先,你可能需要安装JDK 8和NetBeans、IntelliJ IDEA或者Eclipse。对于集成JavaScript开发,它们都至少提供了基本的支持。让我们创建一个简单的Java项目,其中包含下面两个示例文件,并运行它:
(点击图片可以查看大图)
在第12行,我们使用引擎的&eval&方法对任意JavaScript代码求值。在本示例中,我们只是加载了上面的JavaScript文件并对其求值。你可能会发现那个&print&并不熟悉。它不是JavaScript的内建函数,。你也可以将 &hello world&的打印代码直接嵌入到传递给&eval&方法的字符串,但将JavaScript放在它自己的文件中为其开启了全新的工具世界。
Eclipse目前还没有对Nashorn提供专门的支持,不过,通过(JSDT)项目,它已经支持JavaScript的基本工具和编辑。
(点击图片可以查看大图)
13.1(社区版和旗舰版)提供了出色的JavaScript和支持。它有一个全功能的调试器,甚至允许在Java和JavaScript之间保持重构同步,因此举例来说,如果你重命名一个被JavaScript引用的Java类,或者重命名一个用于Java源代码中的JavaScript文件,那么该IDE将跨语言修改相应的引用。
下面是一个例子,展示如何调试从Java调用的JavaScript(请注意,NetBeans也提供了JavaScript调试器,如下截图所示):
(点击图片可以查看大图)
你可能会说,工具看上去不错,而且新实现修复了性能以及一致性问题,但我为什么应该用它呢?一个原因是一般的脚本编写。有时候,能够直接插入任何类型的字符串,并任由它被解释,会很方便。有时候,没有碍事的编译器,或者不用为静态类型担心,可能也是不错的。或者,你可能对Node.js编程模型感兴趣,它也可以和Java一起使用,在本文的末尾我们会看到。另外,还有个不得不提一下,与Java相比,使用JavaScript进行JavaFX开发会快很多。
Nashorn引擎可以使用命令从命令行调用。你可以不带任何参数调用它,这会将你带入一个交互模式,或者你可以传递一个希望执行的JavaScript文件名,或者你可以用它作为shell脚本的替代,像这样:
#!/usr/bin/env jjs
var name = $ARG[0];
print(name ? &Hello, ${name}!& : &Hello, world!&);
向jjs传递程序参数,需要加&&&前缀。因此举例来说,你可以这样调用:
./hello-script.js & Joe
如果没有&&&前缀,参数会被解释为文件名。
向Java传递数据或者从Java传出数据
正如上文所说的那样,你可以从Java代码直接调用JavaScript;只需获取一个引擎对象并调用它的&eval&方法。你可以将数据作为字符串显式传递&&
ScriptEngineManager scriptEngineManager =
new ScriptEngineManager();
ScriptEngine nashorn =
scriptEngineManager.getEngineByName(&nashorn&);
String name = &Olli&;
nashorn.eval(&print('& + name + &')&);
&&或者你可以在Java中传递绑定,它们是可以从JavaScript引擎内部访问的全局变量:
int valueIn = 10;
SimpleBindings simpleBindings = new SimpleBindings();
simpleBindings.put(&globalValue&, valueIn);
nashorn.eval(&print (globalValue)&, simpleBindings);
JavaScript eval的求值结果将会从引擎的&eval&方法返回:
Integer result = (Integer) nashorn.eval(&1 + 2&);
assert(result == 3);
在Nashorn中使用Java类
前面已经提到,Nashorn最强大的功能之一源于在JavaScript中调用Java类。你不仅能够访问类并创建实例,你还可以继承他们,调用他们的静态方法,几乎可以做任何你能在Java中做的事。
作为一个例子,让我们看下来龙去脉。JavaScript没有任何语言特性是面向并发的,所有常见的运行时环境都是单线程的,或者至少没有任何共享状态。有趣的是,在Nashorn环境中,JavaScript确实可以并发运行,并且有共享状态,就像在Java中一样:
// 访问Java类Thread
var Thread = Java.type(&java.lang.Thread&);
// 带有run方法的子类
var MyThread = Java.extend(Thread, {
run: function() {
print(&Run in separate thread&);
var th = new MyThread();
th.start();
th.join();
请注意,从Nashorn访问类的规范做法是使用Java.type,并且可以使用Java.extend扩展一个类。
令人高兴的函数式
从各方面来说,随着JDK 8的发布,Java&&至少在某种程度上&&已经变成一种。开发人员可以在集合上使用高阶函数,比如,遍历所有的元素。高阶函数是把另一个函数当作参数的函数,它可以用这个函数参数做些有意义的事情。请看下面Java中高阶函数的示例:
List&Integer& list = Arrays.asList(3, 4, 1, 2);
list.forEach(new Consumer() {
public void accept(Object o) {
System.out.println(o);
对于这个例子,我们的传统实现方式是使用一个&外部&循环遍历元素,但现在,我们没有那样做,而是将一个&Consumer&函数传递给了&forEach&操作,一个高阶的&内部循环&操作会将集合中的每个元素一个一个地传递给Consumer的&accept&方法并执行它。
如上所述,对于这样的高阶函数,函数式语言的做法是接收一个函数参数,而不是一个对象。虽然在传统上讲,传递函数引用本身超出了Java的范围,但现在,JDK 8有一些语法糖,使它可以使用Lambda表达式(又称为&闭包&)来实现那种表示方式。例如:
List&Integer& list = Arrays.asList(3, 4, 1, 2);
list.forEach(el -& System.out.println(el));
在这种情况下,&forEach&的参数是这样一个函数引用的形式。这是可行的,因为Customer是一个函数式接口(有时称为&单一抽象方法(Single Abstract Method)&类型或&SAM&)。
那么,我们为什么要在讨论Nashorn时谈论Lambda表达式呢?因为在JavaScript中,开发人员也可以这样编写代码,而在这种情况下,Nashorn可以特别好地缩小Java和JavaScript之间的差距。尤其是,它甚至允许开发人员将纯JavaScript函数作为函数式接口(SAM类型)的实现来传递。
让我们来看一些纯JavaScript代码,它们与上述Java代码实现一样的功能。注意,在JavaScript中没有内置的列表类型,只有数组;不过这些数组的大小是动态分配的,而且有与Java列表类似的方法。因此,在这个例子中,我们调用一个JavaScript数组的&for Each&方法:
var jsArray = [4,1,3,2];
jsArray.forEach(function(el) { print(el) } );
相似之处显而易见;但那还不是全部。开发人员还可以将这样一个JavaScript数组转换成一个Java列表:
var list = java.util.Arrays.asList(jsArray);
看见了吗?是的,这就是在Nashorn中运行的JavaScript。既然它现在是一个Java列表,那么开发人员就可以调用其&forEach&方法。注意,这个&forEach&方法不同于我们在JavaScript数组上调用的那个,它是定义在java集合上的&forEach&方法。这里,我们仍然传递一个纯JavaScript函数:
list.forEach(function(el) { print(el) } );
Nashorn允许开发人员在需要使用函数式接口(SAM类型)的地方提供纯JavaScript函数引用。这不仅适应于Java,也适应于JavaScript。
ECMAScript的下一个版本&&预计是今年的最后一个版本&&将包含函数的短语法,允许开发人员将函数写成近似Java Lambda表达式的形式,只不过它使用双箭头=&。这进一步增强了一致性。
Nashorn JavaScript特有的方言
正如简介部分所提到的那样,Nashorn支持的JavaScript实现了。我并不建议使用这些扩展,因为它们既不是Java,也不是JavaScript,两类开发人员都会觉得它不正常。另一方面,有两个扩展在整个Oracle文档中被大量使用,因此,我们应该了解它们。首先,让我们为了解第一个扩展做些准备。正如前文所述,开发人员可以使用Java.extend从JavaScript中扩展一个Java类。如果需要继承一个抽象Java类或者实现一个接口,那么可以使用一种更简便的语法。在这种情况下,开发人员实际上可以调用抽象类或接口的构造函数,并传入一个描述方法实现的JavaScript对象常量。这种常量不过是name/value对,你可能了解JSON格式,这与那个类似。这使我们可以像下面这样实现Runnable接口:
var r = new java.lang.Runnable({
run: function() {
print(&running...\n&);
在这个例子中,一个对象常量指定了run方法的实现,我们实际上是用它调用了Runnable的构造函数。注意,这是Nashorn的实现提供给我们的一种方式,否则,我们无法在JavaScript这样做。
示例代码已经与我们在Java中以匿名内部类实现接口的方式类似了,但还不完全一样。这将我们带到了第一个扩展,它允许开发人员在调用构造函数时在右括号&)&后面传递最后一个参数。这种做法的代码如下:
var r = new java.lang.Runnable() {
run: function() {
print(&running...\n&);
&&它实现了完全相同的功能,但更像Java。
第二个常用的扩展一种函数的简便写法,它允许删除单行函数方法体中的两个花括号以及return语句。这样,上一节中的例子:
list.forEach(function(el) { print(el) } );
可以表达的更简洁一些:
list.forEach(function(el) print(el));
我们已经看到,有了Nashorn,我们就有了一个嵌入到Java的优秀的JavaScript引擎。我们也已经看到,我们可以从Nashorn访问任意Java类。更进一步,它&为Java平台带来了Node编程模型、API和模块生态系统&。要了解这意味着什么以及它为什么令人振奋,我们首先必须了解是什么。从根本上说,Node是将Chrome的V8 JavaScript引擎剥离出来,使它可以从命令行运行,而不再需要浏览器。这样,JavaScript就不是只能在浏览器中运行了,而且可以在服务器端运行。在服务器端以任何有意义的方式运行JavaScript都至少需要访问文件系统和网络。为了做到这一点,Node内嵌了一个名为的库,以异步方式实现该项功能。实际上,这意味着操作系统调用永远不会阻塞,即使它过一段时间才能返回。开发人员需要提供一个回调函数代替阻塞。该函数会在调用完成时立即触发,如果有任何结果就返回。
有若干公司都在重要的应用程序中使用了Node,其中包括和。
让我们来看一个JavaScript的小例子,它是我根据上的例子改写而来:
//加载&http&模块(这是阻塞的)来处理http请求
var http = require('http');
//当有请求时,返回&Hello,World\n&
function handleRequest(req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello, World\n');
//监听localhost,端口1337
//并提供回调函数handleRequest
//这里体现了其非阻塞/异步特性
http.createServer(handleRequest).listen(1337, '127.0.0.1');
//记录到控制台,确保我们在沿着正确的方向前进
console.log('Get your hello at http://127.0.0.1:1337/');
要运行这段代码,需要安装Node,然后将上述JavaScript代码保存到一个文件中。最后,将该文件作为一个参数调用Node。
将libuv绑定到Java类,并使JavaScript可以访问它们,Avatar.js旨在以这种方式提供与Node相同的核心API。虽然这可能听上去很繁琐,但这种方法很有效。Avatar.js支持许多Node模块。对Node主流Web框架&&的支持表明,这种方式确实适用于许多现有的项目。
令人遗憾的是,在写这篇文章的时候,还没有一个Avatar.js的二进制分发包。有一个说明了如何从源代码进行构建,但是如果真没有那么多时间从头开始构建,那么也可以从下载二进制文件而不是自行构建。两种方式都可以,但为了更快的得到结果,我建议选择第二种方式。
一旦创建了二进制文件并放进了lib文件夹,就可以使用下面这样的语句调用Avatar.js框架:
java -Djava.library.path=lib -jar lib/avatar-js.jar helloWorld.js
假设演示服务器(上述代码)保存到了一个名为&helloWorld.js&的文件中。
让我们再问一次,这为什么有用?Oracle的专家()指出了该库的几个适用场景。我对其中的两点持大致相同的看法,即:
有一个Node应用程序,并希望使用某个Java库作为Node API的补充
希望切换到JavaScript和Node API,但需要将遗留的Java代码部分或全部嵌入
两个应用场景都可以通过使用Avatar.js并从JavaScript代码中调用任何需要的Java类来实现。我们已经看到,Nashorn支持这种做法。
下面我将举一个第一个应用场景的例子。JavaScript目前只有一种表示数值的类型,名为&number&。这相当于Java的&double&精度,并且有同样的限制。JavaScript的number,像Java的double一样,并不能表示任意的范围和精度,比如在计量货币时。
在Java中,我们可以使用BigDecimal,它正是用于此类情况。但JavaScript没有内置与此等效的类型,因此,我们就可以直接从JavaScript代码中访问BigDecimal类,安全地处理货币值。
让我们看一个Web服务示例,它计算某个数量的百分之几是多少。首先,需要有一个函数执行实际的计算:
var BigDecimal = Java.type('java.math.BigDecimal');
function calculatePercentage(amount, percentage) {
var result = new BigDecimal(amount).multiply(
new BigDecimal(percentage)).divide(
new BigDecimal(&100&), 2, BigDecimal.ROUND_HALF_EVEN);
return result.toPlainString();
JavaScript没有类型声明,除此之外,上述代码与我针对该任务编写的Java代码非常像:
public static String calculate(String amount, String percentage) {
BigDecimal result = new BigDecimal(amount).multiply(
new BigDecimal(percentage)).divide(
new BigDecimal(&100&), 2, BigDecimal.ROUND_HALF_EVEN);
return result.toPlainString();
我们只需要替换上文Node示例中的handleRequest函数就可以完成代码。替换后的代码如下:
//加载工具模块&url&来解析url
var url = require('url');
function handleRequest(req, res) {
// '/calculate' Web服务地址
if (url.parse(req.url).pathname === '/calculate') {
var query = url.parse(req.url, true).
//数量和百分比作为查询参数传入
var result = calculatePercentage(query.amount,
query.percentage);
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end(result + '\n');
我们又使用了Node核心模块来处理请求URL,从中解析出查询参数amount和percentage。
当启动服务器(如前所述)并使用浏览器发出下面这样一个请求时,
http://localhost:1337/calculate?
amount=13&percentage=7.59
就会得到正确的结果&8.73&。这在单纯使用JavaScript的&number&类型时是不可能。
当你决定将现有的JEE应用程序迁移到JavaScript和Node时,第二个应用场景就有意义了。在这种情况下,你很容易就可以从JavaScript代码内访问现有的所有服务。另一个相关的应用场景是,在使用JavaScript和Node构建新的服务器功能时,仍然可以受益于现有的JEE服务。
此外,基于Avatar.js的也朝着相同的方向发展。该项目的详细信息超出了本文的讨论范围,但读者可以阅读做一个粗略的了解。该项目的基本思想是,用JavaScript编写应用程序,并访问JEE服务。Avatar项目包含Avatar.js的一个二进制分发包,但它需要Glassfish用于安装和开发。
Nashorn项目增强了JDK 6中原有的Rhino实现,极大地提升了运行时间较长的应用程序的性能,例如用在Web服务器中的时候。Nashorn将Java与JavaScript集成,甚至还考虑了JDK 8的新Lambda表达式。Avatar.js带来了真正的创新,它基于这些特性构建,并提供了企业级Java与JavaScript代码的集成,同时在很大程度上与JavaScript服务器端编程事实上的标准兼容。
完整实例以及用于Mac OS X的Avatar.js二进制文件可以从上下载。
Oliver Zeigermann是一名来自德国汉堡的自由软件架构师/开发人员、顾问和教练。目前,他致力于在企业应用程序中使用JavaScript。
查看英文原文:
Author Contacted
语言 & 开发
30 他的粉丝
JavaScript
25 他的粉丝
0 他的粉丝
998 他的粉丝
告诉我们您的想法
允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p
当有人回复此评论时请E-mail通知我
允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p
当有人回复此评论时请E-mail通知我
允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p
当有人回复此评论时请E-mail通知我
赞助商链接
InfoQ每周精要
订阅InfoQ每周精要,加入拥有25万多名资深开发者的庞大技术社区。
架构 & 设计
文化 & 方法
<及所有内容,版权所有 &#169;
C4Media Inc.
服务器由 提供, 我们最信赖的ISP伙伴。
北京创新网媒广告有限公司
京ICP备号-7
找回密码....
InfoQ账号使用的E-mail
关注你最喜爱的话题和作者
快速浏览网站内你所感兴趣话题的精选内容。
内容自由定制
选择想要阅读的主题和喜爱的作者定制自己的新闻源。
设置通知机制以获取内容更新对您而言是否重要
注意:如果要修改您的邮箱,我们将会发送确认邮件到您原来的邮箱。
使用现有的公司名称
修改公司名称为:
公司性质:
使用现有的公司性质
修改公司性质为:
使用现有的公司规模
修改公司规模为:
使用现在的国家
使用现在的省份
Subscribe to our newsletter?
Subscribe to our industry email notices?
我们发现您在使用ad blocker。
我们理解您使用ad blocker的初衷,但为了保证InfoQ能够继续以免费方式为您服务,我们需要您的支持。InfoQ绝不会在未经您许可的情况下将您的数据提供给第三方。我们仅将其用于向读者发送相关广告内容。请您将InfoQ添加至白名单,感谢您的理解与支持。}

我要回帖

更多关于 javascript基础知识 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信