显示标签为“javascript”的博文。显示所有博文
显示标签为“javascript”的博文。显示所有博文

2008年9月16日星期二

JavaScript也够魔幻的

可支持按如下方式使用,而且这几个方法不是在一个函数实现中判断arguments.length来走不同分支的,而是可以动态添加方法的——当然,由于JavaScript不是静态类型语言,只能根据参数个数来决定走那个实现,不能根据参数类型
var users = new Users();
users.find(); // Finds all
users.find("John"); // Finds users by name
users.find("John", "Resig"); // Finds users by first and last name
users.find("John", "E", "Resig");
作者说的private members,其实只是在constructor中声明的变量和函数,没有挂到this后面,根据JavaScript的闭包原则,constructor中声明的函数是可以访问这些private变量和函数的,但在constructor之外(比如通过classFoo.prototype.funcB = function(...) {...}创建的方法)的就无法访问这些东西了。所以作者称constructor里面通过this.funcA = function(...) {...}方式添加的成员函数为priviliged method.
  • 属性名一定要满足标识符规定么?
今天一个兄弟项目组的同事碰到一个问题,让我帮忙看看。他在Firebug中看到一个params对象有如下一些属性显示了出来(大致如此)
params
filter[0][data][type]="string"
filter[0][data][value]=2
filter[0][type]="field"
start=0
limit=20
然后他想去取有多少个filter,然后逐一处理。但访问params.filter时出错,访问params.filter[0]时也出错。但上面连数组内各个值都显示出来了啊。

我开始也觉得不可能,但看了一阵,觉得Filebug的显示比较奇怪,为什么它不把filter作为一个成员,再在下面显示数组内容呢? 然后我用for (e in params) { alter(e) }试了一下,发现它有属性就叫做"
filter[0][data][type]"!

这是怎么设进去的呢?
以前看文章说JavaScript中foo.bar=1和foo["bar"]=1是等价的, 当然现在不经过params.filter[0]就直接设置params.filter[0][data][type]="string"是不行的,所以估计是这种方式: params["filter[0][data][type]"]="string"——不过也说明了这两种不是等价的。至于为什么要这么写,据后来另外一个同事说PHP里面可以直接用上这样的数据(我是不懂)。

2008年3月20日星期四

JavaScript上的闭包(closure): 第二种说法

而Martin Fowler对闭包的介绍却是另外一种解释: 闭包就是一段可作为参数传递的代码。从他提供的示例来看只是个匿名函数,跟嵌套函数没有什么关系,其他人也给出了C#PythonJavaScript上的例子,却跟上面的不一样。
  1. Array.prototype.select = function(func)
  2. {
  3. var ary = [];
  4. for (var i = 0; i < this.length; ++i)
  5. {
  6. if (func(this[i]))
  7. ary[ary.length] = this[i];
  8. }
  9. return ary;
  10. };
  11. function managers_noclosure(emps) {
  12. var result = [];
  13. for (var i = 0; i < class="delimiters1">)
  14. {
  15. var e = emps[i];
  16. if (e.isManager) result[result.length] = e;
  17. }
  18. return result;
  19. }
  20. function managers(emps)
  21. {
  22. return emps.select(function (e){ return e.isManager; });
  23. }

而现在嚷嚷得比较厉害的Java支持也是依照这种概念: http://www.infoq.com/cn/news/2007/09/catching-up-with-closures

按照这种定义,闭包非常类似于C语言中的函数指针、C++里面的模板函数、Java中的内嵌类,虽然Martin Fowler在他文章里也在说明闭包跟这些概念的不同时提到了运行环境的问题,但似乎没有什么说服力,至少从例子上是看不出来的。

个人感觉,前面一种说法是正确的,这种说法不大对。虽然Martin Fowler的名气很大。

JavaScript上的闭包(closure)

闭包这个概念随着并发、函数式编程的复兴,也热乎了起来。”跟上Java闭包(Closure)的步伐“一文中说:
Mark Jason Dominus在Perl概述中的话语作为开场:在未来的三十年中,人们将会取笑那些发明没有闭包特性的语言的人,如同他们现在正取笑那些发明没有递归这种特性的语言的人是一个道理。
  • 定义
那么这是个啥东西? Wikipedia上对closure的解释是:
In computer science, a closure is a function that is evaluated in an environment containing one or more bound variables. When called, the function can access these variables. The explicit use of closures is associated with functional programming and with languages such as ML and Lisp. Constructs such as objects in other languages can also be modeled with closures.

