对于cheater-node的总结——underscore篇

javascript确确实实是一个functional的语言,但问题是它本身并没有提供什么方便使用的库。不过还好我们有社区,有无数英雄们默默无闻地做贡献(眼泪花花儿的)。

介绍一下underscore。点过去看看就知道了,亲切得很。

安装很简单,直接npm就行了。不知道npm是什么的,或者google,或者参考这里

虽然那里有无数的例子,但这里还是给一个吧:

1
2
3
4
5
6
7
8
9
10
11
12
13
var loginInfo = function () {
    var info = [
        ['tz_offset', '480'],
        ['username', 'xxx'],
        ['password', 'yyy'],
        ['realm', 'Zoning']
    ];
    var _ = require('underscore');
 
    return _(info).map(function (item) {
        return item[0] + '=' + item[1];
    }).join('&');
};

“_(info)”返回一个对象,包含一个名叫_wrapped的property。

> var _ = require('underscore');
> var w = _([1, 2, 3]);
> w
{ _wrapped: [ 1, 2, 3 ] }

有了这个东西之后一切都变得美好了,跟所有functional的用法一样,点啊点得就干了很多事儿。不过需要注意的是_(info).map()之后返回的东西就是一个数组了。嗯,不太好……

这个问题人家早就考虑过了:

1
2
3
4
5
6
7
8
9
10
11
12
13
var loginInfo = function () {
    var info = [
        ['tz_offset', '480'],
        ['username', 'xxx'],
        ['password', 'yyy'],
        ['realm', 'Zoning']
    ];
    var _ = require('underscore');
 
    return _(info).chain().map(function (item) {
        return item[0] + '=' + item[1];
    }).join('&').value();
};

先chain一下,玩儿完之后再value一把。这回爽了吧?

顺便说一下,functional这么好的东西为什么会有人跳出来反对呢?

再多废一句话啊。如果你在node的交互式终端里面使用“_”,你会发现诡异的问题,原因是这个终端默认使用“_”表示上一个命令的返回值。

对于cheater-node的总结——继承篇

javascript的对象模型诡异得很,我等半脑残几乎无法领会其精要,仅继承这件简单的事情就有无数种实现方法。不过既然用nodejs,就尽量按照它的标准来走。

Cheater这个类需要触发以及监听事件,所以需要继承EventEmitter这个类。

1
2
3
4
5
6
7
8
var events = require('events');
 
var Cheater = function () {
    events.EventEmitter.call(this);
    ...
};
 
require('sys').inherits(Cheater, events.EventEmitter);

代码倒是简单得很,不过背后还是做了很多事情的。这里写得很详细,就不废话了:http://blog.nodejitsu.com/using-sys-inherits-in-node-js

 

更新:sys这个module在nodejs 0.3之后的版本改成了util,为了保持兼容,sys仍可以用,但是不推荐。

对于cheater-node的总结——异步篇

之前也说了,开始玩儿nodejs,然后拿cheater下手。做得差不多了,总结一下。会有几篇单独的文章,省得看起来乱。

nodejs的基本思想就是异步,这对传统编程模型是彻底的颠覆。刚开始很不习惯,死得很惨,程序怎么都不按我想的跑。一个简单的例子就是http的request,调用不会等待response而是立即返回,然后通过回调函数处理response。

npm安装东西时候的困惑

不知道npm是什么的同学,自己google,提示一下,跟node相关。

npm安装分为两种,local和global,有什么区别这里说得已经很详细了:http://blog.nodejs.org/2011/03/23/npm-1-0-global-vs-local-installation/,我也就不再废话了。

只是有些东西还要解释一下。

刚装好npm的时候,我惊异地发现它所有的安装目录全是777的权限,表示不理解(而且terminal里面看过去,非常不好看),手工改成755。这样带来的问题是如果做global安装的话,普通用户则无法安装;ok没问题,我可以sudo来搞,但是sudo之后新的问题又来了,~/.npm是做cache用的,sudo安装的话这里面东西可都属于root了。这个设计比较土,理想的方案是local安装,~/.npm作为cache,global安装,cache在npm自己的安装路径下。

还有local这种安装方式看起来隔离性挺好,但是对版本管理工具可不怎么友好,不知道有没有办法。

其实根本没有object,所有的东西都是function

