9月抽空从新回顾了下ES6全部知识点,整个回顾过程既惊喜又感慨,感慨开发这么久好像真的没有好好的静下心去读一本好的书,大多状况下只是在使用的时候用到了,不熟悉或者感兴趣再去蜻蜓点水一通,感慨之余也发现了一些自身的的问题,知识体系仍是不够丰富、扎实,一句话:有空多读书总没错,好了不闲扯了,下面咱们步入正题
现在前端知识突飞猛进,越是晚入门小伙伴,不少基础层面的东西,接触的真的是少之又少,各类前端框架层粗不穷Vue
、React
、Ng
这三大带有里程碑意义的框架Api
我想看的这么文字的盆友应该都有接触,基础的Api
使用应该是没有什么难度,可是在遇到问题,解决问题、以及在原有组件以及自我封装组件,搭建框架过程总会遇到一些莫名其妙的问题,解决这个问题,看源码
是大众都知道的一些方法,但我的认为这是一种进阶的方法,新手入门建议能够先了解我们JavaScript的发展史
能够比较轻松的认识咱们整个技术体系的发展和将来方向,避免一些认知错误
互联网早期javascript
“主机-网站-浏览器”
构成的Web系统,这标志BS架构
的网站应用软件的开端,也是前端工程的开端。这个时候前端只是简单的Html静态文本
简单到基本动画都没有javascript
的诞生:1995年,NetScape(网景)公司的工程师Brendan Eich设计了javascript脚本语言,并集成到了navigator2.0版本中。随后微软也意识到了javascript的潜力,并模仿开发VBScript和JScript应用到了IE中,这直接开启了NetScape和微软的浏览器竞争
。因为微软的IE集成在windows操做系统上的优点,NetScape的navigator很快在浏览器市场上落于下风。因而他们把javascript提交到了ECMA
,推进制订了ECMAScript标准
,成功实现了javascript的标准国际化。虽然第一次浏览器战争最后IE大胜Navigator,可是NetScape的javascript主导了W3C的官方标准。互联网发展期前端
javascript推进
,前端页面开始走向动态化,那时流行的跑马灯、悬浮广告
基本是各大门户网站的标配,页面基本都是经过PHP、JSP、ASP
动态渲染出来,这也直接致使后端代码的逻辑臃肿,服务端为了更好的管理代码,应运而生MVC模式
reload
操做,无论交互仍是性能,都是不值当的 "这个问题直到谷歌在04年应用Ajax技术开发的Gmail和谷歌地图的发布,才获得了解决。" 这背后的秘密就是Ajax技术中实现的异步HTTP请求
,这让页面无需刷新就能够发起HTTP请求,用户也不用专门等待请求的响应,而是能够继续网页的浏览或操做。Ajax开启了web2.0的时代
Dojo、Mooltools、YUIExtJS、jQuery
等前端兼容框架,其中jQuery应用最为普遍。这些框架中不知道你们用过几个Web Forms 2.0
、Web Applications 1.0
等规章最后整合成HTML五、各大浏览器都在为适配浏览器不断改善本身的浏览器事件循环的异步I/O框架-Node.js
。Node.js使得前端开发人员能够利用javascript开发服务器端程序。很快,大量的Node.js使用者就建构了一个用NPM包管理工具管理的Node.js生态系统。node.js也能开发跨平台的桌面应用
Node 衍生出的
NPM
包管理工具为整个前端社区提供了一个规范良好的平台
互联网进击java
jQuery Mobile、Sencha Touch、Framework7
如鱼得水;Hybrid技术指的是利用Web开发技术,调用Native相关的API,实现移动与Web两者的有机结合,既能利用Web开发周期短的优点,又能为用户提供Native的体验。ECMAScript 6.0
发布,该版本增长了不少新的语法,极大的拓展了javascript的开发潜力;一些陈旧的浏览器能够经过Babel进行降级转义适配,ES6将JavaScript推向了另外一个历史转折点React、Vue、Anjular
三大框架利用js集合自身优点,彻底实现了目前的先后端分离的开发模式;开发体系发展到:NPM和Yarn为表明的包管理工具;ES6及Babel和TypeScript构成的脚本体系;HTML5;CSS3和相应的处理技术;React、Vue、Anjular为表明的框架;Webpack为表明的打包工具;Node.js为基础的Express和KOA后端框架;Hybrid技术。权重自上到下node
通常走到草案阶段基本能够在正式标准中看到,Tc39可查看各提案es6
Tips:
这也是在babel中配置presets
的来由(可能咱们使用了一些仍然在草案甚至征求意见阶段的API)的时候需babel垫片web
// 基本格式 { "presets":[] "plugins":[] }
不一样环境支持不一样的转换方法正则表达式
通常咱们使用的脚手架默认配置好,可是咱们须要配置的什么意思,以及为何要配置编程
改写require
命令,为每一个require引入的资源进行Babel转义windows
Babel仅会转换新的语法,可是已有的Api中的Iterator、Generator、Set、Map、Proxy、Reflect、Symbol、Promise
是须要用这个垫片处理后端
暴露出Babel的Api,进行特殊操做
基础篇咱们主要从es6中添加的一些命令,以及对已有数据类型拓展的汇总
特性以下
var
的块级做用域// 下面这块很好的体现了`块级做用域` var a = []; for (var i = 0; i < 10; i++) { a[i] = function () { console.log(i); }; } a[6](); // 10 var a = []; for (let i = 0; i < 10; i++) { a[i] = function () { console.log(i); }; } a[6](); // 6
特殊说明下暂时性死区的概念
,就是:在块中,let 声明变量以前都是不能使用的
const 和 let 特性基本一致,区别于,使用const定义的是显式的常量
,一经定义,不可更改
es5以前是有全局做用域、函数做用域
,es6推出的块级做用域但凡一个{}
就是一个做用域;
外层块级做用域能在内层使用,内层定义在外层访问不到
Tips:解构赋值
对应的还有拓展操做符
,解构不成功则为undefined;一看就懂,一用代码就简洁
ES6 容许按照必定模式,从数组和对象中提取值,对变量进行赋值(Iterator类型),这被称为解构(Destructuring)
let [foo, [[bar], baz]] = [1, [[2], 3]]; foo // 1 bar // 2 baz // 3 let [ , , third] = ["foo", "bar", "baz"]; third // "baz" let [x, , y] = [1, 2, 3]; x // 1 y // 3 let [head, ...tail] = [1, 2, 3, 4]; head // 1 tail // [2, 3, 4] let [x, y, ...z] = ['a']; x // "a" y // undefined z // []
let { bar, foo } = { foo: 'aaa', bar: 'bbb' }; foo // "aaa" bar // "bbb" let { baz } = { foo: 'aaa', bar: 'bbb' }; baz // undefined
let obj = { p: [ 'Hello', { y: 'World' } ] }; let { p: [x, { y }] } = obj; x // "Hello" y // "World"
// 设置默认值 function move({x = 0, y = 0} = {}) { return [x, y]; } move({x: 3, y: 8}); // [3, 8] move({x: 3}); // [3, 0] move({}); // [0, 0] move(); // [0, 0]
注:
还有字符串解构(转换成数组)、字符/布尔解构(转换成对象),解构遵循的宗旨是模式、数据格式一致,便可解构,解构失败undefined;进行赋值的过程,无论是数组仍是对象解构均可以设置默认值
;圆括号()
只能在赋值语句的非模式部分便可
用途优点
函数中直接返回多个值
let [a,b,c] = fn()
字符串中改动仍是蛮多的有添加Unicode表示
、JSON.stringify()适配非UTF-8编码
,下面介绍平常开发实用改变
for of
遍历器(es6新增)仅对拥有Iterator接口的适配
`` 反引号 节省咱们字符串拼接的痛点
let str1 = 'There are <b>' + basket.count + '</b> ' + 'items in your basket, '; let str2 = `There arebasket.count ${variable}</b>items in your basket, `;
上面字符串拼接自上到下的升级,同时也可使用${}
动态注入变量
<%...%>
中放置JavaScript代码,以下
let template = ` <ul> <% for(let i=0; i < data.supplies.length; i++) { %> <li><%= data.supplies[i] %></li> <% } %> </ul> `;
能够利用字符串匹配<%...%>
封装template转换函数
0xFFFF
的字符codePointAt()
charAt() // UTF-8 codePointAt() // UTF-16
includes(), startsWith(), endsWith()
includes():返回布尔值,表示是否找到了参数字符串。 startsWith():返回布尔值,表示参数字符串是否在原字符串的头部。 endsWith():返回布尔值,表示参数字符串是否在原字符串的尾部。
0b(0B)二进制;0o(0O)八进制
右结合即右边先运算
)**
、**=
操做符 进行指数运算
//指数拓展符 let a = 2; a ** 2 **4 // 2 * (2 * 4) a **= 3 // a = 2 * 2 * 2
...
将一个数组转成用逗号分隔的参数排列
console.log(1,2 ...[3,4]) // 1,2,3,4
Array.form()
// 将类数组转换成数组Array.of()
// 用于将一组值,转换为数组-1
返回bool值
flat()、flatMap()
// 扯平数组
[1, 2, , [4, 5]].flat() //[1, 2, 4, 5] 默认拉平一层,参数num、Infinity自定义拉平层数目 // flatMap() 至关于先进行Map再进行flat操做 // 至关于 [[2, 4], [3, 6], [4, 8]].flat() [2, 3, 4].flatMap((x) => [x, x * 2]) // [2, 4, 3, 6, 4, 8]
ES6中明确将空位装换成undefined;数组实例方法、map、扩展操做符存在差别
总之避免空位的出现是很必要的
对象中的属性、方法只要key、value名字一致,便可简写成一个以下
// 属性 let a = 'a'; let b = 'b'; let obj = { a, b } // 等同于 let a = 'a'; let b = 'b'; let obj = { a:a, b:b } // 方法 let obj = { a, b, c(){ console.log('这是一个对象方法') } } // 等同于 let obj = { a, b, c:function(){ console.log('这是一个对象方法') } }
let propKey = 'foo'; let obj = { [propKey]: true, ['a' + 'bc']: 123 }; // 须要注意的是若是属性名是一个对象默认会装换成[object Object]
// 合并对象 let ab = { ...a, ...b }; // 等同于 let ab = Object.assign({}, a, b); // 同数组拓展操做符后可跟表达式 如: const obj = { ...(x > 1 ? {a: 1} : {}), b: 2, };
每一个属性都有一个描述对象,用来控制属性的行为Object.getOwnPropertyDescriptor(obj,'key')
可获取对应属性的描述行为,
描述中enumerable
标识是否可遍历
总之:操做中引入继承的属性会让问题复杂化,大多数时候,咱们只关心对象自身的属性。因此,尽可能不要用for...in循环,而用Object.keys()代替
Object.getOwnPropertyNames()
Object.getOwnPropertySymbols()
Reflect.ownKeys()
Object.is()
==
或者===
,前者会强制类型转换,后者NAN不等于自身,并+0等于-0
,此方法就解决了上述问题Object.assign()
第一个参数就是目标对象
,只会处理可枚举的数据类型,并Symbol值属性也会被拷贝Object.getOwnPropertyDescriptors()
原型操做方法替代__proto__
对象键值对获取
Object.fromEntries()
// Object.fromEntries()方法是Object.entries()的逆操做,用于将一个键值对数组转为对象遍历规则以下:
指向当前对象的原型对象。
const proto = { x: 'hello', foo() { console.log(this.x); }, }; const obj = { x: 'world', foo() { super.foo(); } } Object.setPrototypeOf(obj, proto); obj.foo() // "world"
上面代码中,super.foo指向原型对象proto的foo方法,可是绑定的this却仍是当前对象obj,所以输出的就是world。
进阶篇,咱们主要对新增的Symbol、ArrayBuffer
以及Set和Map
数据结构介绍、Promise 到 async
的演变和差别,异步遍历的思想,以及Class、Module的使用
;
ES6引入的新的数据类型,保证了数据的独一无二的特性,能够用来标识对象的额惟一key值
// 新建类型 let a = Symbol() // 添加描述(用于标识Symbol值) let a = Symbol('描述文件')
特性:
方法:
Set 数据结构。它相似于数组,可是成员的值都是惟一的,没有重复的值。
特性:
去重
属性
方法
和 Set
的区别
不进入垃圾回收机制
Map 的数据类型相似对象,可是对象的key值能够是任意类型的Map:值-值
,不一样于传统Object:字符串-值
属性
属性
方法
和Map的结构相似
和Map
的差别
用途
在 DOM 对象上保存相关数据
数据缓存
const cache = new WeakMap();function countOwnKeys(obj) { if (cache.has(obj)) { console.log('Cached'); return cache.get(obj); } else { console.log('Computed'); const count = Object.keys(obj).length; cache.set(obj, count); return count; }}
操做二进制数据的一个接口。早就存在,属于独立的规格(2011 年 2 月发布),ES6 将它们归入了 ECMAScript 规格,而且增长了新的方法。它们都是以数组的语法处理二进制数据,因此统称为
二进制数组
注意:
二进制数组并非真正的数组,而是相似数组的对象。
属性类型
数据存放规则
规格定义区别
存储二进制数据的一段内存,不能直接进行读写,须要经过视图进行操做
new ArrayBuffer(32) //分配一个32位字节的内存
- byteLength 返回分配区域的字节长度
- slice() 操做ArrayBuffer 对象 生成一个新的内存地址 - isView() bool值返回是不是TypedArray视图实例(是不是一个视图)
经过构造方法生成 视图
注:
存在溢出问题
TypedArray(buffer, byteOffset=0, length?)
- buffer // 返回 ArrayBuffer 对象 - byteLength // 占据内存长度(成员长度) - byteOffset // 视图从ArrayBuffer中开始位置 - length // 字节长度
- set() // 复制数组 - subarray() // 返回新的视图 - slice() // 返回新的视图 - of() // 用于将参数转为一个TypedArray实例 - from() // from接受一个可遍历的数据结构(好比数组)做为参数,返回一个基于这个结构的TypedArray实例。 可有两个参数,第二个参数是fun
- buffer // 返回 ArrayBuffer 对象 - byteLength // 占据内存长度(成员长度) - byteOffset // 视图从ArrayBuffer中开始位置
Canvas
读取二进制像素数据File
new FileReader() 读取 ArrayBuffer对象Promise 异步编程的解决方案,社区的提案, async 结局了Promise的回调地狱
有 padding(进行中)、fulfilled(成功)、rejected(失败)三种状态,状态已经改变就并不会变更
方法
any()
allSettled()
注意:
Async
async 只是对 promise 的写法上的一种语法糖
async
: 函数 返回一个Promise对象,return 返回Promise的结果
await: 后面默认是一个Promise对象
try catch(): 捕获错误
解决异步模块加载的问题
将传统
实例对象经过构造方法生成的过程放到class的语法糖中, 以下例
// 传统方法 function Point(x, y) { this.x = x; this.y = y; } Point.prototype.toString = function () { return '(' + this.x + ', ' + this.y + ')'; }; var p = new Point(1, 2); // class 方法 class Point { constructor(x, y) { this.x = x; this.y = y; } toString() { return '(' + this.x + ', ' + this.y + ')'; } }
差别点:
严格模式、不存在变量提高、this指向
与 ES5 同样,在“类”的内部可使用get和set关键字,对某个属性设置存值函数和取值函数,拦截该属性的存取行为
静态方法不会被继承
//现有 class Foo { } Foo.prop = 1; Foo.prop // 1 // 提案 Static prop = 1
私有方法/私有属性
私有方法只能经过命名规则或者Symbol数据类型定义,私有属性有个提案使用的是
#
ES6 提出的Moduel
是前端发展过程当中演变从CommonJs
递进
循环加载问题