标签:
大多数语言都会定义它们的子集,用以更安全地执行不信任的第三方代码。
Douglas Crockford曾写过一本很簿的书《JavaScript: The Good Parts》,专门介绍JavaScript中值得发扬光大的精华部分。这个语言子集的目标是规避语言中的怪癖、缺陷部分,最终编程更轻松、程序更健壮。
Crockford写过一个在线代码质量检测工具JSLint,可通过这个工具对代码进行检查。
子集的设计目的是能在一个容器或”沙箱”中更安全地运行不可信的第三方JavaScript代码。所有能破坏这个沙箱并影响全局执行环境的语言特性和API在这个安全子集中都是禁止的。
为了让JavaScript代码静态地通过安全检查,必须移除一些JavaScript特性:
在JavaScript1.5及后续版本中可以使用const关键字来定义常量,常量是不可重复赋值的变量。
const pi = 3.14;
pi = 4; // 对常量赋值会报"TypeError"
在JavaScript1.7中,添加了关键字let,可以定义带有作用域的变量:
下面列举各种场景使用let的作用域:
let me = ‘go‘; // 全局作用域
var i = ‘able‘; // 全局作用域
function ingWithinEstablishedParameters() {
let terOfRecommendation = ‘awesome worker!‘; // 函数作用域
var sityCheerleading = ‘go!‘; // 函数作用域
};
function allyIlliterate() {
// tuce在这里不可见
for( let tuce = 0; tuce < 5; tuce++ ) {
// tuce在这里可见
};
// tuce在这里不可见
};
function byE40() {
// nish在这里可见
for( var nish = 0; nish < 5; nish++ ) {
// nish在这里可见
};
// nish在这里可见
};
更多可参考:“let” keyword vs “var” keyword
例子如下:
o = {x:1, y:2};
for each(let v in o)
console.log(v); // 输出1和2
console.log(v); // 错误:v is not defined
在for循环中使用let关键字:
// 输出 5, 5, 5, 5, 5
for (var i = 0; i < 5; ++i) {
setTimeout(function () {
console.log(i);
}, 1000);
}
// 输出 1, 2, 3, 4, 5
for (let i = 0; i < 5; ++i) {
setTimeout(function () {
console.log(i);
}, 1000);
}
更多可参考:Explanation of let
and block scoping with for loops
注:var声明的变量在它们所声明的函数内始终是存在的,但直到代码执行行到var语句时才初始化变量,在var语句执行之前它的值是undefined。通过let声明的变量也与之类似。
在解构赋值中,等号右侧是一个数组或对象(一个结构化的值),指定左侧一个或多个变量的语法和右侧的数组和对象直接量的语法保持格式一致。
let [x, y] = [1, 2]; // 等价于let x=1, y=2
[x, y] = [x+1, y+1]; // 等价于x=x+1, y=y+1
[x, y] = [y, x]; // 交换2个变量的值
console.log([x, y]); // => [3, 2]
let [x, y] = [1]; // x = 1, y = undefined
[x, y] = [1, 2, 3]; // x = 1, y = 2
[, x, y] = [1, 2, 3, 4];// x = 2, y = 3
注:JavaScript并未提供将右侧多余的值以数组的形式赋值给左侧变量的语法。比如,上面代码的第2行,并不能将[2,3]赋值给y。
let first, second, all;
all = [first, second] = [1, 2, 3, 4]; // first=1, second=2, all=[1,2,3,4]
let [one, [twoA, twoB]] = [1, [2, 2,5], 3]; // one=1, twoA=2, twoB=2.5
let transparent = {r:0.0, g:0.0, b:0.0, a:1.0};
let {r:red, g:green, b:blue} = transparent; // red=0.0, green=0.0, blue=0.0
let data = {
name: "destructuring assignment",
type: "extension",
impl: [{engine: "spidermonkey", version: 1.7},
{engine: "rhino", version: 1.7}]
};
let ({name: feature, impl: [{engine:impl1, version: v1}, {engine:impl2}]} = data) {
console.log(feature); // => "destructuring assignment"
console.log(impl1); // => "spidermonkey"
console.log(v1); // => 1.7
console.log(impl2); // => "rhino"
}
for循环是遍历对象的属性,而for/each遍历对象属性的值。
a = ["one", "two", "three"];
for(let p in a) console.log(p); // => 0, 1, 2
for each(let v in a) console.log(v) // => "one", "two", "three"
迭代器是一个对象,这个对象允许对它的值集合进行遍历,并保持任何必要的状态以便能够跟踪到当前遍历的”位置”。迭代器必须包含next()方法,每一次调用next()都返回集合中的下一个值。
下面的counter()返回一个迭代器对象:
function counter(start) {
let nextValue = Math.round(start);
return { next: function() { return nextValue++; }}; // 返回迭代器对象
}
let serialNumberGenerator = counter(1000);
let sn1 = serialNumberGenerator.next(); // => 1000
let sn2 = serialNumberGenerator.next(); // => 1001
注:当迭代器用于有限的集合时,没有多余的值可迭代时,next()会抛出StopIterator,StopIterator是全局对象的属性,一个普通的对象(它自身没有属性),只是为了终结迭代而保留的一个对象。
_iterator_()
的方法,用以返回这个集合的迭代器对象。_iterator_()
方法来获得一个迭代器对象(类型自动转换),然后调用迭代器的next()方法。for/in循环会自动处理StopIteration异常,而且处理过程对开发者是不可见的。function range(min, max) {
return {
get min() { return min; },
get max() { return max; },
includes: function(x) { return min <= x && x <= max; },
toString: function() { return "[" + min + "," + max + "]"; },
_iterator_: function() {
let val = Math.ceil(min);
return { next: function() {
if(val > max)
throw StopIteration;
return val++;
}
};
}
};
}
for(let i in range(1, 10)) console.log(i); // => 输出1~10之间的数字
_iterator_()
方法的调用结果,返回一个迭代器对象。_iterator_()
方法,它会返回这个对象的一个可迭代的自定义迭代器。每次调用这个迭代器的next()方法都会返回包含2个值的数组,第1个数组元素是属性名,第2个数组元素是属性的值。for(let [k, v] in Iterator({a:1, b:2}))
console.log(k + "=" + v); // => "a=1", "b=2"
o = {x:1, y:2};
Object.prototype.z = 3;
for(p in o) console.log(p); // => "x", "y", "z"
for(p in Iterator(o)) console.log(p); // => ["x", 1], ["y", 2],注:不会遍历继承属性
for(p in Iterator(o, true)) console.log(p); // => "x", "y", 注:只遍历属性名
任何使用关键字yield的函数都称为”生成器函数”。
下面是一个普通的生成器函数:
function range(min, max) {
for(let i=Math.ceil(min); i <= max; i++) {
yield i;
}
}
var f = range(3, 8); // 返回一个生成器对象
console.log(f.next()); // 3,返回单独值
console.log(f.next()); // 4,返回单独值
如果在生成器函数声明时加个”*”,则yield会返回对象值:
// function后添加"*"
function *range(min, max) {
for(let i=Math.ceil(min); i <= max; i++) {
yield i;
}
}
var f = range(3, 8); // 返回一个生成器对象
console.log(f.next()); // { value=3, done=false, z=3},返回对象
console.log(f.next()); // { value=4, done=false, z=3},返回对象
yield不仅可以返回值,还可以用于接收值,可通过next()或send()传递yield的接收值:
function *test() {
var i = yield 2;
yield i;
};
var f = test();
console.log(f.next()); // { value=2, done=false, z=3}, 第1次调用时,没有执行到yield语句,不需要接收值
console.log(f.next(5)); // { value=5, done=false, z=3}, yield接收变量5,并赋值给i
console.log(f.next(6)); // { done=true, z=3, value=undefined},最后一个值为undefined
更多可参考:
es6-generators
如何理解ES6的yield
数组推导是一种利用另外一个数组或可迭代对象来初始化数组元素的技术。
数组推导的语法如下:
[expression for ( variable in object ) if ( condition )]
定义一个数组:
let evensquares = [x*x for (x in range(0,10)) if (x % 2 === 0)]
与下面的代码等价:
let evensquares = [];
for(x in range(0,10)) {
if(x % 2 === 0)
evensquares.push(x*x);
}
数组推导表达式特点:
将数组推导中的方括号替换成圆括号,它就成了一个生成器表达式。比如:
let h = (f(x) for(x in g));
这段代码与下面的代码等价:
function map(i, g) {
for(let x in g) yield f(x);
}
如果函数只计算一个表达式并返回它的值,关键字return和花括号都可以省略。
比如,对数组按降序排列:
data.sort(function(a,b) b-a); // 在"b-a"的前面省略了"{}"和return
try/catch语句中可以使用多catch从句,在catch从句的参数中可以添加关键字if进行异常类型判断。
try {
// 这里可能会抛出多种类型的异常
throw 1;
}
catch(e if e instanceof ReferenceError) {
// 这里处理引用错误
}
catch(e if e === "quit") {
// 这里处理抛出的字符串是"quit"的情况
}
catch(e if typeof e === "string") {
// 处理其他字符串的情况
}
catch(e) {
// 处理余下的异常情况
}
finally {
// finally从句正常执行
}
注:如果catch从句没有一个是true,那么程序会向上抛出这个未捕获的异常。
E4X为处理XML文档定义了一系列强大的特性。XML对象和原始的JavaScript对象不同,对它们进行typeof运算的结果是”xml”。XML对象和DOM对象没有任何关系。
// 创建一个XML对象
var pt = <periodictable>
<element id="1"><name>Hydrogen</name></element>
<element id="2"><name>Helium</name></element>
</periodictable>;
// 添加一个新元素
pt.element += <element id="3"><name>Lithium</name></element>;
// 创建单个节点 XML
pt.element += new XML(‘<element id="4"><name>Boron</name></element>‘);
// 创建多个节点 XMLList
pt.element += new XMLList(‘<element id="4"><name>Boron</name></element>‘ +
‘<element id="5"><name>Lithium</name></element>‘);
// 得到所有<element>标签的 列表
var elements = pt.element;
// 得到所有的<name>标签的 列表
var names = pt.element.name;
// "Hydrogen",name的第0个标签内容
var n = names[0];
// 得到所有<element>标签的所有子节点(即<name>标签列表)
var names = pt.element.*;
var pt = new XML(‘<periodictable><element id="1"><name>Hydrogen</name></element><element id="2"><name>Helium</name></element></periodictable>‘);
// 访问id属性,输出"2"
var a = pt.element[1].@id;
// 获取所有的<element>标签的所有属性
var b = pt.element.@*;
// 对所有的<element>元素组成的列表进行过滤
// 过滤出那些id属性小于3的元素
var c = pt.element.(@id < 3);
delete pt.element; // 删除所有的<element>标签
delete pt.element[0].@id; // 删除一个属性
E4X是支持命名空间的,它为使用XML命名空间提供了语法支持和API支持。
// 声明默认的命名空间
default xml namespace = "http://www.w3.org/1999/xhtml";
标签:
原文地址:http://blog.csdn.net/byrantch/article/details/51583162