首先要区分语言和平台之间的关系,语言自己是指ECMAScript,平台是指浏览器或者node,在平时咱们浏览器开发里js就是ECMAScript。
浏览器的组成部分
node.js的组成部分
在ES5.1以后版本咱们统称为ES6
主要说明以下:
**• let 和 const
• Arrow functions
• Classes(类)
• Generators
• Map 和 Set
• for ... of 循环
• Symbol
• Modules
• Template literals(模板字⾯量)
• Default parameters(默认参数)
• Enhanced object literals(对象字⾯量加强)
• Destructuring assignments(解构分配)
• Spread operator(展开操做符)
• Proxy和Reflect**前端
这些新增API和对象主要是进行:
**• 对原有语法进⾏加强
• 解决原有语法上的⼀些问题或者缺陷
• 全新的对象、全新的⽅法、全新的功能
• 全新的数据类型和数据结构**node
let 声明的成员只会在所声明的块中生效
if (true) {
let foo = 'zce'
console.log(foo)
}es6
let经典应用场景算法
var elements = [{}, {}, {}] for (let i = 0; i < elements.length; i++) { elements[i].onclick = function () { console.log(i) } }
由于产生本身的循环体的块级做用域,因此能够代替闭包。api
咱们看下面例子来解析一下运行
for (let i = 0; i < 3; i++) {
let i = 'foo'
console.log(i)
}数组
以下:
let i = 0浏览器
if (i < 3) {
let i = 'foo'
console.log(i)
}数据结构
i++闭包
if (i < 3) {
let i = 'foo'
console.log(i)
}dom
i++
if (i < 3) {
let i = 'foo'
console.log(i)
}
i++
实际上是这样的,因此咱们也就能够解释在这其中for 循环会产生两层做用域。
let 还修复了变量声明提高现象。
const 总体和let相似,
const name
name = 'zce' //会报错
箭头函数的 简易写法,能够去看下阮一峰老师的es6,这里主要标明几个箭头函数的特征。
class Super{ sayName =()=>{ //do some thing here } } var a = new Super() var b = new Super() a.sayName === b.sayName //false
es6里实现class关键字,来代替es5里的构造函数的方式生成类。
es6的extends关键词来进行继承,底层是使用es5寄生组合式继承的封装。
使用extends来继承,constructor中使用this必需要先实例化父类,使用super关键词实例化,其余方法里也可经过super调用父类成员。
class里的constructor至关于es5的实例化,而后以外定义的属性函数,至关于定义在原型上(不包含箭头函数)
static关键词 静态属性,能够不实例化类可直接访问,里面的this指向类自己,不是实例化后的对象。
// extends 继承 class Person { constructor (name) { this.name = name } say () { console.log(`hi, my name is ${this.name}`) } } class Student extends Person { constructor (name, number) { super(name) // 父类构造函数 this.number = number } hello () { super.say() // 调用父类成员 console.log(`my school number is ${this.number}`) } } const s = new Student('jack', '100') s.hello()
Generators函数调用会返回一个iterator对象,能够继续调用next()方法来依次返回Generators函数yield关键词以后的表达式结果,结果是个对象{value:'结果值',done:布尔值(是否结束true/false)},yield能够暂停当前函数,而后再经过外面iterator调用next方法继续往下走。
代码以下:
function * createIdMaker () { let id = 1 while (true) { yield id++ } } const idMaker = createIdMaker() console.log(idMaker.next().value) console.log(idMaker.next().value) console.log(idMaker.next().value) console.log(idMaker.next().value)
Map
对象保存键值对。任何值(对象或者原始值) 均可以做为一个键或一个值。构造函数Map
能够接受一个数组做为参数。
map和object区别
Object
的键只能是字符串或者 Symbols
,但一个Map
的键能够是任意值。Map
中的键值是有序的(FIFO 原则),而添加到对象中的键则不是。Map
的键值对个数能够从 size 属性获取,而 Object
的键值对个数只能手动计算。Map
支持for of 循环,obj须要本身添加Symbol.iterator经常使用api
遍历方法
keys()
:返回键名的遍历器values()
:返回键值的遍历器entries()
:返回键值对的遍历器forEach()
:使用回调函数遍历每一个成员map支持 for of 遍历,内部的Symbol.iterator是entries
Set
对象容许你存储任何类型的值,不管是原始值或者是对象引用。它相似于数组,可是成员的值都是惟一的,没有重复的值。
Set
自己是一个构造函数,用来生成Set
数据结构。Set
函数能够接受一个数组(或者具备 iterable 接口(迭代器)的其余数据结构)做为参数,用来初始化(带有Symbol.iterator)。Set
对象存储的值老是惟一的,因此须要判断两个值是否恒等。有几个特殊值须要特殊对待:
set经常使用方法
add(value)
:添加某个值,返回 Set 结构自己(能够链式调用)。delete(value)
:删除某个值,删除成功返回true
,不然返回false
。has(value)
:返回一个布尔值,表示该值是否为Set的成员。clear()
:清除全部成员,没有返回值。遍历方法
keys()
:返回键名的遍历器。values()
:返回键值的遍历器。entries()
:返回键值对的遍历器。forEach()
:使用回调函数遍历每一个成员。因为Set
结构没有键名,只有键值(或者说键名和键值是同一个值),因此keys方法和values方法的行为彻底一致。
for of 循环本意是统一 js中循环的标准,咱们查看可使用for of循环的对象,
解释:里面都有一个Symbol.iterator方法,这个of循环首先调用这个方法,它返回一个对象(而后就是循环对象),这个对象内部有next方法,方法返回一个对象{value:'值',done:布尔值//是否结束},每次循环就是调用这个next方法,等done为true的时候循环结束。
这是否是很像Generator函数,因此说Generator调用的结果也是能够用of循环的,好比map和set结构都有这个Symbol.iterator方法,,因此它也是能够循环的,可是对象是没有这个方法的,因此须要咱们手动添加一下
const todos = { life: ['吃饭', '睡觉', '打豆豆'], learn: ['语文', '数学', '外语'], work: ['喝茶'], [Symbol.iterator]: function * () { const all = [...this.life, ...this.learn, ...this.work] for (const item of all) { yield item } } } for (const item of todos) { console.log(item) }
由于咱们看到 它和Generator函数很像,因此咱们用它辅助实现一下,
给[Symbol.iterator]定义一个生成器函数,返回一个可迭代对象,而后咱们使用 yield 函数来辅助实现,由于它返回的和咱们要的那个对象是同样的。
symbol 是一种基本数据类型 (primitive data type)。Symbol()
函数会返回symbol类型的值,该类型具备静态属性和静态方法。它的静态属性会暴露几个内建的成员对象;它的静态方法会暴露全局的symbol注册,且相似于内建对象类,但做为构造函数来讲它并不完整,由于它不支持语法:"new Symbol()
"。
每一个从Symbol()
返回的symbol值都是惟一的。一个symbol值能做为对象属性的标识符;这是该数据类型仅有的目的。更进一步的解析见—— glossary entry for Symbol。
使用场景:扩展对象,属性名冲突问题
通常使用第三方库扩展时,咱们预防覆盖方法名,可使用Symbol对象作key,由于两个 Symbol 永远不会相等。
因为没法建立出同样的 Symbol 值, 因此咱们能够用它建立「私有」成员
更多的方法能够查看mdn
Symbol
模块 es6中的import语句为变量,函数,和类建立的是只读绑定,标识符只有在导出的模块中能够修改,即便是导入绑定的模块也没法更改绑定的值。
一些简单的语法能够在mdn上查看
这里贴一个之前的异步模块
var me =(function hello(name){ function greeting(){ console.log('hello'+name) } return {//public API greeting:greeting } })('kyle') console.log(me.greeting())
// 反引号包裹
const str = hello es2015, this is a string
;
容许换行,能够经过${}插入表达式,返回得结果会输出到对应位置
xxx${...}xxx
**带标签的模板字符串,模板字符串的标签就是一个特殊的函数,
使用这个标签就是调用这个函数**
const name = 'tom' const gender = false function myTagFunc (strings, name, gender) { // console.log(strings, name, gender) // return '123' const sex = gender ? 'man' : 'woman' return strings[0] + name + strings[1] + sex + strings[2] } const result = myTagFunc`hey, ${name} is a ${gender}.` console.log(result) hey, tom is a woman.
就是把字符串根据变量分割成一个数组,而后后续就是字符串中的变量依次传递.
在es5中给函数的默认参数只能
function foo (enable) { // 短路运算不少状况下是不适合判断默认参数的,例如 0 '' false null // enable = enable || true enable = enable === undefined ? true : enable console.log('foo invoked - enable: ') console.log(enable) } //这样去赋值如今es6中咱们能够 function foo (enable = true) { console.log('foo invoked - enable: ') console.log(enable) } //包括解构的时候能够 const {sex='默认'}=props; 甚至函数能够 function foo({sex='1'}={}){ console.log(sex) }
这一篇比较简单看代码把
// 对象字面量 const bar = '345' const obj = { foo: 123, // bar: bar // 属性名与变量名相同,能够省略 : bar bar, // method1: function () { // console.log('method111') // } // 方法能够省略 : function method1 () { console.log('method111') // 这种方法就是普通的函数,一样影响 this 指向。 console.log(this) }, // Math.random(): 123 // 不容许 // 经过 [] 让表达式的结果做为属性名 [bar]: 123 } // obj[Math.random()] = 123 console.log(obj) obj.method1() // Object.assign 方法 // const source1 = { // a: 123, // b: 123 // } // const source2 = { // b: 789, // d: 789 // } // const target = { // a: 456, // c: 456 // } // const result = Object.assign(target, source1, source2) // console.log(target) // console.log(result === target) // 应用场景 function func (obj) { // obj.name = 'func obj' // console.log(obj) const funcObj = Object.assign({}, obj) funcObj.name = 'func obj' console.log(funcObj) } const obj = { name: 'global obj' } func(obj) console.log(obj) // Object.is console.log( // 0 == false // => true // 0 === false // => false // +0 === -0 // => true // NaN === NaN // => false // Object.is(+0, -0) // => false // Object.is(NaN, NaN) // => true )
数组的解构
const arr = [100, 200, 300]
const [foo, bar, baz] = arr;
能够直接这样去解构,对应下表0,1,2
若是不要前面的能够
[,,baz]
这样就是只取2位置得了
经典的排序算法 交换位置能够:
const [arr[1],arr[0]]=[arr[0],arr[1]]
而后展开操做符
const [foo, ...rest] = arr;
取第一个 参数以后全部的返回一个数组。
展开操做符只能放在最后。
取出来的值也能够给定默认值
例如
const [foo, bar, baz = 123, more = 'default value'] = arr;
对象的解构:
const obj = { name: 'zce', age: 18 }
const { name } = obj;
至关于{name:name}
能够这样去解构,包括对象当参数传递时也能够这样解构
而后也能够给定默认值,前面有例子。
这个解构变量名字的声明和正常声明相反,是在右边,以下
const { name: objName = 'jack' } = obj;
name是从obj解构出来的属性名,objName是咱们新的变量名来接收这个值,而且给了它一个默认值。
而后就是展开操做
const {name,...args}=obj;
不要在意这些报错
这个解构展开就是说,除了解构指明的属性名以外,剩余的属性组成一个新对象,用剩余参数名称接受。
代理对象proxy和defineProperty的对比
优点:
一个简单的例子
const person2 = { name: 'zce', age: 20 } const personProxy = new Proxy(person2, { get (target, property) { console.log('get', property) return target[property] }, set (target, property, value) { console.log('set', property, value) target[property] = value } }) personProxy.name = 'jack' console.log(personProxy.name)
更多的api的使用方式能够在mdn中查看
Proxy的使用方式
Reflect 是一个内置的对象,它提供拦截 JavaScript 操做的方法。这些方法与proxy handlers的方法相同。Reflect
不是一个函数对象,所以它是不可构造的。
它提供了对对象的统一操做,以前对象的操做不统一,
const obj = {
name: 'zce',
age: 18
}
console.log('name' in obj)
console.log(delete obj['age'])
console.log(Object.keys(obj))
console.log(Reflect.has(obj, 'name'))
console.log(Reflect.deleteProperty(obj, 'age'))
console.log(Reflect.ownKeys(obj))
具体提供了哪些方法,也能够直接去mdn中查看
Reflect
该内容借鉴于 拉钩大前端训练营