准备
依赖 nodemon 小工具
作用修改完代码自动执行
命令行代码:
-
code a.js 在当前目录下创建一个a.js的文件
-
del a.js 删除当前目录下的a.js文件
-
npx nodemon ./a.js 使用项目中的nodemon执行a.js文件
let 与块级作用域
let 声明的变量
- 只在块作用域中生效
- 没有声明提升
- 存在暂时性死去
const关键字
- 声明一个常量,不能修改(不能重新指向一个新的内存地址)
- 其它和let一样
数组解构
const arr = [100,200,300]
// const [foo,bar,baz] = arr
// 取出特定的值
// const [,,baz] = arr
// console.log(baz) // 300
// 三点运算
// const [foo,...rest] = arr
// console.log(rest) // [ 200, 300, 400 ]
// arr长度小于赋值项数 多出来的项被赋值为undefined
// const [foo,bar,baz,more] = arr
// console.log(foo,bar,baz,more) // 100 200 300 undefined
// 设置默认值
const [foo,bar,baz,more=400] = arr
console.log(foo,bar,baz,more) // 100 200 300 400
对象的结构
-
根据属性名去提取
-
其他和数组一样
// const obj = {name:'zce' ,age:18}
const obj = {name1 : 'zce',age:18}
// const {name} = obj
// 重命名
const name = 'tom'
// const { name } = obj // SyntaxError: Identifier 'name' has already been declared
// const {name : objName} = obj
//console.log(name,objName) // tom zce
/*
重命名加设置默认值
*/
const {name:objName='jack'} = obj
/*结构console*/
const {log} = console
模板字符串
- 支持换行
- 插值表达式
带标签的模板字符串
const name = 'tom'
const gender = true
function myTagFunc(string ,name,gender){
console.log(string,name,gender) //
return '123'
}
const result = myTagFunc`hey,${name} is a ${gender}` // [ 'hey,', ' is a ', '' ] tom true
console.log(result) // '123'
字符串扩展方法
一下三个方法可以用来判断,字符串中是否包含指定的内容
- includes()判断一个字符串是否包含指定的内容
- startsWith()判断一个字符串是否已指定的内容开头
- endsWith() 判断一个字符串是否已指定的内容结束
函数默认值的设置
- 注意多个参数时,有默认值的参数,一定要放在后面
- 用结构赋值,想咋传就咋传
// 短路运算的方式设置默认值
function foo1(enable){
enable = enable || true
consol.elog('foo invoked-enable')
console.log(enable)
}
// 问题传入false也会使用默认值
foo1(false)
// 判断undefined,不传参数是参数会是undefined
function foo2(enable){
enable = enable=== undefined?true:enable
console.log('foo invoked - enable')
console.log(enable)
}
// 有点麻烦
foo2()
// es6后可直接设置
function foo3(bar,enable=true){
console.log('foo invoked - enable')
console.log(enable)
}
// 没有传递实参,或者实参传递的是一个undefined是去使用
foo3()
剩余操作符
function foo(...args){console.log(args)}
foo('a','b','c','d') // ['a','b','c','d']
箭头函数
- 箭头函数的this指向
对象字面量增强
- 变量名与属性名一样只写变量名
- 方法可以直接定义(普通的function)
- 可以使用表达式的返回值作为属性名(计算属性名)
// 计算属性名
const obj={
[Math.random()]:123
}
对象扩展方法
- Object.assign() 将对各源对象中的属性复制到一个目标对象中
- Object.is() 不常用
// Object.assign()
const surcel = {
a:123,
c:456
}
const target = {
a:789,
c:901
}
const result = Object.assign(target,sourcel)
console.log(target)
console.log(result===target) // true
Proxy
const person={
name:'zce',
age:20
}
const personProxy = new Proxy(person,{
// target代理对象(person)
// property 访问的属性名
get(target,property){
console.log(target,property)
return target[property]
},
// value 写入的属性值
set(target,property,value){
console.log(target,property,value)
target[property] =value
},
// 监听del操作
deleteProperty(target,property){
console.log(target,property)
delete target[property]
},
// in操作符
has(){
},
// Object.getPrototypeOf()
getPrototypeOf(){},
// Object.setPrototypeOf()
setPrototypeOf(){},
// Object.isExtensible()
isExtensible(){},
// Object.preventExtensione()
PreventExtensions(){},
// Object.getOwnPropertyDescriptor()
getOwnPropertyDescriptor(){},
// Object.defineProperty()
defineProperty(){},
//Object.getOwnPropertyNames()、Object.getOwnPropertySymbols()
ownKeys(){},
// 调用一个函数
apply(){},
// 用new调用一个函数
construct(){}
})
相比与Object.defineProperty()的优势
-
proxy更为强大
- defineProperty只能监视属性的读写
- proxy能够监视到更多的对象操作 (del操作,对象方法的调用)
-
数组对象的监视 以往重写数组调用的方法
-
以非侵入的方式监管对象的读写,即对已生成的对象不需要在进行任何的操作
// 数组对象的监视
const list = []
const listProxy = new Proxy(list,{
set(target,property,value){
// target 代理的数组
// 数组的下标
// 接收到的值
console.log(target,property,value)
return true // 设置成功
}
// 其它类似
})
Reflect
- 静态类 不能通过new Reflect()获取对象,只能调用一些静态方法
- 封装了一系列对对象的底层操作(14个静态方法别废弃了一个)
- Reflect成员方法就是Proxy处理对象的默认实现
const obj = {
foo:123,
bar:456
}
const proxy = new Proxy(obj,{
get(target,property){
return Reflect.get(target,property)
}
})
// 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))
Promise
- 一种更优的异步编程解决方案
- 解决了回调函数嵌套过深的问题
class类
// class 关键词
// 以往 构造函数
function Person(name){
this.name = name
}
Person.prototype.say = function(){
console.log(`hi,my name is ${this.name}`)
}
// 现在
class PersonClass{
// 构造函数
constructor(name){
this.name = name
}
say(){
console.log(`hi,my name is ${this.name}`)
}
// 静态方法
static create(name){
// 此处的this指向当前的类型
return new Person(name)
}
}
// 静态方法
// 以往
Person.create(name){
return new Person(name)
}
// 现在使用static关键值
继承
// 以往用原型的方式实现继承
// 现在使用extends关键字
class Student extends Person{
constructor(name,number){
// super始终指向父类,调用它就是调用父类的构造函数
super(name)
}
hello(){
super.say()
console.log(`my school number is ${this.number}`)
}
}
Set数据结果
- 与数组类似,但成员不能重复
const s = new Set()
s.add(1).add(2).add(3).add(4).add(2)
console.log(s)
s.forEach(i => console.log(i))
// for-of es6新增
for(let i of s){
console.log(i)
}
// 与数组中的length同理
console.log(s.size)
// 判断集合中是否包含指定的值
console.log(s.has(100))
// 删除指定的值,删除成功返回true
console.log(s.delete(3))
// clear 清除集合中的全部内容
s.clear()
console.log(s)
// 数组去重
const arr = [1,2,3,4,5,6,1,2]
// const result = Array.from(new Set(arr))
const result = [...new Set(arr)]
console.log(result)
Map数据结构
- 与对象类似
- 对象结构中的键只能够是字符串类型,其它数据类型的键会调用toString()
- Map可以用来映射两个任意类型数据的对应关系
const m = new Map()
const tom = {name:'tom'}
// 存数据
m.set(tom,90)
// 获取数据
m.get(tom)
// 判断数据
m.has()
m.delete()
m.clear()
m.forEach((value,key)=>{
console.log(vlaue,key)
})
Symbol
- 对象的键都是string,可能产生冲突
- Symbol 符号 表示一个独一无二得值
- 最主要的作用是为对象添加一个独一无二的属性标识符
// cache缓存
// a.js
const cache = {}
cache['foo'] = Math.random()
// b.js
cache['foo'] = '123'
// Symbol()
console.log(Symbol('ber')==Symbol('ber')) // false
// 对象的类型可以是Symbol
// 私有成员
const Obj = Symbol()
const person = {
[name]:'zce',
say(){
console.log(this[name])
}
}
// Symbol.for() 维护了一个全局的注册表,为string和Symbol提供了一个一一对应的关系
// 会对不是String的参数调用toString()
const s1 = Symbol.for('foo')
const s2 = Symbol.for('foo')
console.log(s1===s2) true
// 自定义toString标签
const obj = {
// Symbol.toStringTag 内置Symbol常量
[Symbol.toStringTag]:'XObject'
name:'sss'
}
console.log(obj.toString())
// 获取对象Symbol类型的键名
// keys只能获取到string类型的键名
console.log(Object.getOwnPropertySymbols(obj))
未来会新增一个BigInt的原始数据类型,用于存放根长的数值
循环
- for 遍历数组
- for …in… 遍历键值对
- es6 for…of… 遍历所有数据 伪数组也可以 arguments dom节点的列表 set map
- Map对象的遍历 会获取到一个数组 item 为键和值
- obj 不可以遍历 需要使用特殊方法
// for of
const arr = [100,200,300,400]
for(const item of arr){
console.log(item)
// break 可以终止循环
if(item > 100) break
}
// arr.forEach() // 不能终止遍历
// arr.some(()=>true) arr.every(()=>false) 终止遍历
// map遍历
for(const [key,value] of m){
console.log(key,value)
}
// obj 的遍历 不能直接遍历
iterable接口 迭代器
- 可迭代接口(iterable接口)就是for…of的前提,就是一种可以被for of 统一遍历访问的规格标准
- 一个数据结构只要实现了iterable接口都可以使用for of
// 获取可迭代对象的迭代器
const set = new Set(['foo','bar','baz '])
const iterator = set[Symbol.iterator]()
iterator.next()
实现可迭代对象
// const obj={
// [Symbol.iterator]:function(){
// return {
// next:function(){
// return {
// value:'zce',
// done:true
// }
// }
// }
// }
// }
const obj={
store:['foo','bar','baz'],
[Symbol.iterator]:function(){
let index = 0
const self = this
return {
next:function(){
const result = {
value:self.store[index],
done:index>=self.store.length
}
index++
return result
}
}
}
}
迭代器模式
const todos = {
life:['吃饭','睡觉','打豆豆'],
learn:['语文','数学','外语'],
work:['喝茶'],
each:function(callback){
const all = [].concat(this.life,this.learn,this.work)
for(const item of all){
callback(item)
}
},
[Symbol.iterator]:function(){
const all = [...this.life,...this.learn,...this.work]
let index = 0
return {
next :function(){
return {
value : all[index],
done : index++ >=all.length
}
}
}
}
}
todos.each(function(item){
console.log(item)
})
console.log('----------------')
for(const item of todos){
console.log(item)
}
生成器(Generator)
- 避免异步代码嵌套太深
- 提供更好的异步编程解决方案
// 语法 调用生成器函数会返回一个生成器对象
function *foo(){
console.log('zce')
return 100
}
// 返回生成其对象
const result = foo()
// 生成器对象也实现了iterator接口(迭代器接口)
console.log(result.next())
/*
yield 关键词
调用next()方法 代码执行到yield关键词处,之后等待再次调用next()
并将yield关键词后的结果返回
执行到最后一个yield关键词后再次调用next(),会返回undefined,并将done的值置为true
*/
function * foo1(){
console.log('111')
yield 100
console.log('222')
yield 200
console.log('333')
yield 300
}
const generator = foo()
console.log(generator.next())
console.log(generator.next())
console.log(generator.next())
生成器的应用场景
function *createIdMaker(){
let id = 1
while(true){
yield id++
}
}
const idMaker = createIdMaker()
console.log(idMaker.next().value)
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 ite of todos){
console.log(ite)
}
ES Modules
- 语言化层面的模块化标准
ES 2016
- 新增 includes 方法 数组中是否包含指定元素
// Array.prototype.includes
const arr = ['foo',1,NaN,false]
console.log(arr.indexOf(NaN))// false
console.log(arr.includes(NaN)) // true
// 指数运算符
// 2的10次方
// console.log(Math.pow(2,10))
console.log(2**10)
ECMAScript 2017
const obj = {
foo:'value1',
bar:'value2'
}
// 所有值的数组
console.log(Object.values(obj))
// 返回所有的键值对 二维数组
console.log(Object.entries(obj))
console.log(new Map(Object.entries(obj))) // obj转map
// 获取对象当中属性的完整描述信息
Object.getOwnPropertyDescriptors()
/*
es5 后我们可以为对象定义get或set属性
get或set属性不能通过Object.assign()来复制
*/
const p1 = {
firstName:'lei',
lastName:'Wang',
get fullName(){
return this.firstName+' '+ this.lastName
}
}
const p2 = Object.assign({},p1)
p2.firstName = 'zce'
// 将fullName当成了一个普通的属性去复制了
console.log(p2) // { firstName: 'zce', lastName: 'Wang', fullName: 'lei Wang' }
const descriptors = Object.getOwnPropertyDescriptors(p1)
const p3 = Object.defineProperties({},descriptors)
p3.firstName = 'zce'
console.log(p3.fullName)
// 字符串填充方法
// String.prototype.padStart String.prototype.padEnd
// 填充字符串的开始或结束位置,直到达到指定长度为止
const books = {
html:5,
css:16,
javascript:128
}
for(const [name,count] of Object.entries(books)){
console.log(`${name.padEnd(15,'-')}|${count.toString().padStart(3,'0')}`)
}
// 可以在函数参数中添加尾逗号,调用和定义都可以
function(bar,baz,){
}
// Async Await promise的语法糖