在介绍完JavaScript1.6的新特性之后,W3C Group继续为大家介绍JavaScript1.7,JavaScript1.7带来了一系列的新特性,除了向下兼容javascript1.6之外,还包括生成器、迭代器、数组领悟、let 表达式,以及解构赋值等重要特性!浏览器支持:Firefox 2 Beta 1或以上版本如何使用JavaScript1.7如果你想使用Javascript1.7的新特性,你只需要在写Script标签的时候引入javascript1.7的版本号即可,如:<script type="application/javascript;version=1.7"/>注意:"yield" 和 "let"是javascript1.7中的两个新特性,请不要当作变量名或函数名使用!下面我们介绍一下javascript1.7给我们带来的这些新特性!生成器和迭代器每当开发那些涉及到迭代算法(如对列表的迭代或对同一数据集进行相同的演算)的代码时,通常都需要声明一些变量,并在整个计算过程中都保留它们的值。一般来说,你还需要使用一个回调函数来获得迭代算法的中间值。
生成器下面这个迭代算法计算了斐波那契数列:function do_callback(num) {
document.write(num + "<br>\n");
}function fib() {
var i = 0, j = 1, n = 0;
while (n < 10) {
do_callback(i);
var t = i;
i = j;
j += t;
n++;
}
}fib();这段代码使用了一个回调函数,来机械地执行算法每一步迭代的操作。这里,每一个斐波那契数都被简单地打印在控制台上。使用生成器和迭代器,可以提供一个更新更好的方法。现在就让我们来看看使用了生成器的斐波那契数列:function fib() {
var i = 0, j = 1;
while (true) {
yield i;
var t = i;
i = j;
j += t;
}
}var g = fib();
for (var i = 0; i < 10; i++) {
document.write(g.next() + "<br>\n");
}包含 yield 关键字的函数,就是一个生成器。当你调用它时,它的真正参数就会绑定到实际的变量上,但它自身其实并不做实际的计算,而是返回一个生成器-迭代器(generator-iterator)。每调用一次该生成器-迭代器的 next() 方法就再执行一次迭代算法。yield 关键字指定了每一步的值,就像生成器-迭代器版的 return 一样,指出了算法的每次迭代之间的边界。你每调用一次 next(),生成器代码就从 yield 以下的语句处恢复。你可以重复调用一个生成器-迭代器的 next() 方法来使它转动,直到到达你期望的结果条件。在这个例子中,我们只需不停地调用 g.next(),就可以获得任意多的斐波那契数,直到满足我们所需要的结果个数。
从指定位置恢复生成器-迭代器一个生成器在被调用其 next() 方法启动之后,你可以使用 send() 方法传递一个指定的的值,作为上一个 yield 的结果。这个生成器将返回后续 yield 的操作数。你无法强制生成器从某个位置启动,在你 send() 一个指定的值给生成器之前,你必须先以 next() 启动它。
注意: 有意思的是,调用 send(undefined) 与调用 next() 是等价的。不过,用任何除 undefined 之外的值调用 send() 启动一个刚刚创建的生成器将引发 TypeError 异常。
生成器的异常通过调用生成器的 throw() 方法并传递异常值,你可以强制生成器抛出异常。此异常将从该生成器当前挂起的上下文中被抛出,就好像在当前被挂起的 yield 中插入了一个 throw value 语句。如果在抛出异常的过程中没有遇到 yield,那么该异常将被通过调用 throw() 传播,且后续的 next() 调用将导致 StopIteration 异常抛出。
关闭生成器生成器的 close() 方法能强行关闭生成器自身。关闭生成器的效果如下:1. 运行这个生成器函数中活动的 finally 语句。
2. 一旦 finally 语句抛出任何除 StopIteration 之外的异常,该异常被传播给 close() 方法的调用者。
3. 该生成器终结。生成器示例这段代码执行了一个每 100 次循环 yield 一次的生成器。var gen = generator();function driveGenerator() {
if (gen.next()) {
window.setTimeout(driveGenerator, 0);
} else {
gen.close();
}
}function generator() {
while (i < something) {
/** 工作 **/++i;
/** 100 循环 yield 一次 **/
if ((i % 100) == 0) {
yield true;
}
}yield false;
}迭代器迭代器可以让你迭代数据,是一种特殊的对象。在常规的用法中,迭代器对象是“不可见”的,你不需要显示地操作它们。取而代之,使用 JavaScript 的 for...in 和 for each...in 语句 自然地在对象的键、值之上循环。var objectWithIterator = getObjectSomehow();for (var i in objectWithIterator)
{
document.write(objectWithIterator[i] + "<br>\n");
}如果你想实现你自己的迭代器对象,或对直接操作迭代器有另外的需求,你就需要了解 next 方法、StopIteration 异常和 __iterator__ 方法了。你可以通过调用 Iterator(对象名) 来为一个对象创建迭代器。调用一个对象的 __iterator__ 方法时,需要查找它的迭代器;当这个方法不存在时,创建一个默认的迭代器。默认迭代器会根据传统的 for...in 和 for each...in 模型产出该对象的属性。也可以提供一个自定义的迭代器,只需重载 __iterator__ 方法,使它返回你自定义的迭代器的一个实例即可。你可以使用 Iterator(对象) 从脚本中获取一个对象的迭代器,以避免直接访问 __iterator__ 的属性,因为只有前者才对数组起作用。一旦你拥有了一个迭代器,你就能够轻松地获取对象中的下一项了,调用该迭代器的 next() 方法即可。对象中没有余下的数据时,抛出 StopIteration 异常。这里有一个直接迭代器操作的简单示例:var obj = {name:"Jack Bauer", username:"JackB", id:12345, agency:"CTU", region:"Los Angeles"};var it = Iterator(obj);try {
while (true) {
print(it.next() + "\n");
}
} catch (err if err instanceof StopIteration) {
print("End of record.\n");
} catch (err) {
print("Unknown error: " + err.description + "\n");
}该程序的输出如下:name,Jack Bauer
username,JackB
id,12345
agency,CTU
region,Los Angeles
End of record.你可以有选择性地指定创建迭代器的第二个参数,它是一个指示你调用其 next() 方法时是否需要返回 keys 的布尔值。这个参数被作为第一个参数传入给用户定义的 __iterator__ 函数。在上面的例子中,把 var it = Iterator(obj); 改为 var it = Iterator(obj, true); 后的输出如下:name
username
id
agency
region
End of record.对于每一种情况,返回数据的实际顺序只基于实现,数据的顺序是不能保证的。迭代器是一种扫描对象中的数据的简便的方式。被扫描的对象的内容中可能包含你没有注意到的数据,所以当你需要保护那些你的应用程序并不期望的数据时,迭代器会显得非常有用。

