强大的for-of循环
ES6不会破坏你已经写好的JS代码。目前看来,成千上万的Web网站依赖for-in循环,其中一些网站甚至将其用于数组遍历。如果想通过修正for-in循环增加数组遍历支持会让这一切变得更加混乱,因此,标准委员会在ES6中增加了一种新的循环语法来解决目前的问题。 就像这样:
for (var value of myArray) {
console.log(value);
}
这是最简洁、最直接的遍历数组元素的语法
这个方法避开了for-in循环的所有缺陷
与forEach()不同的是,它可以正确响应break、continue和return语句
标识符=>表达式。你无需输入function和return 箭头函数没有它自己的this值,箭头函数内的this值继承自外围作用域。
$("#confetti-btn").click(event => {
playTrumpet();
fireConfettiCannon();
});
// ES5
var selected = allJobs.filter(function (job) {
return job.isSelected();
});
//ES6
var selected = allJobs.filter(job => job.isSelected());
Iterator 迭代器
for of 会首先调用Symbol.iterator[1]方法,然后就会返回一个迭代器对象; 迭代器对象可以是任何有.next()方法的对象
下面根据书上的作者认为最简单的迭代器,我重写了一个更最简单的迭代器,哈哈
let some = {
[Symbol.iterator]() {
return this;
},
next(){
return{
done:false,
value:1
}
}
};
// 在 for of 中会在next()返回 done:true 之后完成,所以这是个死循环,不要在意这些细节。
来看一个正常一点的
let obj = {
data: [ 'hello', 'world' ],
[Symbol.iterator]() {
const self = this;
let index = 0;
return {
next() {
if (index < self.data.length) {
return {
value: self.data[index++],
done: false
};
} else {
return { value: undefined, done: true };
}
}
};
}
};
for(let a of obj){
console.log(a)
}
//hello
//world
支持字符换行与外部变量 ` 号
var a = 'awe'
console.log(`my name is: ${a}`); //my name is: awe
var b = `<div>
<h1>${a}</h1>
</div>`;
console.log(b);
//<div>
// <h1>${a}</h1>
//</div>
symbol
symbol是对象状态的最终的解决方案
symbol是程序创建并且可以用作属性键的值,并且它能避免命名冲突的风险。
symbol 被创建后就不可变更,你不能为它设置属性(在严格模式下尝试设置属性会得到TypeError的错误)。他们可以用作属性名称,性质与字符串类似。
每一个symbol都独一无二,不与其它symbol等同,即使二者有相同的描述也不相等;
var mySymbol = Symbol(); //调用Symbol()创建一个新的symbol,它的值与其它任何值皆不相等。 字符串或数字可以作为属性的键,symbol 也可以,它不等同于任何字符串,因而这个以symbol为键的属性可以保证不与任何其它属性产生冲突。 obj[mySymbol] = "ok!"; // 保证不会冲突 console.log(obj[mySymbol]); // ok! //想要在上述讨论的场景中使用symbol,你可以这样做: // 创建一个独一无二的symbol var isMoving = Symbol("isMoving"); ... if (element[isMoving]) { smoothAnimations(element); } element[isMoving] = true;
JavaScript的6种原始类型
- Undefined 未定义
- Null 空值
- Boolean 布尔类型
- Number 数字类型
- String 字符串类型
- Object 对象类型
symbol成为了JavaScript的第七种原始类型
Class
'use strict'
class Circle{
constructor(radius){
this.radius = radius;
Circle.circlesMade++;
}
draw(circle,canvas){
console.log('draw something')
}
static get circleMade(){
return !this._count ? 0 : this.count;
}
static set circleMade(val){
return this._count = val;
}
area(){
console.log(Math.pow(this.radius,2) * Math.PI)
return Math.pow(this.radius,2) * Math.PI;
}
get radius(){
return this._radius;
}
set radius(radius){
return this._radius = radius;
}
}
var circle = new Circle(3);
circle.draw() // draw something
circle.area() // 28.274333882308138
circle.radius = 99;
circle.area() // 30790.74959783356
- 在class中 ; 符号是可选的。
- constructor也是可选的,如果不指定,会默认构造一个空的constructor(){}
- 不可以用生成器来做构造函数
ES6提供了新的数据结构Set。它类似于数组,但是成员的值都是唯一的,没有重复的值。
Set本身是一个构造函数,用来生成Set数据结构。
一个Set是一群值的集合。它是可变的,能够增删元素。
- set 它和数组不同是不会包含相同元素。试图再次加入一个已有元素不会产生任何效果。
var s = new Set();
[2,3,5,4,5,2,2].map(x => s.add(x))
for (i of s) {console.log(i)}
// 2 3 5 4
上面代码通过add方法向Set结构加入成员,结果表明Set结构不会添加重复的值。
> arrayOfWords[15000]
"anapanapa"
> setOfWords[15000]
undefined
Set不支持索引
arr.indexOf('a') !== -1 //慢
//true
setOfWords.has('a') //快
//true
Set的数据存储结构专门为一种操作作了速度优化:包含性检测。
有一个坏处。 Map和Set都为内部的每个键或值保持了强引用,也就是说,如果一个 DOM 元素被移除了,回收机制无法取回它占用的内存,除非 movingSet中也删除了它。在最理想的情况下,库在善后工作上对使用者都有复杂的要求,所以,这很可能引发内存泄露。
所已有了 WeakSet
WeakSet与Set有两个区别:
- WeakSet的成员只能是对象,而不能是其他类型的值。
- WeakSet中的对象都是弱引用,即垃圾回收机制不考虑WeakSet对该对象的引用,也就是说,如果其他对象都不再引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存,不考虑该对象还存在于WeakSet之中。这个特点意味着,无法引用WeakSet的成员,因此WeakSet是不可遍历的。
var ws = new WeakSet();
ws.add(1)
// TypeError: Invalid value used in weak set
ws.add(Symbol())
// TypeError: invalid value used in weak set
上面代码试图向WeakSet添加一个数值和Symbol值,结果报错。
WeakSet结构有以下三个方法。
- WeakSet.prototype.add(value):向WeakSet实例添加一个新成员。
- WeakSet.prototype.delete(value):清除WeakSet实例的指定成员。
- WeakSet.prototype.has(value):返回一个布尔值,表示某个值是否在WeakSet实例之中。
下面是一个例子。
var ws = new WeakSet();
var obj = {};
var foo = {};
ws.add(window);
ws.add(obj);
ws.has(window); // true
ws.has(foo); // false
ws.delete(window);
ws.has(window); // false
WeakSet没有size属性,没有办法遍历它的成员。
ws.size // undefined
ws.forEach // undefined
ws.forEach(function(item){ console.log('WeakSet has ' + item)})
// TypeError: undefined is not a function
上面代码试图获取size和forEach属性,结果都不能成功。 WeakSet不能遍历,是因为成员都是弱引用,随时可能消失,遍历机制无法保证成员的存在,很可能刚刚遍历结束,成员就取不到了。WeakSet的一个用处,是储存DOM节点,而不用担心这些节点从文档移除时,会引发内存泄漏。
const
ES6引入的第三个声明类关键词与let类似:const。 const声明的变量与let声明的变量类似,它们的不同之处在于,const声明的变量只可以在声明时赋值,不可随意修改,否则会导致SyntaxError(语法错误)。
const MAX_CAT_SIZE_KG = 3000; // 正确
MAX_CAT_SIZE_KG = 5000; // 语法错误(SyntaxError)
MAX_CAT_SIZE_KG++; // 虽然换了一种方式,但仍然会导致语法错误
const theFairest; // 语法错误
用const声明变量后必须要赋值,否则也抛出语法错误。
class RangeIterator {
constructor(start, stop) {
this.value = start;
this.stop = stop;
}
[Symbol.iterator]() { return this; }
next() {
var value = this.value;
if (value < this.stop) {
this.value++;
return {done: false, value: value};
} else {
return {done: true, value: undefined};
}
}
}
Generator 生成器
这个被作者称为最具魔力的特性,貌似很强大的样子,继续看下去。
Generator函数是分段执行的,yield语句是暂停执行的标记,而next方法可以恢复执行。
function* helloWorldGenerator(name) {
yield 'hello';
yield 'world';
if(name){
yield name;
}
return 'ending';
}
var a = helloWorldGenerator('awe');
a.next() //{ value: 'hello', done: false }
a.next() //{ value: 'world', done: false }
a.next() //{ value: 'awe', done: false }
a.next() //{ value: 'ending', done: true }
看完这个代码是不是感觉像迭代器? 还真是。“所有生成器都是内建了.next()和 Symbol.iterator[2]的实现。
感觉生成器内容真是太多了,推荐上这里细看 likebeta.gitbooks.io/es6tutorial…[3]