ES6 ECMAScript 6.0(以下简称 ES6)是 JavaScript 语言的下一代标准,已经在 2015 年 6 月正式发布了。它的目标,是使得 JavaScript 语言可以用来编写复杂的大型应用程序,成为企业级开发语言。
基本数据类型 基本类型:string, number, boolean, null, undefined, symbol, bigint。它们存储的是值本身。 引用类型:Object。所有非基本类型都属于 Object 类型,包括 Array, Function, Date, Map, Set 等。它们存储的是对内存中一个对象的引用(地址)。
Map vs Object:
Map可使用任意类型作为键 Object只能用字符串和symbol
查找键的时间复杂度是O(1)与Object相同 但Object有涉及原型、访问器属性历史包袱 Map在大规模数据下有性能上的稳定性(Object存在隐性查找模式切换)
模块化 export require是CommonJS规范的方法,es6 引入了import ,可以将模块中的对象部分引入,以减少开销,或者使用import as objName from 引入文件所有对象 CommonJS vs ES Modules:*nodejs是默认使用CommonJS的 ,其表现可见express的服务中,如”module.exports = AssetService;”以及”var AssetService = require(‘./AssetService’)”。而es6中用”import common from ‘@myRepo/core’”和”export ..” 更多了解NodeJS Docs
Caution: the semicolon at the end of the import is mandatory!
1 2 3 4 export default { a:100 }
1 2 3 import util1 from './util1.js' console .log(util1)
动态引入
1 2 3 4 5 6 import ('/modules/my-module.js' ) .then((module ) => { }); let module = await import ('/modules/my-module.js' );
见MDN:import 据说动态import的模块在打包时会自动分割,见React Docs: 代码分割
关于声明 >
let 代替 var. 同一变量不能重复使用let声明, 否则报错
const是常量,区别于只读
但是可以用Object.freeze()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 function freezeObj ( ) { "use strict" ; const MATH_CONSTANTS = { PI: 3.14 }; Object .freeze(MATH_CONSTANTS) try { MATH_CONSTANTS.PI = 99 ; } catch ( ex ) { console .log(ex); } return MATH_CONSTANTS.PI; } const PI = freezeObj();
Object.assign() >
将所有可枚举属性的值从一个或多个源对象复制到目标对象 Object.assign(target, …sources)
1 2 3 4 const target = { a : 1 , b : 2 };const source = { b : 4 , c : 5 };const returnedTarget = Object .assign(target, source);
用法用途
浅拷贝 cloneObj = Object.assign({}, …sources)
覆盖目标同名属性
合并数组 实际上是覆盖序号属性值 即Object.assign([1,2,3], [4,5]) // [4,5,3]
箭头函数表达式 1 2 3 const squaredIntegers = arr.filter(item => { return Math .floor(item)===item&&item>0 ; }).map(item =>Math .pow(item, 2 ))
箭头表达式牵扯到的一个知识点是“箭头表达式不会创建this” 需知javascript this是区分运行环境的标记,见 阮一峰 JavaScript 的 this 原理 ,箭头表达式继承外层函数运行环境。
QQs按:创建/生成this的说法只是方便记忆 事实上 this 是运行时调用的东西 箭头函数没有自己的this绑定 其运行时this永远指向到定义箭头函数的所在(即所谓词法作用域)的this
关于省略,函数体只有一个return语句时,可省略return关键字和花括号
1 2 func = x => { return x+1 ;} func = x => (x+1 )
剩余参数运算符(Rest Operator) 使用Rest Operator定义参数数量可变的函数,参数将存入Rest Operator指定的变量指代的数组中
1 2 3 4 function howMany (...args ) { return "You have passed " + args.length + " arguments." ; } console .log(howMany(0 , 1 , 2 ));
1 2 3 4 5 6 7 8 const sum = (function ( ) { "use strict" ; return function sum (...args ) { return args.reduce((a, b ) => a + b, 0 ); }; })(); console .log(sum(1 , 2 , 3 ));
回顾下归并方法reduce,array.reduce(callback,[, initialValue]),callback接受以下参数:previousValue,前一次调用回调函数的返回值;currentValue当前处理的数组元素,currentIndex可选,当前数组元素下标;array可选,调用reduce()方法的数组。initialValue可选,作为第一次调用callback方法的previousValue参数
1 2 3 4 5 6 var arr = [6 , 89 , 3 , 45 ];var maximus = Math .max.apply(null , arr); maximus = Math .max(...arr); arr0 = [...arr] console .log(arr0==arr)
异步归并方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 const groupedMeshes = await meshes.reduce(async (accP, mesh, index) => { const acc = await accP; const group = isUpper(mesh) ? acc[0 ]: acc[1 ]; if (group.length==0 ){ group.push(mesh) }else { const newMesh = compute(mesh, group[0 ]) group.push(newMesh) } return Promise .resolve(acc) }, Promise .resolve([ new Array <IMesh>(), new Array <IMesh>() ]))
上述代码的需求是,将一个集合中的Mesh进行分组运算,分组依据是Upper or Lower,组内运算时以第一个Mesh为基准,调整组内其他Mesh
解构赋值(Destructuring Assignment) 1 2 var voxel = {x : 3.6 , y : 7.4 , z : 6.54 };const { x, y, z } = voxel;
或者将部分属性 voxel.x, voxel.y 存入指定变量 a, b
1 const { x : a, y : b} = voxel
分离多余的变量
1 2 let postData = Object .assign({ extraAttr :'extra' }, dto);let { extraAttr, ...entity } = postData;
嵌套对象(nested objects)
1 2 3 4 5 6 7 8 9 10 11 const tree = { text:'A' , value:0 , parentNode:{ text:'Root' , value:-1 } } const {parentNode :{value :RootVal}} = tree;console .log(RootVal)
数组
1 2 3 4 const [a, b,,, c] = [1 , 2 , 3 , 4 , 5 , 6 ];console .log(a, b, c); const [begining,...rest] = [1 , 2 , 3 , 4 , 5 , 6 ];
交换值
函数传参
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 const stats = { max: 56.78 , standard_deviation: 4.34 , median: 34.54 , mode: 23.87 , min: -0.75 , average: 35.85 }; const half = (function ( ) { "use strict" ; return function half ({max,min} ) { return (max + min) / 2.0 ; }; })(); console .log(half(stats));
函数返回多个值
1 2 3 4 func = () => { return [1 ,2 ] } const [x, y] = func()
类似python中常用的返回多个结果,需要在调用函数时清楚的知道其返回的结果结构 实际上可能并不利于维护
ES9 剩余运算符可应用于解构语法
幂运算符 1 2 3 4 5 6 2 **3 Math .pow(2 ,3 )2 **3 **2 Math .pow(2 , Math .pow(3 ,2 ))-2 **3
Math函数扩展 常用的Math.sigh返回正负符号(-1,0,1) Math.trunc直接移除小数部分
字符串模块(Template Literals) String.prototype.format
1 2 3 4 5 ƒ (){ var e=arguments ; return !!this &&this .replace(/\{(\d+)\}/g ,function (t,n ) {return e[n]?e[n]:t}) }
`xxx${str}xxx`模板
1 2 3 resultDisplayArray = arr.map(item => { return `<li class="text-warning">${item} </li>` });
标签函数
1 2 function tag (strings, ...keys ) {}tag`string1${key1} string24{key2}`
将模板中的字符串和变量分别再拎出来
简化声明 1 2 3 4 5 6 const person = { name: "Taylor" , sayHello: function ( ) { return `Hello! My name is ${this .name} .` ; } };
可写作
1 2 3 4 5 6 const person = { name: "Taylor" , sayHello ( ) { return `Hello! My name is ${this .name} .` ; } };
class 以及 get set 以及super 1 2 3 4 5 6 7 8 9 10 11 12 13 class Book { constructor (author ) { this ._author = author; } get writer (){ return this ._author; } set writer (updatedAuthor ){ this ._author = updatedAuthor; } }
Promise >
区别于回调函数方式的异步编程方案, ES6将其写入语言标准。
所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。
Promise对象的状态 pending(进行中)、fulfilled(已成功)和rejected(已失败)只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 function loadImageAsync (url ) { return new Promise (function (resolve, reject ) { const image = new Image(); image.onload = function ( ) { resolve(image); }; image.onerror = function ( ) { reject(new Error ('Could not load image at ' + url)); }; image.src = url; }); }
加载图片的异步过程,成功或失败时触发相应的事件(load,error),resolve和reject刚好对应作为事件响应方法
Promise 链式调用 Promise可以链式调用是因为then()返回也是一个Promise,见手写Promise 注意是then(onFulfilled, onRejected)如果缺省onFulfilled,则第一个Promise中的结果不做任何保留,意义在于过程,如果onFulfilled=(result)=>{ return newPromise(…)} 即将第一个Promise过程得到的result传入newPromise newPromise作为onFulfilled,resolve(newPromise)就将数据传递给了下一个过程,依次类推可以依次执行不同的异步操作
Promise().then(…)的第二个参数可以捕捉异常,和链式调用最后的catch有和区别?
catch只是一个语法糖而己 还是通过then 来处理的,大概如下所示
1 2 3 Promise .prototype.catch = function (fn ) { return this .then(null ,fn); }
generator 以function*定义的生成器,与function的区别是除了return,其执行期间可以yield‘返回’多次
1 2 3 4 5 function * foo (x ) { yield x + 1 ; yield x + 2 ; return x + 3 ; }
斐波那契生成器
1 2 3 4 5 6 7 8 9 10 11 12 13 function * fib (max ) { var t, a = 0 , b = 1 , n = 0 ; while (n < max) { yield a; [a, b] = [b, a + b]; n ++; } return ; }
fib(5)返回一个generator对象console输出形如fib {[[GeneratorStatus]]: “suspended”, [[GeneratorReceiver]]: Window} 调用generator对象的next方法迭代
1 2 3 4 5 6 7 var f = fib(5 );f.next(); f.next(); f.next(); f.next(); f.next(); f.next();
也可以var x of fib(5)进行迭代,x即value generator似乎是为了状态管理而生的工具,所谓状态管理,因为其表象是一步接一步(next)来的,后面步骤的结果有可能需要依赖前面一步的状态(比如成功或失败,抑或current result)async await是generator的语法糖
关于迭代器和可迭代对象 迭代器是使用next()方法实现迭代器协议(lterator protocal)的任意对象,如Array迭代器 可以使用for of迭代的对象即可迭代对象
Proxy 和 Reflect 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 const user = { name:'QQs' age:18 } const proxyUser = new Proxy (user, { set (target, property, value, receiver ) { Reflect .set(target, property, value, receiver) } get (target, property, receiver ) { return Reflect .get(target, property, receiver) } })
在ES6之前 属性get set添加响应式逻辑需要遍历原对象 调用Object.defineProperty定义getter setter
ES7 Array.protorype.includes array.includes(x) 相当于 array.indexOf(x) ES6中已添加了String.prototype.includes
类似的还有startsWith endsWith 参数接受偏移量
1 2 3 4 5 const str = 'Hello World' str.include('W' ) str.indexOf('W' )>=0 str.starsWith('World' , 6 ) str.indexOf('World' )===6
String.prototype.repeat
指数运算符 **
js引擎(V8)对**的实现与Math.pow的运算结果是会有差别的
ES8 字符串填充 以指定字符/字符串/函数方式, 在首或尾填充字符串至特定长度
1 2 3 str.padStart(targetLength [, padString]) str.padEnd(targetLength [, padString])
Object.values, Object.entries 获取对象属性值的集合
1 2 const obj = { x : 'xxx' , y : 1 };Object .values(obj);
其实现是for in,因此obj也可以是Array或string,其输出结果也是遍历逐个下标组成的集合。
获取对象键值对的集合
1 2 const obj = { x : 'xxx' , y : 1 };Object .entries(obj);
async, await async(asynchronous)异步
await(asynchronous wait)等待异步结果 下面的代码结构被称作callback hell 其需求是从input.xml文件中读取action,如果action=token,则读取注册表,验证token时效,其中读文件,xml转json,读注册表均为异步操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 (function ( ) { fs.readfile('input.xml' ,(err,data )=> { if (err){ console .error(err) }else { regedit.list('HKCU\Software\QQSTEST\',(err,data)=>{ if(err){ console.error(err) }else{ xmlParser.parseString(data,(err,data)=>{ if(err){ console.error(err) }else{ done(data) } }) } }) } }) })()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 function readfileAsync (filepath ) { return new Promise ((resolve,reject )=> { fs.readFile(filepath,(err,data )=> { if (err){ reject(err) }else { resolve(data) } }) }) } (async function ( ) { var fileData = '' ; await readfileAsync('input.xml).then(data=>{ fileData=data; },err=>{ console.log(err) }) if(!fileData) return; await readRegEditAsync(' ') })()
在async声明的function内使用await, 执行时等待promise对象的结果,完成其resolve或reject操作后向下执行。
Caution! 在forEach中加async await不能阻塞循环,事实上forEach回调函数无法跳出循环,不要在forEach里面使用async-await、break、return,在有相关需求的场景下使用for循环语法Q160解析
见下文 ES 9 异步迭代
ES9 异步迭代 1 2 3 4 5 async function process (array ) { for await (let i of array) { doSomething(i); } }
Promise.finally 1 2 3 iPromise.then(do_sth1).then(do_sth2) .catch(err_handle) .finally(complete_handle)
在正则表达式中命名模式匹配结果 模式指使用()封装的规则,在ES9中可以用(?\)的方式封装,在之后的js逻辑中,可以使用命名变量
1 2 3 4 const reDate = /(?<year>[0-9]{4})-(?<month>[0-9]{2})-(?<day>[0-9]{2})/ , d = '2018-04-30' , usDate = d.replace(reDate, '$<month>-$<day>-$<year>' );
正则表达式断言和反向断言 见正则表达式
正则表达式dotAll 正则表达式中点.匹配除回车外的任何单字符,标记s改变这种行为,使之匹配包含终止符的所有字符,例
1 2 /hello.world/.test('hello\nworld' ); /hello.world/s.test('hello\nworld' );
正则表达式 Unicode 转义 转义语法\p{…}
1 2 const reGreekSymbol = /\p{Script=Greek}/u ;reGreekSymbol.test('π' );
ES10 Ecmascript2025(ES16) Array.prototype.flat, flatMap 可指定层次数(允许Infinity)迭代遍历,输出元素的集合 ———— 数组降维
1 2 3 4 5 6 7 8 9 10 11 12 13 14 var arr3 = [1 , 2 , [3 , 4 , [5 , 6 ]]];arr3.flat(2 ); `` `js flat自动移除空项 ### Array.prototype.flatMap 如array.map(callback)一样遍历每个元素,之后,把运算结果“压平”成一个数组,QQs:不如改叫mapFlat ` `` js[1 ,2 ,3 ].flatMap(i => {return new Array (i).fill(i)})
String.prototype.trimStart, trimEnd 去除首/尾的空白字符
Object.prototype.fromEntries 是ES8 Object.entries 的反向操作
String.prototype.matchAll 返回匹配正则表达式的所有结果的集合
新增基本数据类型 BigInt js基本数据类型(值类型)已不止5种(ES6之后是六种)!ES10后一共有七种基本数据类型,分别是: String、Number、Boolean、Null、Undefined、Symbol、BigInt
关于Symbol,生成唯一的值,用于不关心具体值(只需要用变量名区分即可)的场景 见知乎:JS 中的 Symbol 是什么?
装饰器Decorator Angular常见的@Component(), @Module()等,在Ts中已有规范 ES6 提案 尚未标准化,js decorator或无法被浏览器适用,需使用babel打包并规范化 其实质是将定义的方法(装饰器名即函数签名)添加到紧随其后的class, function的propotype上
1 2 3 4 5 6 7 8 9 10 11 function observer (target ) { target.prototype.componentWillMount = function ( ) { targetCWM && targetCWM.call(this ); ReactMixin.componentWillMount.call(this ); }; }
关注木易杨每日面试题 Daily Interview Question