当前位置:嗨网首页>书籍在线阅读

04-更复杂的多行JavaScript

  
选择背景色: 黄橙 洋红 淡粉 水蓝 草绿 白色 选择字体: 宋体 黑体 微软雅黑 楷体 选择字体大小: 恢复默认

[toc]

4.3 更复杂的多行JavaScript

在REPL可以输入跟文件中一样的JavaScript代码,包括用 require 语句来引入模块。下面的代码重复使用了 Query String(qs) 模块:

$ node
> qs = require('querystring');
{ unescapeBuffer: [Function],
  unescape: [Function],
  escape: [Function],
  encode: [Function],
  stringify: [Function],
  decode: [Function],
  parse: [Function] }
> val = qs.parse('file=main&file=secondary&test=one').file;
[ 'main', 'secondary' ]

由于没有使用 var 关键字,所以表达式的结果会打印出来。在本例中,会打印 querystring 这个对象的接口。这真是个意外之喜!因为你不仅可以访问对象,而且可以学到更多关于对象接口的内容。不过,如果你不想让输出太冗长,就用 var 关键字:

> var qs = require('querystring');

通过上述方法,你可以使用 qs 变量访问 querystring 对象。

为了能够集成外部模块,REPL提供了一个代码的文本标识符(用花括号({}包起来的)来支持多行表达式:

> var test = function (x, y) {
... var val = x * y;
.. return val;
.. };
undefined
> test(3,4);
12

REPL中的3个点表示所有在这之后的代码都在花括号中,命令并没有结束。这对于圆括号来讲也同样适用:

> test(4,
... 5);
20

圆点的数量随着嵌套深度的增加而增加。这在交互式环境中很重要,因为你可能在输入代码的时候不知道进行到哪里了:

> var test = function (x, y) {
... var test2 = function (x, y) {
..... return x * y;
..... }
... return test2(x,y);
... }
undefined
> test(3,4);
12
>

在REPL中,你可以直接输入代码,也可以复制粘贴整个Node应用,然后运行。我把服务(Server)端的显示内容缩减和加粗,因为它们太长了,而且当你读到这段代码的时候这些内容很可能会变。

> var http = require('http');
undefined
> http.createServer(function (req, res) {
...
...   // content header
...   res.writeHead(200, {'Content-Type': 'text/plain'});
...
...   res.end("Hello person\n");
... }).listen(8124);
{ domain: 
 { domain: null,
 _events: { error: [Function] },
 _maxListeners: undefined,
 members: [] },
 _
 ... 
 httpAllowHalfOpen: false,
 timeout: 120000,
 _pendingResponseData: 0,
 _connectionKey: '6:null:8124' }
> console.log('Server running at http://127.0.0.1:8124/');
Server running at http://127.0.0.1:8124/
Undefined

你可以从浏览器访问这个应用,这跟用文件写代码然后用Node运行没什么不同。

不将表达式赋值给变量的“缺点”是,应用中可能会显示一个很长的对象。不过,我最喜欢的REPL的特性之一就是能够快速查看对象。例如,在Node网站中,Node核心对象 global 的介绍非常分散。为了更好地了解 global 对象,可以打开一个REPL会话,并将该对象传给 console.log 方法,如下:

> console.log(global)

也可以用一个 gl 变量来达到同样的效果(为了省地方,把 global 缩写成 gl ):

> gl = global;
...
_: [Circular],
  gl: [Circular] }

直接打印 global 也可以输出相同的信息:

> global

我就不在这里复制REPL打印出的内容了。因为 global 的接口太大了,所以这些内容就留给你们在自己的计算机上尝试吧。在这个练习中需要掌握的是,在REPL中,我们可以在任何时间快速、轻易地查看一个对象的接口,这可以让我们很方便地知道哪些方法被调用了,哪些属性是可用的。

在第2章中有很多关于 `global` 的介绍。

在REPL中,我们可以用上下键来切换之前输入过的命令。这样即使在受限的条件下,也能很方便地查看和修改前面写的代码。

请阅读以下REPL会话:

> var myFruit = function(fruitArray,pickOne) {
... return fruitArray[pickOne - 1];
... }
undefined
> fruit = ['apples','oranges','limes','cherries'];
[ 'apples',  'oranges', 'limes',  'cherries' ]
> myFruit(fruit,2);
'oranges'
> myFruit(fruit,0);
undefined
> var myFruit = function(fruitArray,pickOne) {
... if (pickOne <= 0) return 'invalid number';
... return fruitArray[pickOne - 1];
... };
undefined
> myFruit(fruit,0);
'invalid number'
> myFruit(fruit,1);
'apples'

有一些内容在这个输出中没有体现出来,那就是当我需要修改函数来检查输入值时,实际上是按向上键回到函数声明的起始部分,然后按回车键重新启动该函数。我添加了新行,然后再次使用上下键重复前面输出的内容,直到写完函数。我也用了向上键重复函数调用从而导致出现 undefined

说了这么多,好像都是为了不重复输入一些简单的内容。现在考虑一下需要输入正则表达式的场景,比如下面这个例子:

> var ssRe = /^\d{3}-\d{2}-\d{4}$/;
undefined
> ssRe.test('555-55-5555');
true
> var decRe = /^\s*(\+|-)?((\d+(\.\d+)?)|(\.\d+))\s*$/;
undefined
> decRe.test(56.5);
true

碰到正则表达式我就没有办法了,每次都需要调整好多次,表达式才能正确。使用REPL来测试正则表达式很有吸引力。不过,重复输入过长的正则表达式依旧会带来很大的工作量。

幸运的是,在REPL中,我们需要做的仅仅是用上下键找到含有正则表达式的那一行,修改它,按回车键,然后继续测试。

除了上下键以外,还能用Tab键进行自动补全,当然,必须很清楚需要补全的内容才能使用它。举个例子,在命令行输入 va 然后按Tab键,REPL会列出 varvalueOf ,它们都能补全当前的命令。不过,输入 querys 再按Tab键则只有一个选择: querysting 。你也可以用Tab键自动补全任何全局或本地变量。表4-1提供了在REPL中可用的键盘命令的快速汇总。

表4-1  REPL中的键盘控制

| 键盘输入 | 作用 | | :----- | :----- | :----- | :----- | | Ctrl-C | 终止当前命令。按两遍Ctrl-C键会强制退出REPL | | Ctrl-D | 退出REPL | | Tab | 自动补全全局或本地变量 | | 向上键 | 上一条历史命令 | | 向下键 | 下一条历史命令 | | 下划线(_) | 引用上一个表达式的结果 |

如果你担心在REPL中写代码花了很多时间,但却没办法展示写过的代码,别担心,你可以在当前上下文中用 .save 命令来保存结果。在下一小节中我将介绍这个命令和其他一些命令。