常量
声明常量需要使用关键字const,const关键爵var关键字行为非常类似,但const声明的是常量。
对常量重新赋值会失败,而对常量重新声明会报错。
const pi = 3.14;
pi = 4; // 失败的赋值
const pi = 4; // 报错
var pi = 4; // 报错
局部变量
我们常常用var关键字来声明局部变量,但是var关键字缺少块作用域,后来就添加了let关键字。
let关键字有4四种使用方式:
作为变量声明
function f(){
let total = 0;
for (let i = 0; i < 10; i++){
let b = i;
total += b;
}
// 在这里无法使用i和b
return total;
}
在语句块中使用
let x = 1, y = 2;
let (x = x + 1, y = x +2){
// 输出5
console.log(x+y);
}
// 输出3
console.log(x+y);
在表达式中使用
let x = 1, y = 2;
// 输出5
console.log(let (x = x + 1, y = x + 2) x + y);
在解构赋值中,等号右侧是一个数组或对象,指定左侧一个或多个变量的语法和右侧数组和对象直接量的语法保持一致。
// 等价于let x=1,y=2;
let [x,y] = [1,2];
let transparent = {r:0.0,g:0.0,b:0.0,a:1.0};
// red = 0.0, green = 0.0, blue = 0.0
let {r:red,g:green,b:blue} = transparent;
for/each循环
和for/in循环类似但不同之处是循环变量的值。for/in循环对象时,循环变量为属性名。for/each循环对象时,循环变量的属性为属性值。
let o = {one:1,two:2,three:3};
for (let e in o)
// 输出 'one' 'two' 'three'
console.log(e);
for each(let e in o)
// 输出 1-3
console.log(e);
a = ['one', 'two', 'three'];
for (let e in a)
// 输出索引 0,1,2
console.log(p);
for each(let e in a)
// 输出值 'one','two','three'
console.log(p);
注意:for/each循环不仅仅针对数组本身的元素进行遍历,它也会遍历数组中所有可枚举的值,包括数组继承来的可枚举的方法。
迭代器
for/in循环可以遍历可迭代的对象。
迭代器是一个对象,这个对象允许对它的值集合进行遍历,并保持任何必要的状态以便能够跟踪到当前遍历的“位置”。
迭代器必须包含一个next()方法,每次调用next()都返回集合中的下一个值。当遍历完所有的值并且没有多余的值可迭代时,再调用next()方法会抛出StopIteration。
function rangeIter(first, last){
let nextValue = Math.ceil(first);
return {
next:function(){
if (nextValue > last){
throw StopIteration;
}
return nextValue++;
}
}
}
let r = rangeIter(1,5);
while(true){
try{
console.log(r.next());
}catch(e){
if (e == StopIteration)
break;
else
throw e;
}
}
如果关键字in右侧的值是可迭代的,那么for/in循环会自动调用它的__iterator__()方法来获得一个迭代器对象。for/in循环会自己处理StopIteration异常,而且处理过程对开发者不可见。
funciton range(first,last){
get min(){return min;},
get max(){return max;},
__iterator__:function(){
let nextValue = Math.ceil(first);
return {
next:function(){
if (nextValue > last){
throw StopIteration;
}
return nextValue++;
}
}
}
iterator()函数
该函数的参数是一个可迭代的对象,那么它将返回这个对象的的__iterator__()反方法的调用结果。
还有个重要的目的,如果传入的对象或数组没有定义__iterator__()方法,它将返回这个而对象的一个可迭代的自定义迭代器,每次调用这个迭代器的next()方法都会返回其中包括两个值得一个数组,第一个数组元素是一个是属性名,第二个是属性的值。
它只对自有属性进行遍历而忽略继承的属性。如果传入第二个参数true,返回的迭代器只对属性名进行遍历。
任何使用关键字yield的函数都称为“生成器函”,生气才函数通过yield返回值。和函数不同的是不执行生成器函数体,而是返回一个生成器对象。
可以通过生成器对象的next()函数获取数据。
function range(min,max){
for (let i = Math.ceil(min); i < max; i++)
yield i;
}
for (let n in range(3,8))
// 输出数字3-8
console.log(n);
如果不在使用生成器,可以使用圣骑的close()方法来释放它。
每个生成器都有一个send()方法可以带一个参数,这个参数的值称为yield表达式的值。
还有个throw()方法,如果调用这个方法,yield表达式就会将参数作为一个异常抛出。
function couter(initial){
let nextValue = initial;
while (true){
try{
let increment = yield nextValue;
if (increment)
nextValue += increment;
else
nextValue++;
}catch(e){
if (e === "reset")
nextValue = initial;
else
throw e
}
}
}
let c = counter(10);
// 输出10
console.log(c.next());
// 输出12
console.log(c.send(2));
//输出10
console.log(c.throw("reset"));
数组推导
[expression for ( variable in object) if (condition)]
data = [2,3,4];
// 数组的结果[4,9,16]
square= [ x*x for each(x in data)];
生成器表达式
将数组推导中的方括号替换为圆括号,它就成了一个生成器表达式
function map(i,f){
for (let x in i)
yield f(x);
}
// 可以用生成器表达式就不必定义上述的函数了
let h = (f(x) for (x in i));
如果函数值计算一个表达式并返回它的值,关键字return和花括号可以省略。
let add = function(a,b) a+b;
只需要在catch从句的参数中加入关键字if以及一个条件表达式,就可以进行选择进入哪个catch从句
try{
throw 1;
} catch(e if e instanceof ReferenceError){
//...
} catch(e if e === "quit"){
//...
} catch(e){
//...
}