es6-es11 let
- 不存在变量提升
// var 的情况 console.log(foo); // 输出undefined var foo = 2;
// let 的情况 console.log(bar); // 报错ReferenceError let bar = 2;
2)暂时性死区 暂时性死区的本质就是,只要一进入当前作用域,所要使用的变量就已经存在了,但是不可获取,只有等到声明变量的那一行代码出现,才可以获取和使用该变量。 var tmp = 123;
if (true) { tmp = 'abc'; // ReferenceError let tmp; }
3)不允许重复声明 let不允许在相同作用域内,重复声明同一个变量。 因此,不能在函数内部重新声明参数。 // 报错 function func() { let a = 10; var a = 1; }
// 报错 function func() { let a = 10; let a = 1; }
function func(arg) { let arg; } func() // 报错
function func(arg) { { let arg; } } func() // 不报错
- 块级作用域 类似var 但是所声明的变量,只在let命令所在的代码块内有效。
- 不属于顶层对象window
const
const声明一个只读的常量。一旦声明,常量的值就不能改变。具有上述let的属性
const声明的变量不得改变值,这意味着,const一旦声明变量,就必须立即初始化,不能留到以后赋值。 const PI = 3.1415; PI // 3.1415
PI = 3; // TypeError: Assignment to constant variable.
const foo; // SyntaxError: Missing initializer in const declaration
const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动。 对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量。 但对于复合类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指向实际数据的指针,const只能保证这个指针是固定的(即总是指向另一个固定的地址),至于它指向的数据结构是不是可变的,就完全不能控制了 const foo = {}; // 为 foo 添加一个属性,可以成功 foo.prop = 123; foo.prop // 123
// 将 foo 指向另一个对象,就会报错 foo = {}; // TypeError: "foo" is read-only
let var const 区别 1、var声明变量存在提升(提升当前作用域最顶端),let和const是不存在变量提升的情况 2、var没有块级作用,let和const存在块级作用域 3、var允许重复声明,let和const在同一作用域不允许重复声明 4、var和let声明变量可以修改,const是常量不能改变 解构赋值
//赋值元素可以是任意可遍历的对象 let [a, b, c] = [1, 2, 3]; let [firstName, surname] = [] //未分配内容变量是undefined let [name = "Guest", surname = "Anonymous"] = ["Julius"]//赋值默认值 name:Julius surname:Anonymous let [a, b, c] = "abc" // ["a", "b", "c"] let [one, two, three] = new Set([1, 2, 3])
//被赋值的变量还可以是对象的属性,不局限于单纯的变量。 let user = {} [user.firstName, user.secondName] = 'Kobe Bryant'.split(' ')
console.log(user.firstName, user.secondName) // Kobe Bryant
// 忽略数组某元素变量赋值,用逗号处理跳过赋值元素 let [name, , title] = ['John', 'Jim', 'Sun', 'Moon'] console.log( title ) // Sun
//rest参数
let [name1, name2, ...rest] = ["Julius", "Caesar", "Consul", "of the Roman Republic"]
console.log(name1) // Julius
console.log(name2) // Caesar
// Note that type of rest
is Array.
console.log(rest[0]) // Consul
console.log(rest[1]) // of the Roman Republic
console.log(rest.length) // 2
let options = { title: "Menu", rest:"allRest" } let {width , height = 200, title} = options
console.log(title) // Menu
console.log(width) // undefined 取不到值undefined
console.log(height) // 200 指定默认值
let {title, ...rest} = options// rest.rest : allRest
let str = 'mode' let [a, b, c, d, e] = str
Symbol
let s = Symbol()
typeof s // "symbol"
let s1 = Symbol('foo')//接受一个字符串作为参数,表示对 Symbol 实例的描述 let s2 = Symbol('foo') console.log(s1 === s2) // false console.log(Symbol.keyFor(s1)) // undefined
let s1 = Symbol.for('foo')//接受一个字符串作为参数,然后搜索有没有以该参数作为名称的 Symbol 值 let s2 = Symbol.for('foo') console.log(s1 === s2) // true console.log(Symbol.keyFor(s1)) // foo Symbol.keyFor()方法返回一个已登记的 Symbol 类型值的key
BigInt es10 BigInt 表示一个任意精度的整数,可以表示超长数据,可以超出2的53次方。 //1.数字后面增加n const bigInt = 9007199254740993n console.log(bigInt) console.log(typeof bigInt) // bigint
//2.使用 BigInt 函数 const bigIntNum = BigInt(9007199254740993n) console.log(bigIntNum)
promise 概念:promise对象可以处理异步操作,获取异步操作的消息. 特点: 1、Promise对象只有三种状态 异步操作“未完成”(pending) 异步操作“已完成”(resolved,又称fulfilled) 异步操作“失败”(rejected) 2、promise的回调是同步的,then是异步的 3、可以链式调用
Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject。它们是两个函数,由 JavaScript 引擎提供,不用自己部署。 const promise = new Promise(function(resolve, reject) { // ... some code
if (/* 异步操作成功 */){ resolve(value); } else { reject(error); } }); //为promise实例添加状态改变时的回调函数 promise.then(function(value) { // success }, function(error) { // failure });
//手写 function Promise(callback){ var self = this; self.status = 'PENDING'; self.data = undefined;//promise的值 self.onResolvedCallback = [];//resolve回调函数集 self.onRejectedCallback = [];//reject回调函数集 callback(resove,reject);//执行executor并传入相应的参数
function resolve(value){
if (self.status=='PENDING') {
self.status='resolved';
self.data = value;
// 依次执行成功之后的函数栈
for(var i = 0;i<self.onResolvedCallback.length;i++){
self.onResolvedCallback[i](value)
}
}
}
function reject(error){
if (self.status=='PENDING') {
self.status = 'rejected';
self.data = error;
// 依次执行失败之后的函数栈
for(var i = 0;i<self.onRejectedCallback.length,i++){
self.onRejectedCallback[i](error)
}
}
}
}
方法: 自身api
-
Promise.resolve() 1)将Promise对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;
-
Promise.reject()
- reject函数的作用是,将Promise对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。
-
Promise.all() 概念:Promise.all方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。 .all()的作用是接收一组异步任务,然后并行执行异步任务,并且在所有异步操作执行完后才执行回调。 有了all,你就可以并行执行多个异步操作,并且在一个回调中处理所有的返回数据。 多个 Promise 任务同时执行,假如一律成功执行,则以数组的方式返回所有 Promise 任务的执行结果。 假如有一个 Promise 任务 rejected,则只返回 rejected 任务的结果 应用:有一个场景是很适合用这个的,一些游戏类的素材比较多的应用,打开网页时,预先加载需要用到的各种资源如图片、flash以及各种静态文件。所有的都加载完后,我们再进行页面的初始化。 const p = Promise.all([p1, p2, p3]);
//手写 Promise.all = arr => { let aResult = []; //用于存放每次执行后返回结果 return new _Promise(function (resolve, reject) { let i = 0; next(); //开始逐次执行数组中的函数 function next() { arr[i].then(function (res) { aResult.push(res); //执行后返回的结果放入数组中 i++; if (i == arr.length) { //如果函数数组中的函数都执行完,便把结果数组传给then resolve(aResult); } else { next(); } }) } }) };
- Promise.race() 概念:多个 Promise 任务同时执行,返回最先执行结束的 Promise 任务的结果,不论这个 Promise 结果是成功还是失败 .race()的作用也是接收一组异步任务,然后并行执行异步任务,只保留取第一个执行完成的异步操作的结果,其他的方法仍在执行,不过执行结果会被抛弃。 应用:比如我们可以用race给某个异步请求设置超时时间,并且在超时后执行相应的操作 const p = Promise.race([p1, p2, p3]);
//可以用race给某个异步请求设置超时时间,并且在超时后执行相应的操作 function runAsync (x) { const p = new Promise(r => setTimeout(() => r(x, console.log(x)), 1000)) return p } Promise.race([runAsync(1), runAsync(2), runAsync(3)]) .then(res => console.log('result: ', res)) .catch(err => console.log(err))
- Promise.allSettled() es11 //如果并发任务中,假如有一个 Promise 任务 rejected,则只返回 rejected 任务的结果 Promise.all([ Promise.reject({ code: 500, msg: '服务异常' }), Promise.resolve({ code: 200, data: ['1', '2', '3'] }), Promise.resolve({ code: 200, data: ['4', '5', '6'] }) ]).then(res => { console.log(res) console.log('成功') }).catch(err => { console.log(err) console.log('失败') })
//如果并发任务中,无论一个任务正常或者异常,都会返回对应的的状态 Promise.allSettled([ Promise.reject({ code: 500, msg: '服务异常' }), Promise.resolve({ code: 200, data: ['1', '2', '3'] }), Promise.resolve({ code: 200, data: ['4', '5', '6'] }) ]).then(res => { console.log(res) // console.log('成功') const data = res.filter(item => item.status === 'fulfilled') console.log(data) }).catch(err => { console.log(err) console.log('失败') })
Promise.prototype上的方法
-
Promise.prototype.then()
作用:为promise实例添加状态改变时的回调函数 用法: 1.Promise实例生成以后,可以用then方法分别指定resolved状态和rejected状态的回调函数,参数一是resolved的回调函数;参数二(可选)是rejected的回调函数 2.then方法返回一个新promise实例. 3.可采用链式写法.即then方法后面再调用另一个then方法 //采用链式的then,可以指定一组按照次序调用的回调函数。这时,前一个回调函数,有可能返回的还是一个Promise对象(即有异步操作),这时后一个回调函数,就会等待该Promise对象的状态发生变化,才会被调用。如果你在 then 中 使用了 return,那么 return 的值会被 Promise.resolve() 包装 getJSON("/posts.json").then(function(json) { return json.post;// 包装成 Promise.resolve(json.post) }).then(function(post) { // ... }); -
Promise.prototype.finally() es9 作用:方法用于指定不管 Promise 对象最后状态如何,都会执行的操作。该方法是 ES2018 引入标准的。 用法:不接受任何参数,意味着无法知道前面promise状态是fulfilled还是rejected promise .then(result => {···}) .catch(error => {···}) .finally(() => {···});
-
Promise.prototype.catch() 作用:用于指定发生错误时的回调函数 用法: 1.then方法返回一个新promise实例. 2.可采用链式写法.即then方法后面再调用另一个then方法
红灯3秒亮一次,绿灯1秒亮一次 ,黄灯2秒亮一次,意思就是3秒执行一次red函数,2秒执行一次green函数,1秒执行一次yellow函数,不断交替重复亮灯,意思就是按照这个顺序一直执行这3个函数,这步可以利用递归来实现。 function red() { console.log('red'); } function green() { console.log('green'); } function yellow() { console.log('yellow'); }
var light = function (timmer, cb) { return new Promise(function (resolve, reject) { setTimeout(function () { cb(); resolve(); }, timmer); }); };
var step = function () { Promise.resolve().then(function () { return light(3000, red); }).then(function () { return light(2000, green); }).then(function () { return light(1000, yellow); }).then(function () { step(); }); }
step();
const promise1 = new Promise(function(resolve, reject) { setTimeout(function() { resolve('foo'); console.log(1) }, 300); });
promise1.then(function(value) { console.log(value); // expected output: "foo" });
console.log(promise1); // expected output: [object Promise]
Generator 调用 Generator 函数,会返回一个内部指针(即遍历器)g。 next方法的作用是分阶段执行Generator函数。每次调用next方法,会返回一个对象,表示当前阶段的信息(value属性和done属性)。value属性是yield语句后面表达式的值,表示当前阶段的值;done属性是一个布尔值,表示 Generator 函数是否执行完毕,即是否还有下一个阶段。 //手工实现迭代器 function mackIter(parms){ let i =0; return { next(){ let done = (i>=parms.length); let value = !done?parms[i++]:undefined; return { value:value, done:done } } } }
let Iterator = mackIter(['1','2']);
//Generator 生成迭代器 function* gener(){ yield "1"; yield "2"; }
let Iterator = gener();
//改造 Generator let mackgener = function* (parms){ for (var i = 0; i < parms.length; i++) { yield parms[i]; } } let Iterator = mackgener(['1','2']);
console.log(Iterator.next());//{value:"1",done:false} console.log(Iterator.next());//{value:"2",done:false} console.log(Iterator.next());//{value:undefined,done:true}
async...await es8 async 用于声明一个异步函数,返回一个promise对象,await用于等待一个异步方法执行完成. 1.await必须在async函数内部,不能单独使用。 2.async就是 Generator 函数的语法糖。async相当于*,await相当于yeild。 async函数对于Generator函数的改进体现在返回值是promise,相对于Generator返回迭代对象来说更方便 async function async1() { await async2()//立即执行await后面的表达式 console.log('async1 end')//表达式后面的代码放到微任务队列里 then里面 } async function async2() { console.log('async2 end') } async1()
//transfer new Promise((resolve, reject) => { console.log('async2 end') // Promise.resolve() 将代码插入微任务队列尾部 // resolve 再次插入微任务队列尾部 resolve(Promise.resolve()) }).then(() => { console.log('async1 end') })
async function async1 () { console.log('async1 start'); await new Promise(resolve => { console.log('promise1') }) console.log('async1 success'); return 'async1 end' } console.log('srcipt start') async1().then(res => console.log(res)) console.log('srcipt end')
async function async1() { console.log("async1 start"); await async2(); console.log("async1 end"); } async function async2() { console.log("async2"); } async1(); console.log('start') // 在async1中await后面的Promise是没有返回值的,也就是它的状态始终是pending状态,因此相当于一直在await,await,await却始终没有响应… 'async1 start' 'async2' 'start' 'async1 end'
async function async1 () { console.log('async1 start'); await new Promise(resolve => { console.log('promise1') }) console.log('async1 success'); return 'async1 end' } console.log('srcipt start') async1().then(res => console.log(res)) console.log('srcipt end') 'script start' 'async1 start' 'promise1' 'script end'
//加上返回值 async function async1 () { console.log('async1 start'); await new Promise(resolve => { console.log('promise1') resolve('promise1 resolve') }).then(res => console.log(res)) console.log('async1 success'); return 'async1 end' } console.log('srcipt start') async1().then(res => console.log(res)) console.log('srcipt end') 'script start' 'async1 start' 'promise1' 'script end' 'promise1 resolve' 'async1 success' 'async1 end'
async function async1 () { console.log('async1 start'); await new Promise(resolve => { console.log('promise1') resolve('promise resolve') }) console.log('async1 success'); return 'async1 end' } console.log('srcipt start') async1().then(res => { console.log(res) }) new Promise(resolve => { console.log('promise2') setTimeout(() => { console.log('timer') }) }) 'script start' 'async1 start' 'promise1' 'promise2' 'async1 success' 'sync1 end' 'timer'
//综合题 const async1 = async () => { console.log('async1'); setTimeout(() => { console.log('timer1') }, 2000) await new Promise(resolve => { console.log('promise1') }) console.log('async1 end') return 'async1 success' } console.log('script start'); async1().then(res => console.log(res)); console.log('script end'); Promise.resolve(1) .then(2) .then(Promise.resolve(3)) .catch(4) .then(res => console.log(res)) setTimeout(() => { console.log('timer2') }, 1000) 'script start' 'async1' 'promise1' 'script end' 1 'timer2' 'timer1' //async函数中await的new Promise要是没有返回值的话则不执行后面的内容(类似题5.5) //.then函数中的参数期待的是函数,如果不是函数的话会发生穿透(类似题3.8 ) //注意定时器的延迟时间
for...await...of es9
function Gen(time) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve(time)
}, time)
})
}
// async function test() { // let arr = [Gen(2000), Gen(100), Gen(3000)] // for (let item of arr) { // console.log(Date.now(), await item.then(console.log)) // } // }
async function test() { let arr = [Gen(2000), Gen(100), Gen(3000)] for await (let item of arr) { console.log(Date.now(), item) } }
test()//按照任务的先后顺序进行
模板字符串 方便多行表示字符串,便于拼接 可嵌套表达式、变量、函数 function fn() { return "Hello World"; }
foo ${fn()} bar
es8
String.prototype.padStart(targetLength,padString)
String.prototype.padEnd(targetLength,padString)
// 数字替换,比如手机号,身份证号 const tel = '13012345678' const newTel = tel.slice(-4).padStart(tel.length, '*') console.log(newTel) // *******5678
const str1 = 'I am learning es in imooc' console.log(str1.padEnd(30, '.')) // I am learning es in imooc.....
const str2 = '200' console.log(str2.padEnd(5)) //padString非必选,默认"" // "200 "
es10
str.trimStart()
str.trimLeft()
str.trimEnd()
str.trimRight()
let str = ' foo '
console.log(str.length) // 8
str = str.trimEnd()
console.log(str.length) // 6
globalThis console.log(globalThis)//全局作用域中的 this
运算符 ?? es11 const b = null // 或者null undefined false const a = b ?? 123
对象 1.简洁表示 //es5 let name = 'xiecheng' let age = 34 let obj = { name: name, age: age, study: function() { console.log(this.name + '正在学习') } } //es6 let name = 'xiecheng' let age = 34 let obj = { name, age, study() { console.log(this.name + '正在学习') } } 2.属性名表达式 let s = 'school' let obj = { foo: 'bar', [s]: 'imooc'//可直接用变量或表达式来定义Object的key } 3.判断对象是否相等 Object.is(+0,-0);//false Object.is(NaN,NaN);//true 4.Object.assign(target,sources) let t = Object.assign(2) // Number {2} let s = Object.assign(2, { a: 2 }) // Number {2, a: 2}//如果目标对象不是对象,则会自动转换为对象 5.对象遍历 let obj = { name: 'xiecheng', age: 34, school: 'imooc' } //for...in for (let key in obj) { console.log(key, obj[key]) } //Object.keys() Object.keys(obj).forEach(key => { console.log(key, obj[key]) }) Reflect.ownKeys(obj).forEach(key => { console.log(key, obj[key]) }) Object.getOwnPropertyNames(obj).forEach(key => { console.log(key, obj[key]) })
//es8
Object.values()
Object.entries()
Object.getOwnPropertyDescriptors()
Object.getPrototypeOf() Object.setPrototypeOf();//创建后改变对象的proytotype
//es10 Object.fromEntries([ ['foo', 1], ['bar', 2] ])// {foo: 1, bar: 2}
const map = new Map() map.set('name', 'imooc') map.set('course', 'es') console.log(map) const obj = Object.fromEntries(map) console.log(obj)// {name: "imooc", course: "es"}
const course = { math: 80, english: 85, chinese: 90 } const res = Object.entries(course).filter(([key, val]) => val > 80) console.log(res) console.log(Object.fromEntries(res))
函数扩展
-
函数参数默认值 function expand(province,{city,area}={}){//设置默认值,防止未传参报错 console.log(province,city,area) } expand("江苏",{"苏州","新区"});
-
函数参数 rest操作符 // ...也可作为spread操作符 ...infos 展开infos对象 function expand(province,...infos){//多余参数收进infos数组 console.log(province,city,area) } expand("江苏","苏州","新区");
-
函数的length属性 function foo(x = 1, y = 2, z = 3) { console.log(x, y) } console.log(foo.length)// 0 返回没有指定默认值的参数个数
-
函数name属性 let f = function experssion(){};//具名函数表达式 console.log(f.name)
箭头函数
语法更简洁
无this、无原型、无super、无arguments、无new.target、不能通过new关键字调用
- 语法 let arrow = (params1,params2)=>{};//多个参数加括号 let arrow = params=>{}; var arrow = function arrow(params) {};// babel tranfer let food = { drink:"drink", eat(){},//对象方法 remove:function(){} } let pow = x => x * x//返回值是表达式 可省略return {} let person = (name) => ({//返回值是字面量对象,用括号包起来 age: 20, addr: 'Beijing City' })- 特征
1.
无this、无原型、无super、无arguments、无new.target、不能通过new关键字调用
//没有 [[Construct]] 方法,不能被用作构造函数,如果通过 new 的方式调用,会报错 var Foo = () => {}; var foo = new Foo(); // TypeError: Foo is not a constructor
2.不能使用 new 调用,所以也没有 new.target 值 3.箭头函数也不存在 prototype 属性 var Foo = () => {}; console.log(Foo.prototype); // undefined
set/map
区别在于map的key值可以是任意值,包括函数、对象、基本类型.
Set的值不会重复。
let setArr = new Set();
setArr.add()
setArr.delete()
setArr.has()
setArr.clear()
setArr.size
let mapArr = new Map(); mapArr.set(); mapArr.get(); mapArr.delete() mapArr.has() mapArr.clear(); mapArr.size
for/forEach for循环可以用break跳出循环,forEach不能 for循环可以return,forEach return无效 for循环可修改索引,forEach只能从0开始,底层控制索引自增,无法修改
遍历数组 不改变原数组遍历方法: ES5:a.forEach()/ a.every()/ a.some()/ a.fliter()/ a.map()/ a.reduce()/ a.reduceRight() ES6:a.find()/ a.findIndex() / for...of for for...in //遍历对象 for..of //遍历Iterator
- Array.from 1.创建数组 2.伪数组转数组 //初始化一个长度为5的数组,数组元素默认1 let arr = Array(6).join(' ').split('').map(item => 1) Array.from({ length: 5 }, function() { return 1 }) Array(5).fill(1)
Array.of Array.of(7); // [7] Array.of(1, 2, 3); // [1, 2, 3]
Array(7); // [ , , , , , , ] 7个空位(empty)的数组 Array(1, 2, 3); // [1, 2, 3]
-
Array.prototype.fill(value,start,end) value 必选 填充数组元素的值 start end 起始索引 终止索引 默认(0,this.length) let array = [1, 2, 3, 4] array.fill(0, 1, 2) // [1,0,3,4]
-
Array.prototype.find() let array = [5, 12, 8, 130, 44];
let found = array.find(function(element) { return element > 10; });
console.log(found);//12
-
Array.prototype.findIndex() let array = [5, 12, 8, 130, 44]; let found = array.find(function(element) { return element > 10; }); console.log(found);//1
-
Array.prototype.copyWithin(target, start = 0, end = this.length) target 从此索引开始替换数据 start 从此索引开始读取数据 end 从次索引停止读取数据 let arr = [1, 2, 3, 4, 5] console.log(arr.copyWithin(1, 3))// [1, 4, 5, 4, 5]
-
Array.prototype.includes() es7 参数一 要搜索的值; 参数二 搜索的开始索引 //只支持判断简单数据类型的数据 const arr = [1, [2, 3], 4] arr.includes([2, 3]) //false arr.indexOf([2, 3]) //-1
//对于NaN的处理结果不同
const demo = [1, NaN, 2, 3]
demo.indexOf(NaN) //-1
demo.includes(NaN) //true
- Array.prototype.flat(depth) es10
- Array.prototype.flatMap(callback,thisArg) //深度扁平数组 function flattenDeep(arr,deepLength){ return arr.flat(deepLength) } let deepLength = Math.pow(2,53)-1;//JS能表示的最大数字为 Math.pow(2,53)-1; console.log(flattenDeep([1,[2,[3]]],deepLength))
Set let s = new Set() let s = new Set([1, 2, 3, 4])//传入数据必须是可遍历的 s.add('hello').add('goodbye') s.delete('hello') // true 删除指定数据 s.clear()//删除全部数据 s.has('hello') //统计是否存在数据 s.size //统计数据项总数
//求交集 let s1 = new Set(arr1) let s2 = new Set(arr2) let result = new Set(arr1.filter(item => s2.has(item))) console.log(Array.from(result))
//求差集 let arr3 = new Set(arr1.filter(item => !s2.has(item))) let arr4 = new Set(arr2.filter(item => !s1.has(item))) console.log(arr3) console.log(arr4) console.log([...arr3, ...arr4])
keys()//键名 values()//键值 entries()//键值对 forEach() for...of
console.log(s.keys()) // SetIterator {"hello", "goodbye"} console.log(s.values()) // SetIterator {"hello", "goodbye"} console.log(s.entries()) // SetIterator {"hello" => "hello", "goodbye" => "goodbye"} s.forEach(item => { console.log(item) // hello // goodbye })
for (let item of s) { console.log(item) }
for (let item of s.keys()) { console.log(item) }
for (let item of s.values()) { console.log(item) }
for (let item of s.entries()) { console.log(item[0], item[1]) }
WeakSet / WeakMap 成员只能是对象,不能是其他类型的值 WeakSet/WeakMap 中的对象都是弱引用,即垃圾回收机制不考虑 WeakSet/WeakMap 对该对象的引用,也就是说,如果其他对象都不再引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存,不考虑该对象还存在于 WeakSet/WeakMap 之中 const ws = new WeakSet() ws.add(1) // TypeError: Invalid value used in weak set ws.add(Symbol()) // TypeError: invalid value used in weak set
const map = new WeakMap() map.set(1, 2) // TypeError: 1 is not an object! map.set(Symbol(), 2) // TypeError: Invalid value used as weak map key map.set(null, 2) // TypeError: Invalid value used as weak map key
map Object 与 map对象区别 键类型:Object键只能是字符串/Symbols ;Map的键可以是任意值,包括数、对象、基本类型。 键顺序:Object键值无序;Map对象遍历时按插入顺序返回键值. 键统计:Object键值个数手动计算;Map对象的size属性获取Map键值对个数. 键值对迭代:Object迭代需要获取键数组迭代;Map对象可直接迭代. 性能:Map在涉及频繁增删键值对的场景下有性能优势. let map = new Map([iterable]) let keyObj = {} let keyFunc = function() {} let keyString = 'a string'
// 添加键 map.set(keyString, "和键'a string'关联的值") map.set(keyObj, '和键keyObj关联的值') map.set(keyFunc, '和键keyFunc关联的值')
// 删除指定的数据 map.delete(keyObj)
// 删除所有数据 map.clear()
// 统计所有 key-value 的总数 console.log(map.size) //2
// 判断是否有 key-value console.log(map.has(keyObj)) // true
// 和键keyObj关联的值 console.log(map.get(keyObj))
//遍历方式 map.forEach((value, key) => console.log(value, key))
for (let [key, value] of map) { console.log(key, value) }
for (let key of map.keys()) { console.log(key) }
for (let value of map.values()) { console.log(value) }
for (let [key, value] of map.entries()) { console.log(key, value) }
幂运算符 es7 console.log(Math.pow(2, 10)) // 1024 console.log(2 ** 10) // 1024
es6模块化
//util.js
export {};//导出
export {fn as default,variable};//默认导出fn
export default {fn,variable};//默认导出
//main.js import {fn,variable,experssion,Foramt as dateForamt} from './util';//导入指定对象;Foramt重命名为dateForamt; import * as util from './util';//全部导入
import fn,{variable} from './util';//默认导入不需要大括号,且写在最前面
class
class 的方式是 function 方式的语法糖
es5继承
// 定义父类
let Animal = function(type) {
this.type = type
}
// 定义方法
Animal.prototype.walk = function() {
console.log( I am walking
)
}
// 定义静态方法
Animal.eat = function(food) {
console.log( I am eating
)
}
// 定义子类
let Dog = function() {
// 初始化父类
Animal.call(this, 'dog')
this.run = function() {
console.log('I can run')
}
}
// 继承
Dog.prototype = Animal.prototype
es6继承
class Animal {
constructor(type) {
this.type = type
}
walk() {
console.log( I am walking
)
}
static eat() {
console.log( I am eating
)
}
}
class Dog extends Animal { constructor () { super('dog') } run () { console.log('I can run') } }
ES6继承通过 class 新建子类 extends继承父类的方式实现继承,super 关键字用于调用对象的父对象上的函数, static 的标记静态方法 class Point { constructor(x) { this.x = 1; this.p = 2; } print() { return this.x; } } Point.prototype.z = '4' class ColorPoint extends Point { constructor(x) { this.color = color; // ReferenceError super(x, y); this.x = x; // 正确 } m() { super.print(); } }
1.class声明不会提升 const bar = new Bar(); // it's ok function Bar() { this.bar = 42; }
const foo = new Foo(); // ReferenceError: Foo is not defined class Foo { constructor() { this.foo = 42; } }
2.class声明内部启用严格模式 // 引用一个未声明的变量 function Bar() { baz = 42; // it's ok } const bar = new Bar();
class Foo { constructor() { fol = 42; // ReferenceError: fol is not defined } } const foo = new Foo();
3.class的所有方法不可枚举 // 引用一个未声明的变量 function Bar() { this.bar = 42; } Bar.answer = function() { return 42; }; Bar.prototype.print = function() { console.log(this.bar); }; const barKeys = Object.keys(Bar); // ['answer'] const barProtoKeys = Object.keys(Bar.prototype); // ['print']
class Foo { constructor() { this.foo = 42; } static answer() { return 42; } print() { console.log(this.foo); } } const fooKeys = Object.keys(Foo); // [] const fooProtoKeys = Object.keys(Foo.prototype); // []
4.class所有方法无原型对象prototype,也没有[construct],不能使用new调用 function Bar() { this.bar = 42; } Bar.prototype.print = function() { console.log(this.bar); };
const bar = new Bar(); const barPrint = new bar.print(); // it's ok
class Foo { constructor() { this.foo = 42; } print() { console.log(this.foo); } } const foo = new Foo(); const fooPrint = new foo.print(); // TypeError: foo.print is not a constructor
5.必须使用new调用class function Bar() { this.bar = 42; } const bar = Bar(); // it's ok
class Foo { constructor() { this.foo = 42; } } const foo = Foo(); // TypeError: Class constructor Foo cannot be invoked without 'new'
6.class内部无法重写类名 function Bar() { Bar = 'Baz'; // it's ok this.bar = 42; } const bar = new Bar(); // Bar: 'Baz' // bar: Bar {bar: 42}
class Foo { constructor() { this.foo = 42; Foo = 'Fol'; // TypeError: Assignment to constant variable } } const foo = new Foo(); Foo = 'Fol'; // it's ok
//es5 function a() { this.name = 'a'; } a.prototype.getName = function getName() { return this.name } function b() {} b.prototype = new a(); console.log(b.prototype.proto === a.prototype); // true console.log(b.proto === a); // false console.log(b.proto); // [Function]
//es6 class A { constructor(a) { this.name = a; } getName() { return this.name; } }
class B extends A{ constructor() { super();//this生成顺序不同,需使用super() } }
console.log(B.prototype.proto === A.prototype); // true console.log(B.proto === A); // true console.log(B.proto); // [Function: A]
Proxy ES6原生提供了Proxy构造函数,用来生成Proxy实例。 target参数可以是任何类型的对象,包括原生数组,函数,甚至另一个代理,被代理后不能直接被访问 handler一个对象就是实现代理的过程 let proxy = new Proxy(target,handler); //demo let onWatch = (obj,setBind,getLogger)=>{ let handler = { set(target,property,value,receiver){ setBind(value,property) return Reflect.set(target,property,value) }, get(target,property,receiver){ getLogger(target,property) return Reflect.get(target,property,receiver) } } return new Proxy(obj,handler) }
let obj = {a:1};
let proxy = onWatch(
obj,
(v,property)=>{
console.log(监听到属性${property}改变为${v}
)
},
(target,property)=>{
console.log(${property} = ${target[property]}
)
}
)
proxy.a = 2;
proxy.a;