我是意思是js里压根儿就没有object,全是浮云;其实根本就是function。

越看越糊涂,这语言设计得真是够可以的。都说是OO,其实就是个屁,所有东西都是用function模拟的。没有任何东西能跟传统意义上的OO对应起来,然后就说这门语言比较深奥,受过传统程序设计教育的人不容易理解。操蛋也不能操成这样吧?如果你说我就是不支持OO,OO算个屁,那也好很多。

只是发发牢骚,不能这么让人忽悠了,但是该学还是要好好学,既然它这么设计了,就咬牙跟进吧。

果然js给我上的第一课就是this

this在js里设计得还真是够复杂,或者确切地说根本就是设计错了(这不是我说的,是写那本the good parts的老大说的)。

一个例子:

1
2
3
4
5
6
7
myObject.double = function () {
    var helper = function () {
        this.value = add(this.value, this.value);
    };
 
    helper();
};

这个方法要做的事情很简单,就是把自己的value属性double一下。一切看起来都很完美,直到真正跑起来,你才会发现报错说value没定义。

原因在于那个内部匿名函数里的this并不是myObject,而是这个函数本身!诡异得很。

解决起来倒是简单:

1
2
3
4
5
6
7
8
9
myObject.double = function () {
    var that = this;
 
    var helper = function () {
        that.value = add(that.value, that.value);
    };
 
    helper();
};

习惯上大家都用that。怪不得之前总是看到that这that那的,还以为是js的保留字。

关于node.js的第一贴

node.js是一个server端js的运行时。

想研究一下,就拿cheater来练手。(注:cheater是在公司里对付cc zone的实现自动登录的小工具)

首先想到的是用来做管理、监控的socket端口。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
var net = require('net');
var server = net.createServer(function (client) { // 有client连上来的时候调用此回调函数
  client.setEncoding('ascii'); // 设置编码,否则下面的data默认使用Buffer
  client.write('> ');
  client.on('data', function (data) { // client发数据过来,触发'data'事件,然后调用此回调函数
    switch (data.trim()) {
      case 'status':
        client.write('heartbeating...\r\n');
        client.write('> ');
        break;
      case 'quit':
        client.end(); // 关掉client
        break;
      case 'shutdown':
        client.end();
        server.close(); // 关掉server
        break;
      default:
        client.write('> ');
        break;
    }
  });
});
server.listen(44050, 'localhost');

值得注意的是,这里只有一个线程,所有异步的事情都靠事件驱动。这也就是node.js一个最核心的思想:用单个线程充分压榨CPU资源,能异步的全都异步了。

刚开始玩儿,哪里不对的,请多指正。顺便帮cnodejs做个广告。

如何在Lift里用javascript的confirm

使用Lift的SHtml.a()设计ajax调用的时候,老版本的Lift不支持给onclick加入用户自己定义的javascript方法,新版本的有了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
   * Create an anchor tag around a body which will do an AJAX call and invoke the function
   *
   * @param jsFunc -- the user function that will be executed. This function will receive as last parameter
   *                  the function that will actually do the ajax call. Hence the user function can decide when
   * 				  to make the ajax request.
   * @param func - the function to invoke when the link is clicked
   * @param body - the NodeSeq to wrap in the anchor tag
   * @param attrs - the anchor node attributes
   */
  def a(jsFunc: Call, func: () =>; JsCmd, body: NodeSeq, attrs: (String, String)*): Elem = {
    attrs.foldLeft(fmapFunc(contextFuncBuilder(func))(name =>;
            <a onclick="{deferCall(Str(name" href="javascript://">{body}</a>))(_ % _)
  }

对于jsFunc可以这样理解:
用户定义了一个方法:

1
2
3
4
function delete(toDelete) {
  if (confirm("Delete?"))
    toDelete()
}

那么jsFunc可以这样定义:Call(“delete”),Lift会把它生成的ajax方法作为最后一个参数传递给delete方法。

感觉Safari比Firefox快多了

看网上的测试都说JS的处理Firefox要快,但是就我的感觉来说,Safari要快不少,用Google Reader的时候特别明显,FF有点卡,Safari完全没有问题。

FF的冷启动实在是太慢了,已经不能接受了。Safari快上很多倍。

所以Mac下准备投靠Safari了,唯一不爽的是没有Delicious的插件可以用。