1 箭头函数
ES6允许使用"箭头"(=>)定义函数。
如果箭头函数不需要参数或者需要多个参数,就使用圆括号代表参数部分。
var sum = (num1, num2)=> num1+num2
等同于
var sum = function(num1, num2){
return num1 + num2;
}
如果箭头函数的代码块部分多余一条语句,就要使用大括号将其括起来,并使用return语句。
由于大括号被解释成代码块,所以如果箭头函数直接返回一个对象,必须在对象外面加上大括号。
var getItem = id => ({id : id, name : "Temp"});
注意:
1函数体内的this对象就是定义是所在对象,而不是使用时所在的对象。
2不可当作构造函数。也就是说,不可以使用new命令。
3不可以使用arguments对象,该对象在函数体内不存在,如果需要,可以使用rest参数代替。
4不可以使用yield命令,因此箭头函数不能用作Generator函数。
5箭头函数中this指向是固定的。
6箭头函数中没有this,内部的this指向外部的this,所用不能使用bind() call() apple() 等方法。
2 尾调用优化
尾调用:函数的最后一步是调用另一个函数
函数调用会在内存中形成一个“调用记录”,又称调用调用帧,保存调用位置和内部变量等信息。如果在函数A的内部调用函数B,那么在A的调用帧上方,还会形成一个B的调用帧。等到B运行结束,将结果返回到A,B的调用帧才会消失。如果函数B内部还调用了函数C,那就还有一个C的调用帧,以此类推。所有调用帧就形成一个“调用栈”。
尾调用由于是函数的最后一步操作,所以不需要保留外层函数的调用帧,因为调用位置,内部变量等信息都不会再用到了,直接用内层函数的调用帧取代外层函数即可。
这就叫做“尾调用优化”,即只保留内层函数的调用帧。如果所有函数都是尾调用,那么完全可以做到每次执行时调用帧只有一项,这将大大节省内存。这就是“尾调用优化”的意义。
注:只有不在用到外层函数的内部变量,内层函数的调用帧才会取代外层函数的调用帧,否则就无法进行“尾调用优化”
function addOne (a) {
var one = 1;
function inner (b) {
return b + one;
}
return inner(a);
}
上面的函数就不会进行尾调用优化,因为内层函数inner用到了外层函数addOne的内部变量one。
尾递归: 函数调用自身成为递归。如果尾调用自身就称为尾递归。
递归非常耗费内存,因为需要同时保存成百上千个调用帧,很容易发生"栈溢出"错误。但对于尾递归来说,由于只存在一个调用帧,所以永远不会发生“栈溢出”错误。
3 对象的扩展
ES6允许直接写入变量和函数作为对象的属性和方法。
var foo = 'bar';
var o = {
foo,
method(){
return 'hello';
}
}
属性名表达式
var lastWorld = 'last world';
var o = {
[lastWorld] : 'world',
['h'+'ello'](){
return 'hi';
}
}
name属性:函数的name属性返回函数名。对象方法也是函数,因此也有name属性。
Object.is(); 用来比较2个值是否严格相等,它与严格比较运算符(===)的行为基本一致。
object.is({},{});
//false
Object.assign(); 用来将源对象的所有可枚举属性复制到目标对象。至少需要2个参数,第一个参数是目标对象,后面的参数都是源对象。(参数都必须为对象) 如果目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性。只要一个参数不是对象,就会抛出错误。
属性的遍历 (6种)
for..in 循环遍历对象自身的和继承的可枚举的属性(不含symbol属性)
Object.keys(obj) 返回一个数组,包括对象自身的(不含继承的)所有可枚举属性(不含symbol属性)
对象的扩展运算符
rest参数用于从一个对象取值,相当于将所有可遍历但尚未被读取的属性,分配到指定的对象上。所有的键及其值都会复制到心对象上。(浅复制)
let {x,y,...z} = {x:1,y:2,a:3,b:4}
用于取出参数对象的所有可遍历属性,复制到当前对象中。
let z = {a:3,b:4};
let n = {...z};
4 Set
set类似数组,但是成员的值都是唯一的,没有重复的值。其本身是一个构造函数,用来生成Set数据结构。
set不会添加重复的值。
set函数可以接受一个数组(或类似数组的对象)作为参数,用于初始化。
var s = new Set();
[2,3,4,5,5,2,2].map(x=>s.add(x))
for(i of s){ console.log(i) }
//2,3,4,5
var set = new set([1,2,3,4,4]);
[...set]
//[1,2,3,4]
set实例的属性和方法
set.prototype.constructor 构造函数,默认值就是set函数。
set.prototype.size 返回set实例的成员总数。
方法分为2大类 1》操作方法(用于操作数据) 2》遍历方法(用于遍历成员)
add(value) 添加某个值,返回set结构本身
delete(value) 删除某个值,返回一个布尔值,表示删除是否成功
has(value) 返回一个布尔值,表示参数是否为set的成员
clear() 清楚所有成员,没有返回值
keys() 返回一个键名的遍历器
values() 返回一个键值的遍历器
entries() 返回一个键值对的遍历器
forEach() 使用回调函数遍历每个成员
5 WeakSet
WeakSet结构和set类似,也是不重复的值的集合,与set有2个区别
首先WeakSet中的成员都是对象,而不能是其他类型的值。其次WeakSet中的对象都是弱引用,即垃圾回收机制不考虑WeakSet对该对象的引用。
add(value) 向WeakSet实例添加一个新成员
delete(value)清除WeakSet实例的指定成员
has(value)返回一个布尔值,表示某个值是否在WeakSet实例中。
6 Map
javaScript的对象(obj)本质上是键值对的集合(Hash结构),但是只能用字符串为键。(自动转化)
为了解决这个问题,ES6提供了Map数据结构,它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当做键。也就是说,Object结构提供了“字符串-值”的对应,Map结构提供了“值-值”的对应,是一种更完善的Hash结构实现。
只有对同一个对象的引用,Map结构才将其视为同一个键。
var map = new Map();
map.set(['a'],555);
map.get(['a']);//undefind
set和get方法,表面上是针对同一个键,但实际上这是两个值,内存地址是不一样的。Map的键实际上是跟内存地址绑定的。
实例的属性和操作方法
sizes属性返回Map结构的成员总数
set(key,value) set方法设置key做对应的键值,然后返回整个Map结构。如果key已经有值,则键值会被更新,否则就新生成该键。 set返回的是Map本身,因此可以采用链式写法。
get(key)
.keys()
.values()
.entries()
.forEach()
7 WeakMap
weakMap结构与Map结构基本类似,唯一的区别是它只接受对象作为键名(null除外),不接受其他类型的值作为键名,而且键名所指向的对象不计入垃圾回收机制。