JavaScript的语言本身
通常看作 JavaScript 的标准化规范
实际上 JavaScript 是 ECMAScript 的拓展语言
ECMAScript 只是提供了做基本的语法
let 与 块级作用域
作用域: 某个成员能够起作用的范围
ES2015 之前 JavaScript 的作用域有:
- 全局作用域
- 函数作用域
ES2015 新增了:
- 块级作用域
let const
const 在 let 的基础上增加了 只读 的功能
最佳实践: 不用 var 主用 const 需要时用 let
数组的解构
const arr = [100, 200, 300]
const [foo, bar, baz] = arr
console.log(foo, bar, baz) //100 200 300
const [, , t] = arr
console.log(t) //300
const [p, ...rest] = arr
console.log(rest) //[ 200, 300 ]
const [o, tw, th, f] = arr
console.log(f) //undefined
const [y, e, s = 321, si = 'default'] = arr
console.log(s, si) //300 default
对象的解构
const obj = { name: 'ds', age: 18 }
const { name } = obj
console.log(name) // ds
const age = 19
const { age: age1 } = obj
console.log(age1)
const { name: objName = 'jack' } = obj
console.log(objName)
模板字符串
- 直接换行
- 插值表达式
- 带标签的模板字符串
const name = 'tom'
const gender = true
function myTagFunc (strings, name, gender) {
return strings[0] + name + strings[1] + gender
}
const result = myTagFunc`hey, ${name} is a ${gender}`
console.log(result)
字符串的拓展方法
- includes()
- startsWith()
- endsWith()
const message = 'Error: foo is not defined.'
console.log(
message.startsWith('Error'),
message.endsWith('.'),
message.includes('foo')
)
参数默认值
function foo (bar, enable = true) {
console.log(enable)
}
foo()
剩余参数
function foo (...args) {
console.log(args)
}
foo(1, 2, 3, 4)
展开数组
const arr = ['foo', 'bar', 'baz']
console.log.apply(console, arr)
console.log(...arr)
箭头函数
const inc = n => n + 1
console.log(inc(100))
const arr = [1, 2, 3, 4]
arr.filter(function(item) {
return item % 2
})
arr.filter(i => i % 2)
箭头函数不会改变
this指向
const person = {
name: 'tom',
sayHello: function () {
console.log(this.name)
},
sayHi: () => {
console.log(this.name)
},
sayHiAsync: function () {
setTimeout(function () {
console.log(this.name)
}, 1000)
},
sayHelloAsync: function () {
setTimeout(() => {
console.log(this.name)
}, 1000)
}
}
person.sayHello() // tom
person.sayHi() // undefined
person.sayHiAsync() // undefined
person.sayHelloAsync() // tom
对象字面量的增强
const bar = '233'
const obj = {
foo: 123,
// bar: bar,
bar,
// method: function () {}
method () {
console.log(this)
},
[Math.random()]: 889
}
obj.method()
console.log(obj)
对象拓展方法
- Object.assign
// 将多个源对象中的属性复制到一个目标对象中
const source = {
a: 123,
b: 123,
c: {
k: 'dsa'
}
}
const target = {
a: 456,
c: {
l: 'dawsd'
}
}
const result = Object.assign(target, source)
console.log(target) // { a: 123, c: { k: 'dsa' }, b: 123 }
console.log(target === result) // true
function func (obj) {
const funcObj = Object.assign({}, obj)
funcObj.name = 'func obj'
return funcObj
}
const obj = { name: 'global obj' }
console.log(func(obj)) // { name: 'func obj' }
console.log(obj) // { name: 'global obj' }
- Object.is
console.log(0 == false) // true
console.log(0 === false) // false
console.log(+0 === -0) // true
console.log(NaN === NaN) // false
console.log(Object.is(NaN, NaN)) // true
console.log(Object.is(+0, -0)) // false
Proxy
const person = {
name: 'dasd',
age: 23
}
const personProxy = new Proxy(person, {
get (target, property) {
return property in target ? target[property] : 'default'
},
set (target, property, value) {
if (property === 'age') {
if (!Number.isInteger(value)) {
throw new TypeError(`${value} is not an int`)
}
}
target[property] = value
// console.log(target, property, value)
}
})
personProxy.age = 100
personProxy.gender = true
personProxy.name = 'biki'
console.log(personProxy.name)
console.log(personProxy.xxx)
console.log(personProxy)
Proxy vs Object.defineProperty()
defineProperty只能监视属性的读写Proxy能够监视到更多对象操作
const person = {
name: 'dsad',
age: 23
}
const personProxy = new Proxy(person, {
deleteProperty (target, property) {
console.log('delete', property)
delete target[property]
}
})
delete personProxy.age
console.log(person)
- Proxy 更好的支持数组对象的监视
const list = []
const listProxy = new Proxy(list, {
set (target, property, value) {
console.log('set', property, value)
target[property] = value
return true
}
})
listProxy.push(100)
//set 0 100
// set length 1
- Proxy 是以非侵入的方式监管了对象的读写
Reflect
- Reflect 属于一个静态类
- Reflect 内部封装了一系列对对象的底层操作
- Reflect 成员方法就是 Proxy 处理对象的默认实现
const obj = {
foo: '123',
bar: '456'
}
const proxy = new Proxy(obj, {
get (target, property) {
console.log('watch logic~')
return Reflect.get(target, property)
}
})
console.log(proxy.foo)
- Reflect 统一提供一套用于操作对象的 API
const obj = {
name: 'das',
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))
Promise
- 一种更优的异步编程解决方案
- 解决了传统异步编程中回调函数嵌套过深的问题
class 类
// function Person (name) {
// this.name = name
// }
// Person.prototype.say = function () {
// console.log(`hi, my name is ${this.name}`)
// }
class Person {
constructor (name) {
this.name = name
}
say () {
console.log(`hi, my name is ${this.name}`)
}
}
const p = new Person('biki')
p.say()
实例方法 vs. 静态方法
class Person {
constructor (name) {
this.name = name
}
say () {
console.log(`hi, my name is ${this.name}`)
}
static create (name) {
console.log(this) // [class Person]
return new Person(name)
}
}
const p = Person.create('biki')
p.say()
类的继承
class Person {
constructor (name) {
this.name = name
}
say () {
console.log(`hi, my name is ${this.name}`)
}
static create (name) {
console.log(this) // [class Person]
return new Person(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()
Set 数据结构
const s = new Set()
s.add(1).add(2).add(3)
console.log(s)
console.log(s.size)
console.log(s.has(100))
console.log(s.delete(3))
console.log(s)
s.clear()
console.log(s)
const arr = [1, 3, 3, 2, 1, 4]
const result = Array.from(new Set(arr)) || [...new Set(arr)]
console.log(result)
Map 数据结构
const obj = {}
obj[true] = 'value'
obj[123] = 'value'
obj[{ a: 1 }] = 'value'
console.log(Object.keys(obj)) //[ '123', 'true', '[object Object]' ]
const m = new Map()
const tom = { name: 'tom' }
m.set(tom, 90)
console.log(m) // Map(1) { { name: 'tom' } => 90 }
console.log(m.get(tom)) // 90
console.log(m.has(tom)) // true
m.delete(tom)
console.log(m) // Map(0) {}
m.set('dsa', true)
console.log(m.get('dsa')) // true
m.clear()
console.log(m) // Map(0) {}
m.set('biki', 100)
m.forEach((value, key) => {
console.log(value, key)
})
Symbol
const s = Symbol()
console.log(s) // Symbol()
console.log(typeof s) // symbol
console.log(Symbol() === Symbol()) // false
// 实现私有成员
// a,js =======================================
const name = Symbol()
const person = {
[name]: 'dsad',
say () {
console.log(this[name])
}
}
// b.js =======================================
person[Symbol()] // 访问不到
person.say()
Symbol 最主要的作用就是为对象添加独一无二的属性名
其他
const s1 = Symbol.for('foo')
const s2 = Symbol.for('foo')
console.log(s1 === s2) // true
console.log(
Symbol.for(true) === Symbol.for('true') // true
)
console.log(Symbol.iterator) // Symbol(Symbol.iterator)
console.log(Symbol.hasInstance) // Symbol(Symbol.hasInstance)
const obj = {
[Symbol.toStringTag]: 'XObject'
}
console.log(obj.toString()) // [object XObject]
====================================================================
const obj = {
[Symbol('dsad')]: 'symbol value',
foo: 'normal value'
}
for (var key in obj) {
console.log(key) // 拿不到 Symbol 值
}
console.log(Object.keys(obj)) // [ 'foo' ]
console.log(JSON.stringify(obj)) // {"foo":"normal value"}
console.log(Object.getOwnPropertySymbols(obj)) //[ Symbol(dsad) ]
for...of
for...of 将作为遍历所有数据结构的统一方式
const arr = [100, 200, 300, 400]
for (const item of arr) {
console.log(item)
}
// 虽然类似于 for...Each
arr.forEach(item => {
console.log(item)
})
// 但是 for...of 可以使用 break 随时终止循环 forEach 不能
for (const item of arr) {
console.log(item)
if (item > 100) {
break
}
}
// 其他可以跳出循环的遍历方法
arr.some() // 返回 true
arr.every() // 返回 false
// 遍历 Set
const s = new Set(['foo', 'bar'])
for (const item of s) {
console.log(item)
}
// 遍历 Map
const m = new Map()
m.set('foo', '123')
m.set('bar', '321')
for (const item of m) {
console.log(item)
}
//[ 'foo', '123' ]
//[ 'bar', '321' ]
// 遍历普通对象
const obj = { foo: 124, bar: 433 }
for (const item of obj) { //TypeError: obj is not iterable
console.log(item)
}
可迭代接口 (iterable)
实现
iterable接口是for...of的前提
const set = new Set(['foo', 'bar', 'baz'])
const iterator = set[Symbol.iterator]()
console.log(iterator.next()) // { value: 'foo', done: false }
console.log(iterator.next()) // { value: 'bar', done: false }
console.log(iterator.next()) // { value: 'baz', done: false }
console.log(iterator.next()) // { value: 'baz', done: false }
实现可迭代接口
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
}
}
}
}
for (const item of obj) {
console.log(item)
}
迭代器模式
// 场景: 你我协同开发一个任务清单应用
// 我的代码 ======================================
const todos = {
life: ['fa', 'dad', 'fafaf'],
learn: ['dsaddsa', 'dasdsadasdds', 'fggggg'],
work: ['ewewe'],
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(item => {
console.log(item)
})
// ======================================
for (const item of todos) {
console.log(item)
}
普通对象使用 for...of
const obj = {
a: '1',
b: 2,
c: { d: 3 },
[Symbol.iterator]: function () {
let index = 0
let keys = Object.keys(this)
let self = this
return {
next: function () {
return {
value: self[keys[index]],
done: index++ >= keys.length
}
}
}
}
}
for (const item of obj) {
console.log(item)
}
生成器
function * foo () {
console.log('1111')
const a = yield 100
console.log(a) // 2000
console.log('222222')
const b = yield 200
console.log(b) // 3000
console.log('333333')
const c = yield 300
console.log(c) // 4000
}
const generator = foo()
console.log(generator.next()) // { value: 100, done: false }
console.log(generator.next(2000)) // { value: 200, done: false }
console.log(generator.next(3000)) // { value: 300, done: false }
console.log(generator.next(4000)) // { value: undefined, done: true }
生成器的应用
// 发号器
function * createIdMaker () {
let id = 1
while (true) {
yield id++
}
}
const idMaker = createIdMaker()
console.log(idMaker.next())
console.log(idMaker.next())
console.log(idMaker.next())
console.log(idMaker.next())
console.log(idMaker.next())
// iterator
const todos = {
life: ['fa', 'dad', 'fafaf'],
learn: ['dsaddsa', 'dasdsadasdds', 'fggggg'],
work: ['ewewe'],
[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)
}
ES Modules
ES2016 概述
Array.prototype.includes
const arr = ['foo', 1, NaN, false]
// 旧
console.log(arr.indexOf('foo'))
// 新
console.log(arr.includes('foo'))
- 指数运算符
// 旧
console.log(Math.pow(2, 10))
// 新
console.log(2 ** 10)
ES2017 概述
Object.values
const obj = {
foo: 'dsad'
}
console.log(Object.values(obj))
Object.entries
const obj = {
foo: 'eqwe',
bar: 'dasd'
}
console.log(Object.entries(obj)) // [ [ 'foo', 'eqwe' ], [ 'bar', 'dasd' ] ]
for (const [key, value] of Object.entries(obj)) {
console.log(key, value)
}
// foo eqwe
// bar dasd
// 普通对象 转成 Map
console.log(new Map(Object.entries(obj))) // Map(2) { 'foo' => 'eqwe', 'bar' => 'dasd' }
Object.getOwnPropertyDescriptors
const p1 = {
firstName: 'li',
lastName: 'lei',
get fullName () {
return this.firstName + ' ' + this.lastName
}
}
console.log(p1.fullName) // li lei
const p2 = Object.assign({}, p1)
p2.firstName = 'biki'
console.log(p2.fullName) // li lei
const descriptors = Object.getOwnPropertyDescriptors(p1)
console.log(descriptors)
const p3 = Object.defineProperties({}, descriptors)
p3.firstName = 'biki'
console.log(p3.fullName) // biki lei
String.prototype.padStart/String.prototype.padEnd
const books = {
html: 5,
css: 16,
javascript: 121
}
for (const [name, count] of Object.entries(books)) {
console.log(`${name.padEnd(16, '-')}|${count.toString().padStart(3, '0')}`)
}
/**
html------------|005
css-------------|016
javascript------|121
**/
- 在函数参数中添加尾逗号
// 对代码管理工具 更友好
function foo (
bar,
baz,
) {
}
const arr = [
100,
200,
300,
400,
]
Async / Await