let允许创建块级作用域,ES6推荐在函数中使用let定义变量,而非var。const声明一个常量,同样在块级作用域有效,const声明的变量类似于指针,指向某个引用,也就是说这个【变量】并非一成不变。
var a = 2;
{
let a =3;
console.log(a);//3
}
console.log(a);//2
{
const ARR = [5,6]
ARR.push(7);
console.log(ARR);//[5,6,7]
ARR = 10;//TypeError
}
特征:
块级作用域?
ES5只有全局作用域和函数作用域,没有块级作用域。ES5规定,函数只能在顶层作用域和函数作用域之中生命,不能再跨级作用域声明。
ES6的块级作用域,允许任何作用域的嵌套。ES6引入了块级作用域,明确允许在块级作用域之中声明函数。ES6允许在跨级作用域内声明函数,函数声明类似于var,即会提升到全局作用域或函数作用域的头部,同时,函数声明还会提升到所在的块级作用域的头部
ES6中,箭头函数就是函数一种简写形式,使用括号包裹参数,跟随一个 =>,紧接着是函数体
var getData = function(){
return 4.55
}
var getData = () => 4.55
需要注意是是,上面的getData箭头函数采用了简洁函数体,它不需要return语句,下面的李子使用正常函数体:
let arr = ['apple','banana','orange']
let breakfast = arr.map(fruit => {
return fruit + 's';
})
console.log(breakfast);//["apples", "bananas", "oranges"]
当然,箭头函数不仅仅是让代码变得简洁,函数中this总是绑定总是指向对象本身,具体看下面几个例子。
function Person(){
this.age = 0;
setInterval(function growUp(){//在非严格模式下,growUp()函数的this指向window对象
this.age++;
},1000);
}
var person = new Person();
我们经常需要使用一个变量来保存this,然后在growUp函数中引用
function Person(){
var self = this;
self.age =0;
setInterval(function growUp(){
self.age++;
},1000);
}
然而使用箭头函数可以省却这个麻烦
function Persion(){
this.age = 0;
setInterval(() => { //this => person对象
this.age++;
},1000);
}
ES6运行你对函数参数设置默认值
let getFinalPrice = (price,tax=0.7) => price+price*tax;
getFinalPrice(500);//850
Spread、Rest操作符... 需要看上下文语境。
当被用于迭代器中时,它是一个Spread操作符
function foo(x,y,z){
console.log(x,y,z)
}
let arr = [1,2,3]
foo(...arr);//1 2 3
当被用于函数传参时,是一个Rest操作符
function foo(...args){
console.log(args);
}
foo(1,2,3,4,5);//[1,2,3,4,5]
ES6允许声明在对象字面量时使用简写语法,来初始化属性变量和函数的定义方法,并且允许在对象属性中进行计算操作:
function getCar(make, model, value) {
return {
// 简写变量
make, // 等同于 make: make
model, // 等同于 model: model
value, // 等同于 value: value
// 属性可以使用表达式计算值
['make' + make]: true,
// 忽略 `function` 关键词简写对象函数
depreciate() {
this.value -= 2500;
}
};
}
let car = getCar('Barret', 'Lee', 40000);
// output: {
// make: 'Barret',
// model:'Lee',
// value: 40000,
// makeKia: true,
// depreciate: function()
// }
ES6 支持二进制和八进制的字面量,通过在数字前面添加 0o 或者0O 即可将其转换为八进制值:
let oValue = 0o10;
console.log(oValue); // 8
let bValue = 0b10; // 二进制使用 `0b` 或者 `0B`
console.log(bValue); // 2
解构可以避免在对象赋值时产生中间变量;
function foo(){
return [1,2,3]
}
let arr = foo();//[1,2,3]
let [a,b,c] = foo();
console.log(a,b,c);//1 2 3
function bar(){
retun {
x:4,
y:5,
z:6
}
}
let {x:x,y:y,z:z} = bar ();
console.log(x,y,z);//4 5 6
ES6允许在对象中使用super方法:
var parent = {
foo(){
console.log('Hello from the Parent');
}
}
var child = {
foo(){
super.foo();
console.log('hello from the child')
}
}
Object.setPrototypeOf(child,parent);
child.foo();//hello from the parent;
//hello from the child
ES6中有一种十分简洁的方法组装一堆字符串和变量
let user = 'make';
console.log(`Hi $(user}!`); //Hi make
for...of 用于遍历一个迭代器,如数组:
let nicknames = ['di','boo','punkey'];
nicknames.size =3;
for (let nickname of nicknames){
console.log(nickname); //di, boo ,punkey
}
for... in 用来遍历对象中的属性:
let nicknames = ['di','boo','punkey']
nickname.size = 3;
for(let nickname in nicknames){
console.log(nickname); //0,1,2,size
}
ES6中两种新的数据结构集:Map和WeakMap。事实上每个对象可以看做一个Map.
一个对象由多个key-val对构成,在Map中,任何类型都可以作为对象的key,如:
var myMap = new Map();
var keyString = "a string",
keyObj = {},
keyFunc = function () {};
// 设置值
myMap.set(keyString, "value 与 'a string' 关联");
myMap.set(keyObj, "value 与 keyObj 关联");
myMap.set(keyFunc, "value 与 keyFunc 关联");
myMap.size; // 3
// 获取值
myMap.get(keyString); // "value 与 'a string' 关联"
myMap.get(keyObj); // "value 与 keyObj 关联"
myMap.get(keyFunc); // "value 与 keyFunc 关联"
WeakMap 就是一个 Map,只不过它的所有 key 都是弱引用,意思就是 WeakMap 中的东西垃圾回收时不考虑,使用它不用担心内存泄漏问题。
另一个需要注意的点是,WeakMap 的所有 key 必须是对象。它只有四个方法 delete(key),has(key),get(key) 和set(key, val):
let w = new WeakMap();
w.set('a', 'b');
// Uncaught TypeError: Invalid value used as weak map key
var o1 = {},
o2 = function(){},
o3 = window;
w.set(o1, 37);
w.set(o2, "azerty");
w.set(o3, undefined);
w.get(o3); // undefined, because that is the set value
w.has(o1); // true
w.delete(o1);
w.has(o1); // false
set对象是一组不重复的值,重复的值将被忽略,值类型可以是原始类型和引用类型:
let mySet = new Set([1,1,2,2,3,3]);
mySet.size = 3;//3
mySet.has(1);//true
mySet.add('string');
mySet.add([a:1,b:2});
可以通过forEach和for...of来遍历Set对象:
mySet.forEach((item) => {
console.log(item);
// 1
// 2
// 3
// 'strings'
// Object { a: 1, b: 2 }
});
for (let value of mySet) {
console.log(value);
// 1
// 2
// 3
// 'strings'
// Object { a: 1, b: 2 }
}
Set同样有delete()和clear()方法。
WeakSet
类似于WeakSet,WeakSet对象可以让你在一个集合中保存对象的弱引用,在WeakSet中的对象允许出现一次:
var ws = new WeakSet();
var obj = {};
var foo = {};
ws.add(window);
ws.add(obj);
ws.has(window);//true
ws.has(foo); //fase,foo没有添加成功
ws.delete(window);//从结合中删除window对象
ws.has(window); //false,window对象已经被删除
ES6中有class语法,值得注意的是,这里的class不是新的对象继承模型,它只是原型链的语法糖表现形式。函数中使用static关键词定义构造函数的方法和属性:
class Task(){
constructor(){
console.log('task instantiated!');
}
showId(){
console.log(23)
}
static loadAll(){
console.log('Loading all tasks..');
}
}
console.log(typeof Task); //function
let task = new Task(); // 'task instantiated'
task.showId(); //23
Task.loadAll(); // loading all task..
类中的继承和超集
class Car(){
constructor(){
console.log('Creating a new car')
}
}
class Porsche extends Car{
constructor(){
super();
console.log('creating Porsche')
}
}
let c = new Porsche();// creating a new car; creating Porsche
extends允许一个子类继续父类,需要注意的是,子类的constructor函数中需要执行super()函数。
当然,你也可以在子类方法中调用方法,如super.parentMethodName().
注意几点:
symbol是一种新的数据类型,它的值是唯一的,不可变的。ES中提出symbol的目的是为了生成一个唯一的标识符,不过你访问不到这个标识符:
var sym = Symbol('some optional description');
console.log(typeof sym);//symbol
注意,这里symbol前面不能使用new操作符。
如果它被用作一个对象的属性,那么这个属性会是不可枚举的:
var o = {
val:10,
[Symbol('random')]:'i am a symbol',
}
console.log(Object.getOwnPropertyNames(o); //val
如果要获取对象 symbol 属性,需要使用Object.getOwnPropertySymbols(o)。
迭代器允许每次访问数据集合的一个元素,当指针指向数据集合最后一个元素是,迭代器便会退出,它提供了next()来遍历一个序列,这个方法返回一个包含done和value属性的对象。
ES6中可以通过Symbol.iterator给对象设置默认的遍历器,无论什么时候对象需要被遍历,执行它的@@iterator方法便可以返回一个用于获取值的迭代器。
数组默认就是一个迭代器:
var arr = [11,12,13];
var itr = arr[Symbol.iterator]();
itr.next(); // { value: 11, done: false }
itr.next(); // { value: 12, done: false }
itr.next(); // { value: 13, done: false }
itr.next(); // { value: undefined, done: true }
Generators函数是ES6的新特性,它允许一个函数的可遍历对象生成多个值,在使用中你会看到*语法和一个新的关键词yield
function *infiniteNumbers() {
var n = 1;
while (true){
yield n++;
}
}
var numbers = infiniteNumbers(); // returns an iterable object
numbers.next(); // { value: 1, done: false }
numbers.next(); // { value: 2, done: false }
numbers.next(); // { value: 3, done: false }
每次执行yield时,返回的值变为迭代器的下一个值。
ES6对Promise有原生的支持,一个Promise是一个等待被异步执行的对象,当它被执行完成后,其状态会变成ressolved或者rejected。
var p = new Promise(function(resolve, reject) {
if (/* condition */) {
// fulfilled successfully
resolve(/* value */);
} else {
// error, rejected
reject(/* reason */);
}
});
每一个Promise都有一个.then方法,这个方法接受两个参数,第一个是处理resolved状态的回调,一个是处理rejected状态的回调:
p.then((val) => console.log("Promise Resolved", val),
(err) => console.log("Promise Rejected", err));
解构赋值的规则是,只要等号右边的值不是对象或数组,就先将其转为对象。由于undefined和null无法转为对象,所以对他们进行解构赋值都会报错。undefined会触发变量的参数的默认值。
不能使用圆括号
1)变量声明语句;
// 全部报错
let [(a)] = [1];
let {x: (c)} = {};
let ({x: c}) = {};
let {(x: c)} = {};
let {(x): c} = {};
let { o: ({ p: p }) } = { o: { p: 2 } };
2)函数参数。函数参数也属于变量声明,因此不能带有圆括号。
// 报错
function f([(z)]) { return z; }
// 报错
function f([z,(x)]) { return x; }
3)赋值语句的模式。
// 全部报错
({ p: a }) = { p: 42 };
([a]) = [5];
可以使用圆括号
1)赋值语句的非模式部分,可以使用圆括号。
[(b)] = [3]; // 正确
({ p: (d) } = {}); // 正确
[(parseInt.prop)] = [3]; // 正确
用途
1)变换变量的值
let x = 1;
let y = 2;
[x, y] = [y, x]
2)从函数返回多个值
//返回一个数组
function example(){
return [1, 2, 3]
}
let [a, b, c] = example();
//返回一个对象
function example(){
return {
foo: 1,
bar: 2
}
}
let {foo, bar} = example();
3)函数参数的定义
解构赋值可以方便地讲一组参数与变量名对应起来
//参数是一组有次序的值
function f([x, y, z]){ ... }
f([1, 2, 3])
//参数是一组无次序的值
function f({x, y, z}){ ... }
f({z:3, y:2, x:1})
4)提取JSON数据
let jsonData = {
id: 42,
status: "OK",
data:[867, 100]
}
let {id, status, data} = jsonData;
console.log(id, status, data)
//42, ok, [867, 100]
5)函数参数的默认值
jQuery.ajax = function(url, {
async = true,
beforeSend = function(){},
cache = true,
complete = function(){},
crossDomain = false,
global = true,
} = {}) {
// ... do stuff
};
6)遍历Map解构
const map = new Map();
map.set('first', 'hello')
map.set('second', 'world')
for (let [key, value] of map) {
console.log(key+'is'+value);
}
//first is hello;
//second is world;
7)输入模块的指定方法
const { SourceMapConsumer, SourceNode } = require('source-map');