解决方案 »

  1.   

    数组领悟数组领悟是一种对生成器的运用,展示了一种初始化数组的强大而方便的方式。例如:function range(begin, end) {
    for (let i = begin; i < end; ++i) {
    yield i;
    }
    }range() 是一个返回从 begin 到 end 之间值的生成器。知道了这些,我们就可以这样使用它:var ten_squares = [i * i for each (i in range(0, 10))];这段代码预初始化了一个新数组 ten_squares,包含了范围在 0..9 之间的值的平方数。在初始化数字时你可以使用任何限制条件。如果你想要初始化一个包含 0 到 20 之间偶数的数组,你可以使用下面的代码:var evens = [i for each (i in range(0, 21)) if (i % 2 == 0)];在 JavaScript 1.7 之前,这个工作必须要写出类似这样的代码:var evens = [];
    for (var i=0; i <= 20; i++) {
    if (i % 2 == 0)
    evens.push(i);
    }一旦你熟悉了数组领悟,你就会发现它不但紧凑,而且易于阅读。作用域规则数组领悟被暗含的块包围着,包含了方括号内所有的东西,类似隐含的 let 声明。更多细节。
    let 的块作用域有好几种使用 let 来管理数据和函数的块作用域的方式:* let 语句 提供了一种在块作用域中联系值与变量、常量、函数的途径,且不会影响到块之外的同名变量。
    * let 表达式 使你能在仅有一个表达式所限定的作用域内建立变量。
    * let 定义 在一个块中,定义变量、常量和函数,并把它们的作用域限制在块内。从语法上看,let 定义 很类似 var。
    * 你也可以使用 let 建立只存在于 for 循环上下文中的变量。let 语句let 语句为变量、常量和函数提供了本地作用域,其工作是把零个或多个变量绑定到单个代码块的词法作用域上,这个过程与块语句完全相同。特别要注意的是,在 let 语句内部使用 var 声明的变量,其作用域和它在 let 语句外被声明时相同,这样的变量仍然具有函数作用域。例如:var x = 5;
    var y = 0;let (x = x+10, y = 12) {
    print(x+y + "\n");
    }print((x + y) + "\n");这段程序的输出是:27
    5此规则对任何 JavaScript 中的代码块适用。使用 let 声明,可以给代码块建立属于它自己的本地变量。
    注意: 使用 let 语句这个语法时,跟在 let 后面的括号是必需的,丢掉它们将导致一个语法错误。
    作用域规则用 let 定义的变量的作用域是 let 块本身,覆盖了任何 let 块内部的块,除非这些内部块定义了同名的变量。
    let 表达式你可以使用 let 建立作用域仅在一个表达式中的变量。var x = 5;
    var y = 0;
    document.write( let(x = x + 10, y = 12) x+y + "<br>\n");
    document.write(x+y + "<br>\n");输出如下:27
    5在这个例子中,对 x 的值 x+10 的绑定和对 y 的值 12 的绑定的作用域被限制于表达式 x+y。作用域规则let 表达式:let (声明) 表达式在 表达式 周围创建了一个隐含的块。
    let 定义let 关键字也可被用于在块中定义变量、常量和函数。if (x > y)
    {
    let gamma = 12.7 + y;
    i = gamma * x;
    }使用内部函数时,let 语句,let 表达式和 let 定义常常能使代码更加清晰。var list = document.getElementById("list");
    for (var i = 1; i <= 5; i++)
    {
    var item = document.createElement("LI");
    item.appendChild(document.createTextNode("Item " + i));
    let j = i;
    item.onclick = function (ev) {
    alert("Item " + j + " is clicked.");
    };
    list.appendChild(item);
    }上面的例子能像我们所期望的那样工作,因为五个匿名函数的实例引用了变量 j 的不同实例。请注意,如果你把 let 换成 var,或者移除变量 j 并仅在内部函数中使用变量 i,这段代码就不能正常工作了。
    作用域规则用 let 定义的变量的作用域覆盖了它们被定义的块,已经任何没有重定义它们的子块。从这一点来看,let 的效果非常类似 var。主要的区别在于用 var 定义的变量的作用域是整个闭合函数:function varTest() {
    var x = 31;
    if (true) {
    var x = 71; // 同一个变量!
    alert(x); // 71
    }
    alert(x); // 71
    }function letTest() {
    let x = 31;
    if (true) {
    let x = 71; // 不是同一个变量
    alert(x); // 71
    }
    alert(x); // 31
    }= 右侧的表达式处于块的内部。这与 let-表达式和 let-语句的作用域不同:function letTests() {
    let x = 10;// let-语句
    let (x = x + 20) {
    alert(x); // 30
    }// let-表达式
    alert(let (x = x + 20) x); // 30// let-定义
    {
    let x = x + 20; // 这里的 x 的求值结果为 undefined
    alert(x); // undefined + 20 ==> NaN
    }
    }在程序和类中,let 不创建 global 对象上的属性,这与 var 的做法不同。但 let 会在一个隐含的块中创建属性,使其它上下文中的语句可以被求值。这就意味着,let 不会覆写前面用 var 定义的变量。例如:var x = 'global';
    let x = 42;
    document.write(this.x + "<br>\n");这段代码将输出 "global" 而不是 "42"。隐含的块指的不是那种被括弧括起的块,它只由 JavaScript 引擎隐式创建。由 eval() 执行的 let 与 var 不同,它不会在变量对象(活动对象或在最内层绑定的组成部分)上创建属性。为使其它上下文中的语句可以被求值,它会在一个隐含的块中创建属性,这是 eval() 对于程序的操作与前述规则共同作用的结果。换句话说,当你使用 eval() 执行代码时,这段代码就被当作一段独立程序处理,拥有自己的包围其代码的隐含的块。
    for 循环中的 let-界定变量你可以使用 let 关键字在 for 循环的作用域内绑定本地变量,和使用 var 类似。** 添加对象 **
    var i=0;
    for ( let i=i ; i < 10 ; i++ )
    document.write(i + "<br>\n");for ( let [name,value] in obj )
    document.write("Name: " + name + ", Value: " + value + "<br>\n");作用域规则for (let 表达式1; 表达式2; 表达式3) 语句在这个例子中,表达式1,表达式2,表达式3和语句都被闭合在一个隐含的块中,其中包含了用 let expr1 声明的本地变量。上面例子中的第一个循环示范了这个用法。for (let 表达式1 in 表达式2) 语句
    for each(let 表达式1 in 表达式2) 语句在这两个例子中,都存在包含了每个 statement 的隐含的块。上面例子中的第二个循环展示了这里的第一种用法。
    解构赋值解构赋值使用了一种反映数组常量和对象常量结构的语法,使得从数组或对象中抽取数据成为可能。通过使用对象常量和数组常量表达式,你可以轻松地按需创建成包的数据,然后以任意你想要的方式使用它们。你甚至可以从函数中返回它们。而你使用解构赋值最重要的一件事就是,你可以从一个语句中读取整个结构。在这一节的余下的部分中会给出很多例子,你将看到你可以使用的很多有趣的功能。解构赋值这种能力与 Perl,Python 等语言所显示出的特性很类似。
    示例用例子就可以很好地诠释解构赋值,所以这里几乎没有什么需要你通过阅读来学习的内容。
     避免临时变量你可以用解构赋值来交换两个变量的值。例如:var a = 1;
    var b = 3;[a, b] = [b, a];这段代码执行之后,b 为 1,a 为 3。不使用解构赋值的话,这个工作就需要一个临时变量。(当然了,在某些低级语言中,可以使用 XOR-交换技巧)与此类似,解构赋值也可以被用于三个或更多变量之间的轮换:var a = 'o';
    var b = "<span style='color:green;'>o</span>";
    var c = 'o';
    var d = 'o';
    var e = 'o';
    var f = "<span style='color:blue;'>o</span>";
    var g = 'o';
    var h = 'o';for (lp=0;lp<40;lp++)
    {[a, b, c, d, e, f, g, h] = [b, c, d, e, f, g, h, a];
    document.write(a+''+b+''+c+''+d+''+e+''+f+''+g+''+h+''+"<br />");}这段代码执行之后,将显示一个可视化的、彩色的变量轮换过程。回到我们上文中的菲波那契数生成器的例子,我们可以使用一个成组赋值语句来计算 "i" 和 "j" 的新值,从而消除临时变量 "t"。function fib() {
    var i = 0, j = 1;
    while (true) {
    yield i;
    [i, j] = [j, i + j];
    }
    }var g = fib();
    for (let i = 0; i < 10; i++)
    print(g.next());
      

  2.   

    多值返回有了解构赋值之后,函数就可以返回多个值了。虽然在以前也可以从函数中返回数组,但解构赋值为此增加了极大的便利。function f() {
    return [1, 2];
    }正如你所看到的,用方括号括住所有要返回的值,使它们看上去像是数组,这就是多值返回。在上面的例子中,f() 返回 [1, 2] 作为其输出。var a, b;
    [a, b] = f();
    document.write ("A is " + a + " B is " + b + "<br>\n");命令 [a, b] = f() 使用函数结果给方括号中的变量依次赋值。a 被设为 1,b 被设为 2。你也可以把这些返回值恢复成一个数组:var a = f();
    document.write ("A is " + a);在这个例子中,a 是一个包含值 1 和 2 的数组。
    在对象中循环你也可以使用解构赋值把数据从对象中倾倒出来:let obj = { width: 3, length: 1.5, color: "orange" };for (let [name, value] in Iterator(obj)) {
    document.write ("Name: " + name + ", Value: " + value + "<br>\n");
    }这段代码循环了对象 obj 中的所有键值对,并显示出它们的名字和值。这个例子的输出如下:Name: width, Value: 3
    Name: length, Value: 1.5
    Name: color, Value: orange在 JavaScript 1.7 中,obj 周围的 Iterator() 不是必须的,不过 JavaScript 1.8 就需要了,这样可以允许对数组的解构赋值(见 bug 366941)。
    在对象组成的数组中循环你可以循环一个由对象组成的数组,并倾倒出每个对象中你感兴趣的域。var people = [
    {
    name: "Mike Smith",
    family: {
    mother: "Jane Smith",
    father: "Harry Smith",
    sister: "Samantha Smith"
    },
    age: 35
    },
    {
    name: "Tom Jones",
    family: {
    mother: "Norah Jones",
    father: "Richard Jones",
    brother: "Howard Jones"
    },
    age: 25
    }
    ];for each (let {name: n, family: { father: f } } in people) {
    document.write ("Name: " + n + ", Father: " + f + "<br>\n");
    }这段代码用 name 域给 n 赋值,用 family.father 域给 f 赋值,然后打印它们。这个过程被作用于 people 数组中的每一个对象。输出如下:Name: Mike Smith, Father: Harry Smith
    Name: Tom Jones, Father: Richard Jones忽略某些返回值你也可以忽略掉那些你不感兴趣的返回值:function f() {
    return [1, 2, 3];
    }var [a, , b] = f();
    document.write ("A is " + a + " B is " + b + "<br>\n");这段代码运行之后,a 为 1,b 为 3,2 这个值被忽略了。你也可以用这种方式忽略多个,甚至是全部返回值。例如:[,,,] = f();从正则表达式匹配结果中倾倒值当正则表达式的 exec() 方法找到一个匹配时,它会返回一个数组,第一项是目标字符串中被匹配的完整部分,后面是被正则表达式中被括号括起的组所匹配的数段字符串。解构赋值使你能轻松地倾倒出该数组中的各个部分,并忽略掉其中不需要的匹配。// 一个简单的正则表达式,用来匹配 http / https / ftp 型的 URL
    var parsedURL = /^(\w+)\:\/\/([^\/]+)\/(.*)$/.exec(url);
    if (!parsedURL)
    return null;
    var [, protocol, fullhost, fullpath] = parsedURL;貌似JavaScript1.7的新特性来的更多更猛,接下来,w3c group将为大家介绍javascript1.8的一些新特性!
      

  3.   

    好长啊,楼主要是别的浏览器不支持,这个JavaScript1.7 有什么用呢?
      

  4.   

    是啊,现在我的N多客户还在用IE 5.5/6 。这个东西只是未来趋势,估计2年后才会慢慢被使用。
      

  5.   

    w3c规范按照现在IE6,占有绝大多市场份额的情况下,,貌似很难啊 
    2年之后能慢慢被使用吗?
    还是未知数。。
      

  6.   

    好长啊,楼主 要是别的浏览器不支持,这个JavaScript1.7 有什么用呢?
      

  7.   

    好长啊,楼主要是别的浏览器不支持,这个JavaScript1.7 有什么用呢?