In some languages, a closure may occur when a function is defined within another function, and the inner function refers to local variables of the outer function. At runtime, when the outer function executes, a closure is formed, consisting of the inner function’s code and references to any variables of the outer function required by the closure.
这个说法比较抽象。还是来看看实际的例子吧。
  • 实例说明
JavaScript中,简单的说法是: In JavaScript, if you use the function keyword inside another function, you are creating a closure.(摘自Morris Johns的JavaScript Closures for Dummies, 中文翻译可看这里: 在JavaScript中,什么是闭包)。
  1. function sayHello(name) {
  2. var text = 'Hello ' + name; // local variable
  3. var sayAlert = function() { alert(text); }
  4. return sayAlert;
  5. }
  6. var say = sayHello('Bob');
  7. say();

注 意sayAlert是sayHello的一个嵌套函数,当var say = sayHello('Bob')这行执行完之后,因为say是对内部函数sayAlert的一个引用,所以这个函数对象不会被释放,而sayAlert的 执行环境(execution context)也不会被释放,一个函数与它的数据、执行环境绑在一起,这个sayHello就是一个闭包了。

这里有好几个概念: 嵌套函数,函数引用,作用域链(scope chain),执行环境。从目前看见的资料来看,闭包的构成必须有这几个要素。
  • 作用
这个东西有什么作用呢,先看如下一个例子:
  1. var f, g;
  2. function foo() {
  3. var x = 0;
  4. f = function() { return ++x; };
  5. g = function() { return --x; };
  6. x = 1;
  7. print(f()); // "2"
  8. }
  9. foo();
  10. print(g()); // "1"
  11. print(f()); // "2"
  • 两个不同功能、相互独立的函数只能通过全局变量交换数据么(这里说语言本身提供的能力,而不是平台提供的能力)? 上面例子中两个函数都操作了变量x,但x并不是全局变量,但对于其他函数也是不可见的。可见第一个作用是提供另一种手段来供两段程序交换数据,同时保护变 量安全
  • 两个闭包建立之后,只需要根据两个引用就可以调用了,这两个引用相互独立,但又是完全自包含的,——这显然是函数式编程的风格了

2007年12月25日星期二

Firefox 3上如何添加 del.icio.us 书签

以前我为了几台机器、几个操作系统上书签的同步烦心不已,即使安装了Foxmarks同步器还得留神用哪个覆盖哪个,而Google工具栏提供的书签功能也不太好用。后来开始使用del.icio.us的书签服务,加上del.icio.us Bookmarks扩展,终于很满意了。

Firefox 3出来了beta 1之后,我就基本上开始用新版本了,毕竟很多功能很不错,内存占用比原来少了(也许是目前安装的扩展还比较少),再说反正以后要切的。不过目前还是两个版本都用。

但目前很多扩展都还不支持Firefox 3(而且Firefox 3开始要求对扩展进行签名了,不能象以前那样简单地下载xpi包后自己来改改版本匹配申明就说不定可以使用),有些扩展倒也罢了,但现在del.icio.us 似乎变成必须了 :-)

查看/搜索书签的功能倒简单,只要访问 http://del.icio.us/home 就可以了,网页上也有输入tag进行搜索的功能。

主要的问题是没法方便地添加书签了,以前只要在网上逛,看到不错的地方,按一下Ctrl+D或者点击工具栏的TAG按钮,就有一个对话框出来,当前网页的标题、其他人的tag都显示出来了,并且当前网页选中的文字还可以自动放入书签的说明栏。
del.icio.us

在del.icio.us的帮助中找了一下,发现可以用如下办法: 在书签栏上添加一个书签,其URL是:
javascript:location.href='http://del.icio.us/post?v=4;url='+encodeURIComponent(location.href)+';title='+encodeURIComponent(document.title)
(可以拖这个链接到书签栏,然后自己改名字)

详细的说明在这里: bookmarklet buttons for any browser

但“当前网页选中的文字还可以自动放入书签的说明栏”这一点还不能做到,不太爽。我试验了一下,发现多传一个notes参数就可以了: 在上述URL后面再添加一节:
+';notes='+encodeURIComponent(window.getSelection().toString())

结论: 拖下面这个链接到书签栏就可以了:
post to del.icio.us