这篇文章发布于 2011年02月18日,星期五,22:24,归类于 外文翻译。 阅读 50607 次, 今日 5 次 3 条评论
by zhangxinxu from http://www.zhangxinxu.com
本文地址:http://www.zhangxinxu.com/wordpress/?p=1448
以下为翻译全文,有编辑
最近我在Firebug控制台上折腾一些东西的时候记住了表达式闭包(expression closures)。这是个附加的语言,在Mozilla的JavaScript 1.8中引入。
MDC抓住了表达式闭包(expression closures)的本质,并对其进行了简明的解释://zxx:我琢磨着,这个MDC应该是Mozilla Develope Center,Mozilla开发中心。
该添加只不过可以让简单的函数速写,让语言类似的一个典型的λ符号。[…]该语法允许你不要花括号({})以及”return”声明——使其更隐式。这种代码书写形式除了语法构成上讲短了外没有其他的好处。
正好,这是我需要的——迅速地尝试一些东西,缩短的函数表达式以节约打字时间。
MDC同时给了个例子,展示如何使用表达式闭包写函数:
// 正常的语法 function() { return x * x } // 表达式闭包 function(x) x * x
正如你所见,表达式闭包骨子里就是个创建更简单函数的方式。根据MDC,表达式闭包允许我们把函数体中的花括号啊以及”return”啊什么的如擦屁股纸般扔掉。
然而,MDC提供的关于表达式闭包的信息比王之涣流传下来的诗还少,于是我就好奇表达式闭包的其他一些出色的细节。它们是不是只能用来创建函数表达式?函数声明怎么样?已命名函数表达式又如何?是否function() ...
总是和function(){return ...}
一样,而与 ...
(函数体)无关?MDC所谈到的“简单函数”到底指什么?
上面的问题一个也没有答案,所以我决定做个快速的研究,给这个时髦的语言加点深度。下面的就是我的发现;你会发现某些行为不是那么明显。
让代码自己说话,这里是一个简单的测试之后问题清单,试图回答这些问题。下面的简短叙述的发现你可以随意跳过。
测试(Test)
-
是否表达式闭包可以用来创建函数声明(而不仅仅是函数表达式)?
答案是:是的。
function f(x, y) x + y typeof f; // "function"
上面的测试代码,正常的声明应该是:
typeof(f);
,而现在就是typeof f
,测试结果显示是支持的。您可以狠狠地点击这里:表达式闭包与函数声明测试demo
点击demo页面中的“点击我弹出结果”按钮查看效果,在firefox浏览器中可以看到如下的弹出框:
因为表达式闭包是mozilla的东西,所以目前在诸如IE/Chrome浏览器下是没有效果的。火狐浏览器下直接下面代码就有效果了:
<script> function f(x, y) x + y alert(typeof f); </script>
但是如果就上面光秃秃的代码的话,其他浏览器下会是报错的,为了友好其他浏览器,可以给javascript代码添加版本说明,就在type属性中,代码如下:
<script type="application/javascript;version=1.8"> function f(x, y) x + y alert(typeof f); </script>
-
已命名函数表达式又如何?
结果是:支持。
typeof (function f(x, y) x + y); // "function"
您可以狠狠地点击这里:表达式闭包与已命名函数表达式测试demo
效果以及注意事项与上面一致。
-
表达式闭包如何影响函数表示?
就跟平常一样,就是不包含花括号以及”return”关键字。
String(function (x) x + x ); // "function (x) x + x;"
您可以狠狠地点击这里:表达式闭包与函数表示测试demo
在FireFox浏览器下点击页面上的按钮后的效果如下:
-
关于非标准的”name”属性?
结果:如预期工作!
function foo(x, y) x + y; foo.name; // "foo"
您可以狠狠地点击这里:表达式闭包与非标准name属性测试demo
结果如下图:
-
即时应用函数表达式怎么样?
结果是:工作良好。
(function(x, y) x + y)(1, 2); // 3
您可以狠狠地点击这里:表达式闭包与即时应用函数表达式测试demo
结果如下图:
-
没有括号包裹的即时应用函数表达式?
结果:啊哦,有点小疙瘩
var f1 = (function(x, y) x + y)(1, 2); var f2 = function(x, y) x + y (1, 2); f1; // 3 f2; // function(x, y) x + y(1, 2)
正如你所看到的,
x + y
之后的(1, 2)
实际上被当做内部的表达式了,而不是应用在外部函数上。x + y(1, 2)
当做一个整体当做f2
的返回值了。这是明确可以知道的。如果您手头上的正是Firefox浏览器,您可以狠狠地点击这里:表达式闭包与无括号包裹的即时应用函数表达式demo
-
表达式闭包在ECMAScript 5访问语法下是否起作用(先试试get方法)?
结果是:起作用滴。
var obj = ({ get foo() 1 }); obj.foo; // 1
您可以狠狠地点击这里:表达式闭包与ES5访问语法测试demo
结果如下图:
如果您看到下面的文字,可能是由于在其他网站或是RSS中阅读本文,本文原地址:http://www.zhangxinxu.com/wordpress/?p=1448,本文作者:张鑫旭,来自张鑫旭-鑫空间-鑫生活,访问原出处更多优秀技术文章。 -
那么set方法呢?
答案是:同样可以。
var _x; var obj = ({ set foo(x) _x = x }); obj.foo = 5; _x; // 5
您可以狠狠地点击这里:表达式闭包与ES5 set语法测试demo
结果点击demo页面的测试按钮,在我的火狐浏览器下弹出结果是”
5
“。 -
要是双管齐下呢?
结果:都ok!恩,没理由不ok啊~~
var _x = '初始值'; var obj = ({ get foo() _x, set foo(x) _x = x }); obj.foo; // '初始值' obj.foo = '重置值'; obj.foo; // '重置值'
您可以狠狠地点击这里:表达式闭包与ES5 set/get双管齐下测试demo
点击测试按钮后,连续弹出下图所示两弹框:
-
我们可以用逗号混淆分析器?
答案是:是的。
({ set foo(x) bar = 1, baz = 2 }); // 解析错误
在这个例子中,我们可能希望
bar = 1, baz = 2
作为函数内部的一个表达式,然而,逗号被解释成了对象初始化的一部分。当然,包裹一副括号可以解决字问题。({ set foo(x) (bar = 1, baz = 2) });
-
语句是否允许存在于通过表达式闭包创建函数的函数体中?
答案是:No!
var f = function() if (true) "foo"; // 错误
这个相当容易理解。表达式闭包中,
function()
后面跟着的表达式直接被当做要被return
语句后面的东西给return掉了。显然,return
语句是不能返回其他语句的,就是说return if (true) "foo";
是行不通的。不过幸运的是,有个叫做三元运算的东西可以好好安抚这里的小错误:var f = function() someCondition ? "foo" : "bar";
-
通过表达式闭包创建的函数体是否可以忽略?
(*^__^*) 嘻嘻……,答案是:门都没有!
function f() // 错误
你可能会想啊,这
function f()
应该等同于function f(){ return }
。但是,不是滴,这里空函数体时不允许的。至于为什么会这样还不是很清楚。解析复杂,错乱如麻?或许吧。 -
如果不止一个表达式会怎样呢?
结果是:只有第一个被当做柴油来烧。
function f() alert("第一个语句"); alert("第二个语句"); alert("第三个语句"); // 弹出 "第二个语句"和"第三个语句"
上面的语句被解析成了:
function f() { return alert("第一个语句"); } alert("第二个语句"); alert("第三个语句");
只有第一个表达式作为了表达式闭包的燃料使用了。
您可以狠狠地点击这里:表达式闭包与多表达式测试demo
-
分号自动插入规则怎么样呢?
答案是:规则一致。
function foo(x) x (function() { /* ... */ })() foo; // function foo(x) x(function(){ /* ... */})()
这是个经典的分号自动插入实例——函数声明在新的一行同时在表达式的后面出现的奇怪表现。这里规则一致,
foo
函数(即使是表达式闭包)也以函数体x(function(){})()
而不是x
结束。您可以狠狠地点击这里:表达式闭包与分号自动插入规则测试demo
结果如下图:
-
“{“是当做声明块还是对象字面量?
结果是:语句块。整体生产基本上符合常规的函数语法。
function foo(x) { top: 0, left: 0 } // 语法错误
你可能会想,
function foo(x) { top: 0, left: 0 }
应该被解析成function foo(x) { return { top: 0, left: 0 } }
,但是这里“正常”解析规则先执行,而function foo(x) { top: 0, left: 0 }
回导致错误,花括号{
和}
被解析成了函数体,而top: 0, left: 0
被当做函数体里面的内容了。 -
如果是个表达式呢?
结果与上面一样。
(function(x, y) { left: x, top: y }) // 语法错误
你必须小心地用括号包裹返回的对象,为的是花括号不会被认为是函数生成的一部分。在本例中,
left: x, top: y
导致了个错误。但是,如果返回的对象只包含一个值,或者甚至没有值,则会有类似下面的意想不到的行为表现:(function() { x: 1 } )(); // 返回 "undefined" (function() ({ x: 1 }) )(); // 表达式闭包; 返回带有x=1的对象 (function() {} )(); // 返回 "undefined" (function() ({}) )(); // 表达式闭包; returns 对象
-
是否可以让函数明确严格?
答案是:不行的!
function foo(x, y) "use strict"; 1 + 1; typeof foo(); // "string" (而不是 "number")
显然没起作用。本想使用严格指令(use strict)让函数行为表现得跟ECMAScript 5中的严格模式规则一样,然而没有任何特殊的表现。”use strict”被直接当做了字符串字面量。于是,上面的代码就直接被解析成了
function foo(){ return "use strict"; }
,然后后面就是无止尽的1 + 1
语句。您可以狠狠地点击这里:表达式闭包与严格模式测试demo
结果如下截图(截自 FireFox 3.6):
原作者也提供了上面小例子的一系列测试结果,您可以点击这里查看。
主要特征
恩,真是有意思。现在总结下一些主要特征:
- 函数体需一直存在
- 只有第一个表达式会被当做return语句
- 函数声明和函数表达式(显示命名还是匿名的)都可以用来被替换
function idopt (argsopt) expr
不完全等于function idopt (argsopt) { return expr }
(依赖于上下文)- 优先应用的表达式不明显。例如:
(function()x+y)()
vs.function()x+y()
。
实践?
据我所知,目前仅基于Mozilla的浏览器支持表达式闭包,其也不被诸如Google Closure Compiler或是YUI Compressor这样的工具支持,这些势必增加了其在实际项目应用中的挑战。
目前还不清楚是否有更多的工具会加入mozilla,添加对这种简写的支持。是否其可以作为和谐之路(road to Harmony)实验的一部分(以及其函数缩写语法)——下一个ECMAScript语言版本?你是否已经在你的工作/实验中使用表达式闭包,或者可能计划使用?你会改变他们的行为吗?
以上为翻译全文
大结局
虽然目前而言,表达式闭包在实际中应用不太现实。但是,本文对于拓展眼界,开阔思路还是很有帮助的。技术总在不停的发展,谁知道明天又会出来什么东西呢?
时间仓促,翻译能力有限。如果翻译不准确的地方,欢迎指正,不甚感谢。//zxx:独自饿扁啦,饭饭饭~~
本文为原创文章,转载请注明来自张鑫旭-鑫空间-鑫生活[http://www.zhangxinxu.com]
本文地址:http://www.zhangxinxu.com/wordpress/?p=1448
(本篇完)
- 翻译-你必须知道的28个HTML5特征、窍门和技术 (0.855)
- CSS content内容生成技术以及应用 (0.772)
- 翻译 - 解释JavaScript的“预解析(置顶解析)” (0.228)
- 翻译-IE7/8@font-face嵌入字体与文字平滑 (0.197)
- HTML5终极备忘大全(图片版+文字版) (0.197)
- Ajax Upload多文件上传插件翻译及中文演示 (0.175)
- jQuery照片图像剪裁插件Jcrop中文翻译详解 (0.175)
- 回流与重绘:CSS性能让JavaScript变慢? (0.175)
- jQuery Pagination Ajax分页插件中文详解 (0.175)
- 翻译-高质量JavaScript代码书写基本要点 (0.175)
- 原来DOM还有toggleAttribute这样的JS API (RANDOM - 0.030)
ie不支持 那就没有什么用啊 除非全国人民用FF了
有点看不懂啦!
这个语法的改进不错,能让javascript更加简洁。