ES6学习笔记
1.const和let
let特点:
1.在编译过程中没有变量提升
2.不允许重复声明(同个代码块内)
3.块级作用域(只在声明的代码块内有效)
4.暂时性死区
1)说个问题
1 | for (var i = 0; i < 5; i++) { |
其实是想每隔一秒打印出0到4,使用let
1 | for (let i = 0; i < 5; i++) { |
代码转成es5的结果:
当然也可以使用闭包(在函数调用的时候,首先会在函数内寻找变量,找不到就会在定义函数的作用域内找)
1 | for (var i = 0; i < 5; i++) { |
2)临时性死区
1 | var a = 1; |
在es6中,在区域中存在let和const声明的变量,在声明之前使用就会报错。
const特点:
1.在编译过程中没有变量提升
2.不允许重复声明(同个代码块内)
3.块级作用域(只在声明的代码块内有效)
4.暂时性死区
5.声明常量,必须在初始化的时候赋值,不可再改变值。
但是const比较奇怪的地方就是:
保存的是常量的时候,不允许修改,如果保存的是复合类型数据的引用地址,可以修改数据的属性。
1 | const obj = { |
2.对象和数组的解构
特点:
1.按照一定的模式,从数组和对象中取得值。
2.解构不成功,值为undefined。
3.指定默认值
1)一般使用方法
对象:
1 | var obj = { |
数组:
1 | var arr = [1,2,3]; |
2)指定默认值
1 | var obj = { |
null和undefined有区别。
3)对象解构赋值的特点 (变量名与属性名不一样)
1 | let { foo: baz } = { foo: 'aaa', bar: 'bbb' }; |
可以理解为:
1 | let { foo } = { foo: 'aaa', bar: 'bbb' }; |
先找同名属性,再赋值给对应变量。
解构用于嵌套对象:
1 | const node = { |
转换成es5:
这样子可能更易于理解
3.字符串
1)模板字符串(支持换行)
1 | const name = "qinhanwen"; |
2)字符串方法
1 | var URI = 'file://xxxxxxx.png'; |
4.函数
1)参数的解构赋值与默认参数
1 | function move({x = 0, y = 0} = {}) { |
编译结果:
和
1 | function move({x, y} = { x: 0, y: 0 }) { |
编译结果:
这两个都是为move方法指定默认值,表现略微有点不同。看到编译结果就很好理解。
2)剩余操作符
1 | function sum(a, ...arr) { |
3)展开运算符
1 | var arr1 = [1,2,3]; |
编译一下:
这是es7!!!!哈哈哈哈哈
1 | var obj1 = {name:'qinhanwen'}; |
说一下深拷贝和浅拷贝,其实就是传值和传址的问题。
1 | var obj = {name:'qinhanwen'}; |
var obj1 = obj;
是传递obj的引用地址,指向栈中。
如何深拷贝?
想到2个办法
1.序列化与反序列化
1 | var obj = {name:'qinhanwen'}; |
不过这有个缺点,在序列化的时候,undefined与函数等会丢失
1 | var obj = { |
2.递归实现一个简单的深拷贝
1 | function ObjectDeepClone(obj) { |
其实typeof 数组和对象,返回都是object,直接用typeof也可以
4)箭头函数
箭头函数没有this,它会使用上层的this
1 | var obj = { |
编译:
箭头函数中的this,与es5中this指向有区别,es5中this只与调用的上下文有关,与声明的时候无关,而箭头函数的this,在函数声明的时候就定死了。
如果this需要随调用环境变化,就不适合使用箭头函数。
5.数组方法
1)filter
1 | var arr = [1, 2, 3]; |
2)find和findIndex
3)includes
4)every
5)some
6.对象拓展
1)属性和方法简写
1 | const a = 1; |
2)对象方法
1.setPrototypeOf
1 | var obj = { |
那么setPrototypeOf做了什么,相当于:
1 | Object.prototype.setPrototypeOf = function (obj, proto) { |
2.super
1 | var obj = { |
7.类
1)类
1 | class Parent{ |
编译成es5:
1 | ; |
其实总的来说做了几件事
1)函数表达式声明Parent,在它内部声明了一个函数Parent
2)绑定内部函数Parent的原型上的属性
和静态属性(类上的属性)
3)返回Parent
2)继承
1 | class Parent{ |
编译成es5:
嗯,确实有点长看起来有点吓人,看下它做了什么吧。不过看之前最好先了解一下Object构造函数
1 | ; |
总的来说这里做了哪些事情
1.首先将Parent的静态属性和原型属性绑定到Parent上
2.将Parent的静态属性和原型属性绑定到Child.__proto__
上和Child.prototype.__proto__
上
3.将静态属性和原型属性绑定在Child上
看一下child实例,如图:
那么温习一下,es5来实现一个简易的继承吧
1 | function Parent(name){ |
child实例如图:
与上面的打印出的实例有一点差异,这里暂时不深入了。
8.生成器(Generator)与迭代器(iterator)
迭代器
1 | let books = ['JavaScript','Node']; |
可以看出来迭代器可以不停的调用next方法,会得到{value,done}的结果,当done为true的时候,遍历结束。
生成器函数
声明方式:function
关键词与函数名中有一个*
号
1 | function * test(){} |
使用方式:碰到yield
表达式,便会停止执行,必须调用遍历器对象的next
方法,使得指针移向下一个状态。也就是说,每次调用next
方法,内部指针就从函数头部或上一次停下来的地方开始执行,直到遇到下一个yield
表达式(或return
语句)为止。
1 | let books = ['JavaScript','Node']; |
也就是说,遇到yield
是暂停的标志,next
可以恢复执行。
#####
9.Promise
10.Symbol
新的基础数据类型,表示独一无二的值,可以接受一个字符串作为参数
1 | let s = Symbol(); |
可以转成字符串或者布尔值
1 | let s = Symbol('booleanOrString'); |
作为属性名来用,可以避免键名被覆盖
1 | let s = Symbol('booleanOrString'); |
for…in , Object.getOwnPropertyName,以及Object.keys都无法获得键名,因为它不是私有属性,要使用Object.getOwnPropertySymbols方法
1 | let s = Symbol('booleanOrString'); |
11.Set与Map
Set是一个构造函数,用于生成Set数据结构,类似于数组,但是成员的值都是唯一的。
1 | let arr = new Set([1,1,2,3,3,4,5,5]); |
实例的__proto__
上的方法和属性。
也可以使用add方法
1 | let set = new Set(); |
可是使用它来去重
1 | var arr = [...new Set([1,1,2,3,3,4,5,5])]; |
实例的__proto__
属性上的方法:
add(value)
:添加某个值,返回 Set 结构本身。delete(value)
:删除某个值,返回一个布尔值,表示删除是否成功。has(value)
:返回一个布尔值,表示该值是否为Set
的成员。clear()
:清除所有成员,没有返回值。keys()
:返回键名的遍历器values()
:返回键值的遍历器entries()
:返回键值对的遍历器forEach()
:使用回调函数遍历每个成员
1 | let s = new Set(); |
Map
类似于对象,也是键值对的集合,但是它各种类型的数据
都可以当做键名
1 | var obj = {} |
对象会把键名调toString方法
1 | var m = new Map(); |
总结
不要问我为什么有的地方用var有的地方用let,调试方便。。