ES2015基础知识

336 阅读4分钟

2015年开始ES保持每年一个版本的迭代,ES6指的是2015年的版本,也泛指ES2015之后的版本

ES2015有哪些新特性?

1.解决原有语法上的一些问题和不足,例如let、const提供的块级作用域
2.对原有语法进行增强。例如数组对象的解构、函数参数得默认值、模板字符串
3.全新的对象、全新的方法、全新的功能。例如promise、async/await、Generator
4.全新的数据类型和数据结构。如map、set、symbol

块级作用域

//  var是没有块级作用域的,在外面也能拿到
if (true) {
    var foo = 'sss';
}
console.log(foo)
//  let/const就有块级作用域,会报错
if (true) {
    let foo = 'sss';
}
console.log(foo)

var、let、const之间的差别

1.var存在变量提升,即在变量定义之前调用,这个变量为undefined;let/const不存在变量提升,如果在声明变量之前调用就会报错。
2.var不存在块级作用域,在for/if中定义的变量外面也能获取到;let/const存在块级作用域。
3.在同一作用域下,var允许重复声明变量,let/const则不允许,会报错。
4.var/let定义的变量可以被修改,const定义的一旦声明则不能被修改。const对于应用类型,则是保留内存地址不能被修改,并不能保证里面的值被修改。

数组的扩展

1.数组的解构

const arr = [1, 2, 3];
//  参数位置一一对应
const [a, b, c] = arr;
//  剩余参数解构,只能在最末尾出现
const [a, ...rest] = arr;
//  解构参数设置默认值
const [a, b, c, d = 4] = arr;
console.log(a, b, c, d)

2.数组的展开

//  函数参数的展开
const arr = [1, 2, 3];
console.log(...arr);
//  数组的合并
const arr1 = [3, 4];
const arr3 = [...arr, ...arr1];

对象的扩展

1.对象的解构

const obj = {
    name: 'tom',
    age: 18
}
const {name, age} = obj

2.计算属性名

const aaa = 'xxx'
const obj = {
    [aaa] : 123
}
console.log(obj)

3.Object.assign

const obj1 = { name: 'tom' }
const obj2 = { age: 18 }
// 两种浅拷贝的方法
const obj3 = Object.assign(obj1, obj2);
const obj4 = {...obj1, ...obj2};

模板字符串

自动支持换行

const name = 'tom'
const str = `my name is ${name}`;

支持标签函数,他会以表达式分割

const name = 'tom';
const age = 18;
const fn = string => console.log(string)

const result = fn`my name is ${name}, i am ${age} yaers old`;
console.log(result)
// [ 'my name is ', ', i am ', ' yaers old' ]

字符串的扩展方法

includes、startsWith、endsWith

const message = 'Error: foo is not defined.'
console.log(message.includes('foo'));
console.log(message.startsWith('Error'))
console.log(message.startsWith('e'))
console.log(message.endsWith('e'))
console.log(message.endsWith('.'))
/*
true
true
false
false
true
*/

箭头函数

箭头函数不会改变this的指向,他的this是在函数定义的时候就确定好了

const person = {
    name: 'tom',
    sayHi: () => {
        console.log(`Hi, my name is ${this.name}`)
    }
}
person.sayHi()
// Hi, my name is undefined

proxy

监视对象属性的读写 Object.defineProperty/Proxy。

Object.defineProperty/Proxy有哪些区别

1.Object.defineProperty只能监视到对象属性的读写,proxy可以监视到更多对象的操作,如 delete
2.proxy可以监听数组
3.proxy是以非侵入的方式监管了对象的读写

const personProxy = new Proxy(person, {
    get(target, property) {
        return target[property] ? target[property] : 'default';
    },
    set(target, property, value) {
        console.log(target, property, value)
        target[property] = value;
    },
    deleteProperty(target, property) {
        console.log(property);
        delete target[property]
    }
})
personProxy.height = 172;
delete personProxy.height;

reflect

将Object对象的一些明显属于语言层面的方法放到Reflect对象上 Reflect.apply(target, thisArg, args)
Reflect.construct(target, args)
Reflect.get(target, name, receiver)
Reflect.set(target, name, value, receiver)
Reflect.defineProperty(target, name, desc)
Reflect.deleteProperty(target, name)
Reflect.has(target, name)
Reflect.ownKeys(target)
Reflect.isExtensible(target)
Reflect.preventExtensions(target)
Reflect.getOwnPropertyDescriptor(target, name)
Reflect.getPrototypeOf(target)
Reflect.setPrototypeOf(target, prototype)

iterator和for...of循环

iterator遍历器就是一种接口,为各种不同的数据结构提供统一的访问机制,任何数据结构只要部署了iterator接口,就可以完成遍历操作,object没有提供for...of接口

新的数据结构Symbol、Set、Map

Symbol的特点:
1.symbol的值都是唯一的
2.symbol.for方法为字符串与symbol提供了一一对应的关系,同样的字符串一定可以得到相同symbol值,boolean值都会转化为字符串
3.symbol()作为对象的键时,循环是无法拿到的,Object.keys,for都拿不到

console.log(Symbol('foo') === Symbol('foo'))
const s1 = Symbol.for('foo');
const s2 = Symbol.for('foo');
console.log(s1 === s2)
console.log(Symbol.for(true) === Symbol.for('true'))
const symbolObj = {
    [Symbol()]: 'aaa',
    aaa: 123
}
console.log(Reflect.ownKeys(symbolObj))
//  [ 'aaa', Symbol() ]
console.log(Object.keys(symbolObj))
//  [ 'aaa' ]
console.log(Object.getOwnPropertySymbols(symbolObj))
//  [ Symbol() ]

Set主要运用于去重


const setArr = new Set();
setArr.add(1).add(2).add(1)
console.log(setArr)
// Set(2) {1, 2}

map结构的键可以是任何数据类型

const mapObj = new Map();
mapObj.set({aaa: 1}, {bbb: 2});
console.log(mapObj)

promise/async

class

export/import

export命令用于规定模块的对外接口

export var firstName = 'Michael'
export { firstName };
export function multiply(x, y) {
    return x * y;
};

// 报错
export 1;

// 报错
var m = 1;
export m;

// export语句输出的接口,与其对应的值是动态绑定关系,即通过该接口,可以取到模块内部实时的值
export var foo = 'bar';
setTimeout(() => foo = 'baz', 500);

import命令用于输入其他模块提供的功能

import { firstName, lastName, year } from './profile.js';

export default命令用于指定模块的默认输出。显然,一个模块只能有一个默认输出,因此export default命令只能使用一次。所以,import命令后面才不用加大括号,因为只可能唯一对应export default命令。

gennerator

异步编程的方法,大概有下面四种:
1.回调函数
2.事件监听
3.发布/订阅
4.Promise对象
Generator 函数将 JavaScript 异步编程带入了一个全新的阶段。 Generator 函数可以暂停执行和恢复执行,这是它能封装异步任务的根本原因。除此之外,它还有两个特性,使它可以作为异步编程的完整解决方案:函数体内外的数据交换和错误处理机制。

next返回值的 value 属性,是 Generator 函数向外输出数据;next方法还可以接受参数,向 Generator 函数体内输入数据。

function* gen(x){
    var y = yield x + 2;
    return y;
}

var g = gen(1);
g.next() // { value: 3, done: false }
g.next(2) // { value: 2, done: true }