写在前面
本系列为在我读完阮一峰老师的《ES6标准入门》第二版之后,所做的阅读笔记的整理。
许多初学ES6, 同时和我一样初次阅读阮老师的这本书的时候, 读第一遍会越发的困惑, 因为阮老师上面说的很多的定义,方法,之前都是没有见过的, 读到后面才发现, 哦~原来是这样.
有一句话叫做”大神的世界我们不懂”, 所以我在初读第一遍《ES6标准入门》这本书的时候,也是踩了不少坑,读书的时候查阅了不少的资料.
所以,在这一系列的笔记教程中,我会从一个初学者的角度,向您讲述ES6的相关知识,在后面介绍的知识我会尽量不提前用,即使提前使用,也会同时做好标注,避免了阅读时各种查阅资料的烦恼.
系列博客将采用一个一个的样例,来说明书中的精华部分(当然,这只是我认为的),同时引导新手,快速入门ES6,并逐步将其投入到生产实践中。
同时,在阅读前也提醒您, 为了系统连贯性的学习ES6的基础知识,建议您从我的博客第一章开始阅读,当然,如果您对对应的知识已经有所了解,那么可以跳转到任意章节阅读,每一篇博客名中均有介绍该博客中涉及到的ES6的内容.
阮一峰老师的这本书是开源的,在其官方博客就可以下载到,但是我强烈建议大家去购买一本书, 一是方便自己查阅ES6中新增的众多API, 二也是表达一下对大神的敬仰.
Symbol
在ES6之前,当我们命名变量的时候,总是会担心,如果我把之前的变量改写了该怎么办呢
那么,现在ES6推出了继 null undefined string number boolean 这五中数据类型以外的第六种简单数据类型symbol
推出的主要目的在于,解决属性名冲突的问题
1 | let s = Symbol() |
symbol一般会传入一个字符串作为不同symbol实例的描述,方便进行区分
1 | let a = Symbol('a') |
我们查看控制台的打印结果,会发现symbol的值是以红色显示的,而普通字符串则以灰色显示
symbol的几个特征
symbol函数的参数只表示对当前symbol值的表示,因此相同参数的symbol函数的返回值是不相等的
symbol无法与其他类型值进行运算,否则会报错
symbol可以转为布尔值,但是无法转为数值
symbol作为变量时,不能使用点运算符
因为symbol是一个特殊的基本类型,因此使用点运算符是不行的,这样会被理解为是在使用字符串作为变量名称
那么这个时候,可以使用方括号加上symbol名称的方式,来调取这个symbol值
1 | var mySymbol = Symbol('aaa') |
作为属性名的symbol
symbol作为属性名,该属性不会出现在for…in for…of 循环中,也不会被Object.keys()/Object.getOwnPropertyNames()返回
但它也不是私有属性,有一个Object.getOwnPropertSymbols方法可以获取指定对象的所有symbol属性名
1 | var obj = {} |
由以上可知,使用getOwnPropertySymbols() 方法可以得到对应的symbol值,而getOwnPropertyNames() 是得不到对应的symbol值的
Reflect.ownKeys(obj)
ES6中定义了一个新的API Reflect.ownKeys(obj) 可以返回所有类型的键名称,包括常规键名和symbol键名
1 | let obj = { |
Symbol.for() 和 Symbol.keyFor()
有时候我们希望重新使用同一个symbol值, Symbol.for方法可以做到这一点,它接收一个字符串作为参数,然后搜索没有以该字符串作为名称的Symbol值. 如果有,就返回这个Symbol值, 否则就新建一个以该字符串为名称的Symbol值
1 | let s1 = Symbol.for('foo') |
上面的代码中,虽然s1和s2都是Symbol值,但是它们都是同一个Symbol.for生成的,所以是同一个值
Symbol()和Symbol.for()两种写法,都会生成新的Symbol,但是后者会被登记在全局环境中供 搜索,但是前者不会
1 | console.log(Symbol.for('bar') === Symbol.for('bar')) // true |
上面的代码中,由于Symbol()没有登记机制,所以每次调用都会返回不同的值
Symbol.keyFor()方法用于返回一个已经登记的Symbol类型值的key
1 | let s3 = Symbol.for('aaa') |
Proxy概述
proxy 用于修改某些操作的默认行为,等同于在语言层面做出修改,所以属于一种元编程, 即对编程语言进行编程
Proxy 可以理解为在目标对象前架设一个拦截层,外界对该对象的访问都必须先通过这一层拦截,因此提供了一钟机制来对外界的访问进行过滤和改写
所以,Proxy 也可以理解为一种代理器
1 | let obj = new Proxy({}, { |
上面的代码说明, proxy实际上重载了点运算符, 即用自己的定义覆盖了语言的原始定义
一个小技巧是,可以将Proxy对象设置到object.proxy属性,从而可以在object对象上调用
1 | var object = { |
那么我们就可以直接定义一个proxy对象,并在需要的时候使用Object.create() 进行对象的创建即可
1 | var proxy = new Proxy({}, { |
Reflect
Reflect对象和Proxy对象一样, 也是ES6为了操作对象而提供的新api
reflect对象的设计目的主要有以下几个
将object对象的一些明显属于语言层面的方法放到reflect对象上. 现阶段, 某些方法同时在object和reflect对象上部署, 未来的新方法将只部署在reflect对象上
修改某些object方法的返回结果, 让其变得更加合理, 如:
Object.defineProperty(obj, name, desc)
在无法定义属性时会抛出一个错误, 而Reflect.defineProperty(obj, name, desc)
则会返回一个false
让Object操作都变成函数行为, 某些object操作是命令式, 比如
name in obj
和delete obj[name]
, 而Reflect.has(obj, name)
和Reflect.deleteProperty(obj, name)让他们变成了函数行为
Reflect对象的方法和Proxy对象的方法一一对应, 只要是Proxy对象的方法, 就能在Reflect对象上找到相应的方法. 也就是说, 不管Proxy怎么修改默认行为, 你总可以在Reflect上获取默认行为
1 | Proxy(target, { |
上面的代码中,proxy方法拦截了target对象的属性赋值行为, 它采用Reflect.set
方法赋值给对象的属性, 然后再部署额外的功能.
(完)