ES2015(ES6)学习手册

作用域

  • 全局作用域
  • 函数作用域
  • 块级作用域(es6)

let

  • let 声明的变量只在所处的块级有效
  • let没有变量声明提升

需要注意的一点:

for (let i = 0;i < 3; i++) {
     let i = "xxx"
     console.log(i);
}

其实在此处是两层的块级作用域

const

  • const 与 let一样作用域都是块级
  • const只用来声明常量
  • const声明的时候必须复制,否则会报错
const obj = {}
obj.name = "sam"

这种情况不会报错,根本原因是obj指向的地址是没变的

数组的解构

const [first, second, third] = [1,2,3]
const [first, second, third, fourth = 4] = [1,2,3]
const [first, ...rest] = [1,2,3,4]

对象的解构

const obj = {name: "xxx", age: 18}
const {name,age} = obj

模板字符串

const param = "world"
const str = `hello,  //可换行
${param}`   //嵌入变量以及script语句
console.log(str)

还一个比较特殊的使用方式是带标签

const  name = "sam"

function tagFn (string, name) {
    console.log(string, name) // 可以在这部分做对字符串的修饰
    return string[0] + name + string[1]
}

const result = tagFn`hi, ${name}.`
console.log(result)

字符串扩展方法

includes()
startsWith()
endsWith()

参数默认值

function foo (a = 1) {
    console.log(a )
}
foo()

剩余参数

function foo (...rest) { //只能用在形参的最后一位 并且只能使用一次
    console.log(rest)
}
foo(1,2,3,4)

展开数组

const arr = [1,2,3]
console.log.apply(console, arr)//两种方式等同
console.log(...arr)

箭头函数

const inc = (n,m) => {
    return n + m
}
console.log(inc(1,2))

箭头函数不会改变this的指向

对象字面量的增强

const bar = "2"
const obj = {
    foo: 1,
    bar,
    fn() {
        console.log("fnfnfnfnfnfn")
    }
}
obj[1+1] = 3
obj.fn()

对象的扩展方法

Object.assign()

const obj1 = {
    a:1,
    b:2
}
const obj2 = {
    a:3,
    c:4
}
const obj = Object.assign(obj1, obj2)
console.log(obj)
console.log(obj === obj1)
//{ a: 3, b: 2, c: 4 }
//true

Object.is()

Object.is(+0 === -0)

Proxy

Proxy在目标对象的外层搭建了一层拦截,外界对目标对象的某些操作必须通过这层拦截

const person = {
    name: "sam",
    age: 18
}
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
    }
})

personProxy.age = 12
personProxy.sex = "man"

我们发现proxyObject.defineProperty()的作用相似,那么两者有什么区别呢?

  • Object.defineProperty()只能监控到对象属性的读写
  • proxy 可监控更多操作例如属性删除,对象方法调用
handle 触发条件
get 读取某个属性
set 写入某个属性
has in 操作符
deleteProperty delete 操作符
getProperty Object.getPropertypeOf()
setProperty Object.setPrototypeOf()
isExtensible Object.isExtensible()
preventExtensions Object.preventExtensions()
getOwnPropertyDescriptor Object.getOwnPropertyDescriptor()
defineProperty Object.defineProperty()
ownKeys Object.keys() 、Object.getOwnPropertyNames()、Object.getOwnPropertySymbols()
apply 调用一个函数
construct 用 new 调用一个函数

对数组监视
本质: 重写数组的操作方法。
proxy监视数组

const list = []

const listProxy = new Proxy(list, {
    set(target, property, value) {
        console.log("push", property, value)
        target[property] = value
        return true
    }
})
listProxy.push(100)

非侵入便可监视

Reflect

Reflect 是一个静态类,使用方式类似Math
Reflect成员方法就是Proxy处理对象的默认实现。
Reflect提供了一套用于操作对象的API,详情见以上表格

const obj = {
    name: "zicoo",
    age: 18
}
// console.log("name" in obj)
console.log(Reflect.has(obj, "name"))
// console.log(delete obj[age])
console.log(Reflect.deleteProperty(obj, "age"))
// console.log(Object.keys(obj))
console.log(Reflect.ownKeys(obj))

Promise

提供了一种更优的异步编程方案
具体可见之前的文章《Promise核心功能从原理到实现

class 类

class Person {
    constructor (name) {
        this.name = name
    }
    say() {
        console.log(`my name is ${this.name}`)
    }
    static create(name) {
        return new Person(name)
    }
}

const zicoo = new Person("zicoo")
zicoo.say()
const sam = Person.create("sam")
sam.say()

class Student extends Person {
    constructor(name, number) {
        super(name)
        this.number = number
    }
    hello() {
        super.say()
        console.log("student say hello")
    }
}
const tom = new Student("tom", 10)
tom.hello()

Set 数据结构

  • 可看做集合
  • Set中数据不重复
const s = new Set();
s.add(1).add(2).add(1)
console.log(s)

