javaScript的语言本身。
javaScript的标准化规范,只提供了最基本的语法。
- 2015年开始ES保持每年一个版本的迭代
ES2015
- 概述
- 相比于上一个版本ES5.1变化较大
- 命名规则发生变化
- 重大变化分类
- 解决原有语法上的一些问题或者不足
- 对原有语法进行增强
- 全新的对象、全新的方法、全新的功能
- 全新的数据类型和数据结构
let与块级作用域
- let声明的变量只在最近的{},即程序块中有效
- let声明的变量不会提升
const
- 在let基础上多了一个只读特性,一旦声明就不可以修改
- 声明的时候必须赋初始值
- 不能改变的是引用数据类型的内存地址
解构
- 数组的解构 ```javascript const arr = [100, 200, 300]
const [, ,baz] = arr console.log(baz)
const [foo,…rest] = arr
const [foo, bar, baz, more = ‘default value’] = arr
- 对象的解构
```javascript
const obj = { name: 'zce', age: 18 }
const { name } = obj
console.log(name) // zce
const { name: objName } = obj // 重命名
模板字符串
const str = "hello world"
const strEs6 = `hello ES6`
// 支持换行
// 支持通过插值表达式${}插入变量值,或者进行运算
//带标签的模板字符串
const str = console.log`hello world`
const name = 'tom'
const gender = true
function myTagFunc(strings, name, gender) {
console.log(strings, name, gender) // ['hey','is a ', '.']
//return 123
const sex = gender? 'man' : 'woman'
return strings[0] + name + string[1] + sex + string[2]
}
const result = MyTagFunc`hey, ${name} is a ${gender}.`
console.log(result)
字符串的扩展方法
- includes:是否包含某个内容
- startsWith:以什么什么开头
- endsWith:以什么什么结尾
形参列表扩展
默认值
function foo(enable = true) {
console.log(enable)
}
// 只会在不传参的时候增加默认值
剩余参数 ```javascript // es5 使用arguments接受剩余参数
function foo (…args) { console.log(args) // [1, 2, 3, 4] } foo(1,2,3,4) // 只能出现在形参最后一位,只可以用一次
<a name="91ddc809"></a>
### 展开数组
```javascript
const arr = ["foo", "bar", "baz"]
console.log(...arr)
箭头函数
const inc = n => n+1
console.log(inc(100))
// 如果参数只有一位 括号可省略
// 如果函数体只有一句,且是return语句 那么{} 和return 可以省略
// 箭头函数不会改变this指向
const person = {
name: 'tom',
sayHiAsync: function() {
setTimeout(() => {
console.log(this.name)
},0)
}
}
person.sayHiAsync()
this 指向问题
- 沿着作用域向上找最近的一个function(不是箭头函数),看这个function是怎样执行的。
- this的指向取决于所属function的调用方式,而不是定义。
- function调用一般分为以下几种情况
- 作为函数调用,即:foo() 指向全局对象(globalThis)严格模式下是undefined。
- 作为方法调用,即:foo.bar() / foo.bar.baz() / foo[‘bar’] / foo0 指向最终调用这个方法的对象
- 作为构造函数调用,即:new Foo() 指向一个新对象 Foo {}
- 特殊调用,即:foo.call() foo.bind() foo.apply() 指向参数指定成员
- 找不到所属function,就是全局对象(浏览器环境指向window,node环境指向global)
对象字面量增强
- 变量名如果跟对象中属性名一致,那么就可以只写一次
- 属性如果是函数那么可以将:function省略
- 计算属性名:意思是可以直接以[]的形式当做对象的属性,而不需要后期再以对象[]的形式添加动态属性名
Object.assign
将多个源对象的属性复制到一个目标对象中
const source = {
a:123,
b:123
}
const target = {
a: 456,
c: 456
}
const result = Object.assign(target, source)
console.log(target) // { a: 123, c: 456, b: 123 }
console.log(result === target) // true
// 将后面的对象与第一个对象合并,覆盖掉第一个对象的重复属性的值
// 返回的地址值与第一个对象地址值相同
Object.is
同值比较,大多时候还是使用全等来判断
Proxy
对象代理
const person = {
name: 'zxc',
age: 20
}
const personProxy = new Proxy(person, {
get(target, property) {
// 返回值是外部访问的结果
// target指被访问的对象
// property 表示外部要访问的属性
return property in target? target[property] : "default"
},
set(target, property, value) {
// target 是代理的对象
// property是被外部访问的属性
// value是设置的值
// 可以在这里面做一些数据的校验。
target[property] = value
}
})
对比Object.defineProperty
object.defineProperty只能监视对象的属性的读写,而proxy能监视整个对象,能监听更多操作,例如删除对象中的属性。
new Proxy(person, {
deleteProperty(target, property){
delete target[property]
}
})
promise更好的支持数组对象的监视,defineProperty需要重写数组的操作方法来实现,Vuejs源码就是这么做的 ```javascript const list = []
const listProxy = new Proxy(list, { set (target, property, value) { // property就是数组下标 target[property] = value return true // 表示设置成功 } })
- proxy是以非侵入的方式监管了对象的读写
<a name="Reflect"></a>
### Reflect
> 静态类,封装了一系列对对象底层的操作,其成员方法就是Proxy处理对象的默认实现
```javascript
const proxy = new Proxy(obj, {
get (target, property) {
return Reflect.get(target, property)
}
})
- 统一提供了一套用于操作对象的API
```javascript
const obj = {
name: ‘zce’,
}age: 18
// 以往对象的一些操作会涉及很多不同的api console.log(‘name’ in obj) delete obj[‘age’] Object.keys(obj)
// Reflect提供了统一的形式 Reflect.has(obj, ‘name’) Reflect.deleteProperty(obj,’age’) Reflect.ownKeys(obj)
- [MDN中Reflect详解](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Reflect)
<a name="Promise"></a>
### Promise
> 解决回调函数嵌套过多的问题,细节参考之前的JavaScript异步笔记
<a name="0e702886"></a>
### Class类
```javascript
// ES6之前 类的定义
function Person (name) {
this.name = name
}
Person.prototype.say = function () {
console.log(`hi, my name is ${this.name}`)
}
var tom = new Person('Tom')
tom.say()
//ES6之后
class Person{
constructor (name) {
this.name = name
}
say() {
console.log(`hi, my name is ${this.name}`)
}
}
静态方法
static 关键词定义 类似于Java
class Person{
constructor (name) {
this.name = name
}
say() {
console.log(`hi, my name is ${this.name}`)
}
static create (name) {
return new Person(name)
// 这里this不指向Person对象
}
}
类的继承
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}`)
}
}
Set数据结构
类似数组,但是set里面不能有重复的值
const s = new Set()
s.add(1).add(2).add(3).add(4)
s.forEach(i => console.log(i))
for(let i of s) {
console.log(i)
}
console.log(s.size) // set长度
s.has(1) // 是否包含某个值
s.delete(1) // 删除某个值
s.clear()
const arr = [1, 2, 3, 4, 5, 1]
const result = Array.from(new Set(arr)) || [...new Set(arr)]
Map数据结构
与对象类似,键值对
const obj = {}
obj [true] = 'value'
obj[123] = 'value'
obj[{ a: 1 }]
console.log(Object.keys(obj)) // ["true", "123", "[object Object]"]
// 普通对象键值对 不管什么类型 都会被转变成字符串,会出现一些bug
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) => {
})
Symbol
一种全新的原始数据类型,表示一种独一无二的值
// 如果两个js文件操作同一个对象,可能会出现命名重复 从而覆盖掉别人的值
// 最主要的作用就是为对象添加一个独一无二的值
let obj = {}
obj[Symbol("foo")] = "foo"
const s1 = Symbol.for('foo')
const s2 = Symbol.for('foo')
s1 === s1 // true
Symbol.for(true) === Symbol.for('true') // true
symbol.iterator Symbol.hasInstance
const obj = {
[Symbol.toStringTag]: 'XObject'
}
console.log(obj.toString())
const obj = {
[Symbol()]: 'symbol value', // 这个属性名 遍历不出来 因此可用于私有化属性
foo: 'normal value'
}
Object.getOwnPropertySymbols()方法获取对象中的symbol属性名
For…of
可以遍历任何可被迭代的数据结构,有些数据原生不具备可迭代接口,需要实现可迭代接口, 可使用break终止遍历
const m = new Map()
m.set('foo', '123')
m.set('bar', '345')
for(const [key, value] of m) {
console.log(ket, value)
}
可迭代接口
Iterable接口 可以被for of 的前提
const arr = ["foo", "bar", "baz"]
const iterator = arr[Symbol,iterator]()
iterator.next() // {value: 'foo', done: false}
// 实现可迭代接口
const obj = {
store: ['foo', "bar", "baz"],
[Symbol.iterator]: function () {
let index = 0
const selt = this
return {
next: function () {
return result = {
value: self.store[index],
done: index++ >= self.store.length
}
}
}
}
}
// 迭代器模式
const todos = {
life: ['吃饭', "睡觉", "写代码"],
learn: ['JavaScript', 'Java', 'C++']
}
// 可为todos实现可迭代接口来方便使用者取出对象中每一个属性的数组的每一位值
const todos = {
life: ['吃饭', "睡觉", "写代码"],
learn: ['JavaScript', 'Java', 'C++'],
[Symbol.iterator]: function () {
let all = [...this.life, ...this.learn, ...this.work]
let index = 0
return {
next: function () {
return {
value: all[index],
done: index++ >= all.length
}
}
}
}
}
生成器函数
Generator,避免回调函数嵌套太深
const todos = {
life: ['吃饭', "睡觉", "写代码"],
learn: ['JavaScript', 'Java', 'C++'],
[Symbol.iterator]: function () {
let all = [...this.life, ...this.learn, ...this.work]
let index = 0
return {
next: function () {
return {
value: all[index],
done: index++ >= all.length
}
}
}
}
}
function * foo () {
console.log("111")
yield 100
console.log("222")
yield 200
}
const generator = foo()
generator.next() // {value: 100, done: false}
// 生成器函数应用
const todos = {
life: ['吃饭', "睡觉", "写代码"],
learn: ['JavaScript', 'Java', 'C++'],
[Symbol.iterator]: function () {
let all = [...this.life, ...this.learn, ...this.work]
for( const item of all) {
yield item
}
}
}
ES Modules
import… from …
ES2016
- 数组的方法:includes,数组中是否存在某个值
- 指数运算:Math.pow(2, 10) 2是底数,10是指数 新增的指数运算符:2 ** 10
ES2017
- Object.values:返回的是对象中所有值的数组。
- Object.entries:返回到的是数组,数组的每一位是键值对数组。new Map(Object.entries(obj))
- Object.getOwnPropertyDescriptors:主要配合ES2015中对象的get set使用
- String.prototype.padStart/padEnd:用给定字符串去填充目标字符串的开始和结束,直到字符串达到指定长度
- 函数参数,数组中使用尾逗号
- Async/Await:Promise语法糖