JavaScript 1.8

JavaScript 1.8 是 Gecko 1.9(已合并在 Firefox 3 中)的一部分。比起 JavaScript 1.7,这只是很小的更新,不过它也确实包含了一些向 ECMAScript 4/JavaScript 2 升级的痕迹。JavaScript 1.8 还将包含 JavaScript 1.6JavaScript 1.7 中的所有新特性。


1. 使用 JavaScript 1.8


为了可以在 HTML 中使用 JavaScript 1.8 的新特性,需要这样写:


<script type=”application/javascript;version=1.8”> … 你的代码 … </script>

在使用 JavaScript shell 、JavaScript XPCOM 组件,或者 XUL <script> 元素的时候,自动启用最新的JS版本(Mozilla 1.9中的 JS1.8)。


另一种方法(不推荐)是使用旧式的 <script> 属性 language,把它定义为 “JavaScript1.8”。


如果需要使用新的关键字 “yield” 和 “let”,你需要指定是1.7版本或者更高的版本,因为现有的代码可能会把这两个关键字用作变量名或者函数名。如果没有使用任何新的关键字,就可以不指定 JavaScript 的版本。


好高级,可是其它浏览器不行啊  (┬_┬)




2. 表达式闭包


这个新添加的特性其实就是简单函数的方便写法,使得这个语言更加类似典型的 Lambda notation.
JavaScript 1.7 以及更老的版本:


function(x) { return x  x; }

JavaScript 1.8:


function(x) x  x

这个语法允许你省略花括号和 ‘return’ 语句--使它们成为隐式的。用这种方法写,只是表面上看起来短了一些,并没有其他好处。


示例:


绑定事件处理器的简单写法:


document.addEventListener(“click”, function() false, true);

把这个定义与 JavaScript 1.6 中的数组函数一起使用:


elems.some(function(elem) elem.type == “text”);



第一感觉,不太可读,即使只有一行,我也会用个括号括起来的。


3. 生成器表达式


这个新添加的特性,允许你简单的创建生成器(在 JavaScript 1.7 中引入)。通常你需要创建一个自定义的函数,它含有一个 yield,但这个新特性使你可以使用类似数组领悟的语法来创建一个独立的生成器句柄。


JavaScript 1.7 中,你可能需要写出像下面这样的代码来为一个对象创建自定义的生成器:


 function add3(obj) {
for ( let i in obj )
yield i + 3;
}

let it = add3(someObj);
try {
while (true) {
document.write(it.next() + “<br>\n”);
}
} catch (err if err instanceof StopIteration) {
document.write(“End of record.<br>\n”);
}

在 JavaScript 1.8 中,你可以规避要创建生成器函数的麻烦,而使用一个生成器表达式来代替:


 let it = (i + 3 for (i in someObj));
try {
while (true) {
document.write(it.next() + “<br>\n”);
}
} catch (err if err instanceof StopIteration) {
document.write(“End of record.<br>\n”);
}

生成器表达式也可以被作为值传给一个函数。特别要注意的是,生成器在绝对要用到的时候才运行(与典型的数组领悟的场景不同,不事先构造数组)。这个区别可以从下面的例子中看出:


使用 JavaScript 1.7 数组领悟


 handleResults([ i for ( i in obj ) if ( i > 3 ) ]);

function handleResults( results ) {
for ( let i in results )
// …
}

使用 JavaScript 1.8 的生成器表达式


 handleResults( i for ( i in obj ) if ( i > 3 ) );

function handleResults( results ) {
for ( let i in results )
// …
}

这两个例子之间最大的区别就是,使用生成器表达式的时候,一共只循环 ‘obj’ 结构一次;而在第一个例子中,领悟这个数组时要循环一次,遍例的时候又循环一次。


有点小复杂,需要结合 JavaScript 1.7 中的 let 和 Array comprehensions




4. 更多数组特性


JavaScript 1.8 中包含了两个新的数组遍例方法,分别是:



4.1 reduce() : 对该数组的每项和前一次调用的结果运行一个函数,收集最后的结果。




语法:array.reduce(callback[, initialValue])

参数:

       callback      为每个元素执行的函数,有以下四个参数:

                        previousValue:  上一个回调函数返回的值或者初始值 initialValue. (参见下文)

                        currentValue: 当前元素的值

                        index: 当前元素位置。有初始值 initialValue 时从0开始,否则从1开始。

                        array: 当前数组

       initialValue  第一次调用函数中的第一个参数值


兼容性:于 ECMAScript 5 标准中添加,部分浏览器可能会不支持。您可以添加以下代码来进行支持。


if ( !Array.prototype.reduce ) {
Array.prototype.reduce = function reduce(accumulator){
var i, l = this.length, curr;

if(typeof accumulator !== “function”) // ES5 : “If IsCallable(callbackfn) is false, throw a TypeError exception.”
throw new TypeError(“First argument is not callable”);

if((l == 0 || l === null) && (arguments.length <= 1))// == on purpose to test 0 and false.
throw new TypeError(“Array length is 0 and no second argument”);

if(arguments.length <= 1){
curr = this[0]; // Increase i to start searching the secondly defined element in the array
i = 1; // start accumulating at the second element
}
else{
curr = arguments[1];
}

for(i = i || 0 ; i < l ; ++i){
if(i in this)
curr = accumulator.call(undefined, curr, this[i], i, this);
}

return curr;
};
}





4.2 reduceRight() : 同上,但从右向左执行。



语法:array.reduceRight(callback[, initialValue])

参数:

       callback      为每个元素执行的函数,有以下四个参数:

                        previousValue:  上一个回调函数返回的值或者初始值 initialValue. (参见下文)

                        currentValue: 当前元素的值

                        index: 当前元素位置。有初始值 initialValue 时从0开始,否则从1开始。

                        array: 当前数组

       initialValue  第一次调用函数中的第一个参数值


兼容性:于 ECMA-262 标准中添加,部分浏览器可能会不支持。您可以添加以下代码来进行支持。


    if (!Array.prototype.reduceRight)  {
Array.prototype.reduceRight = function(callbackfn /, initialValue /) {
“use strict”;

if (this === void 0 || this === null)
throw new TypeError();

var t = Object(this);
var len = t.length >>> 0;
if (typeof callbackfn !== “function”)
throw new TypeError();

// no value to return if no initial value, empty array
if (len === 0 && arguments.length === 1)
throw new TypeError();

var k = len - 1;
var accumulator;
if (arguments.length >= 2) {
accumulator = arguments[1];
}
else {
do {
if (k in this) {
accumulator = this[k–];
break;
}

// if array contains no values, no initial value to return
if (–k < 0)
throw new TypeError();
}
while (true);
}

while (k >= 0) {
if (k in t)
accumulator = callbackfn.call(undefined, accumulator, t[k], k, t);
k–;
}

return accumulator;
};
}