//s.forEach()
//for (let i of s)
// s.zie
// s.has(1)
// s.delete(2)
// s.clear()

Set有个常见的场景是用来数组去重

const arr = [1,2,3,1,3,2]
const result = Array.from(new Set(arr))
// const result = [...new Set(arr)]
console.log(result)

Map数据结构

Object类似都是存的键值对,但是Object的key只能为String类型

const obj = {}
obj[true] = 123
obj[123] = 123
obj[{a: 1}] = 123
console.log(Reflect.ownKeys(obj))
//[ '123', 'true', '[object Object]' ]
console.log(obj[{}])
// 123

我们发现真正对象的key是字符串, 并且我们发现这么使用存在的其他问题。
那么Map的出现解决了这些问题

const m = new Map()
const tom = {name: "tom"}
m.set(tom, 90)
// m.get()
// m.delete()
// m.clear()
// m.forEach()

Symbol 数据类型

独一无二的值
最主要的作用是给对象增加一个独一无二的属性

// const obj = {
//     [Symbol("name")]: 123
// }
// console.log(obj)
// 场景  私有成员

const name = Symbol()
const person = {
    [name]: 'zicoo',
    say() {
        console.log(this[name])
    }
}
console.log(person.name)
person.say()

以上就是最简单的使用,那么Symbol的其实使用场景呢

console.log(Symbol("foo") === Symbol("foo"))
console.log(Symbol.for("foo") === Symbol.for("foo"))
//false
//true
console.log(Symbol.for(true) === Symbol.for("true"))
// false       证明会将true 转成字符串

//Symbol 本身有好多方法的标识符
// eg: 
//Symbol.hasInstance
//Symbol.iterator

const obj = {}
console.log(obj.toString())
//[object Object]
const objX = {
    [Symbol.toStringTag] : "XObject"
}
console.log(objX.toString())
//[object XObject]

// 通过 for 无法不按理 objx中的 [Symbol.toStringTag], Object.keys 也不可以

console.log(Object.getOwnPropertySymbols(objX))
// [ Symbol(Symbol.toStringTag) ]

for ... of 循环

可遍历所有数据类型

基本用法

// 遍历数组
const arr = [100,200,300,400]
for (const item of arr) { 
    if (item > 100) {
        break
    }
    console.log(item)
}
// 遍历map
const m = new Map()
m.set("foo", 123)
m.set("bar", 234)
for(const [key,value] of m) {
    console.log(key, value)
}

当我们遍历数组时会出现什么情况

const obj = {name: "sam"}
for (const item of obj) {
    console.log(item)
}
//obj is not iterable

问题来了报错了! 其实 数据结构的 Iterable接口是使用 for ... of 的前提

迭代器

image.png

我们发现无论Array``Set``Map_proto_原型上都有Symbol(Symbol.iterator)这个方法。
image.png

我们发现这个iterator的作用相当于一个指针,每调用一次next(),都会将value指向下一个值,并且done来区分是不是遍历完成

const set = new Set(["foo","bar","baz"])
const iterator = set[Symbol.iterator]()
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())

//{ value: 'foo', done: false }
//{ value: 'bar', done: false }
//{ value: 'baz', done: false }
//{ value: undefined, done: true }

那我们简单实现一下可迭代接口Iterable

// 实现可迭代接口(Iterable)

const obj = {
    store: ["foo", "bar", "baz"],
    [Symbol.iterator]: function() { // Iterable
        let index = 0
        const self = this
        return {
            next: function() {  // Iterator
                return  {   //IterationResult
                    value: self.store[index], 
                    done: index++ >= self.store.length
                }
            }
        }
    }
}

for (const item of obj) {
    console.log(item)
}

生成器

function * foo() {
    console.log("111")
    yield 100
    console.log("222")
    yield 200
    console.log("333")
    yield 300
}

const result = foo()
console.log(result.next())
console.log(result.next())
console.log(result.next())
console.log(result.next())



// 使用generator 改造 iterator 方法

const obj = {
    store: ["foo", "bar", "baz"],
    [Symbol.iterator]: function * () { // Iterable
        for(const item of obj.store) {
            yield item
        }
    }
}

for (const item of obj) {
    console.log(item)
}

它还有一个很重要的使用场景就是 异步编程, 可见之前的文章《异步编程(Promise、Generator、Async与Await)

ES Modules

后续有详细介绍。略

ES2016

  • Array.propotype.includes
  • 指数运算 eg: Math.pow(2, 10) === 2 ** 10

ES2017

  • Object.vaules: 返回所有值的数组
  • Object.entries: 返回所有键值对数组
  • Object.getOwnPropertyDescriptors: 获取所有属性 eg: get() set()
  • String.prototype.padStart/String.prototype.padEnd: 填充字符串前面或后面
  • Async/Await
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,386评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,142评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,704评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,702评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,716评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,573评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,314评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,230评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,680评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,873评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,991评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,706评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,329评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,910评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,038评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,158评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,941评论 2 355

推荐阅读更多精彩内容