ES6
Babel 转码器
将 ES6 转为 ES5.
let 命令
let 申明变量只在它所在的代码块无效。
for 循环就非常适合 let 的应用。
然而:
for (let i = 0; i < 10; i++) {
}
console.log(i);
// ReferenceError: i is not defined
同一个作用域不能应用 let 反复申明同一个变量。
不存在变量晋升
let 放在它被调用之前。
暂时性死区
只有块级作用域内存在 let 命令,它所申明的变量绑定“bind”这个区域就不再受内部影响。
var tmp = 123;
if (true) {
tmp = 'abc'; // ReferenceError
let tmp;
}
全局变量 TMP 然而块级作用域内 let 有申明了一个局部变量 tmp,导致后绑定了这个作用域,在 let 申明变量之前,tmp 会报错。
不容易发现的死区
function bar(x = y, y = 2) {return [x, y];
}
bar();
x= y 并没有申明,就错了。
var x = x;
// 报错
let x = x;
// ReferenceError: x is not defined
不容许反复申明
let 不容许在同一个作用域内,反复申明一个变量。
// 报错
function func() {
let a = 10;
var a = 1;
}
// 报错
function func() {
let a = 10;
let a = 1;
}
ES6 Symbol
ES6 引入了一种新的原始数据类型 Symbol,示意举世无双的值,最大的用法是用来定义对象的惟一属性名。
ES6 数据类型除了 Number、String、Boolean、Object、null 和 undefined,还新增了 Symbol。
Symbol 函数栈不能用 new 命令,因为 Symbol 是原始数据类型,不是对象。
因为每一个 Symbol 的值都是不相等的,所以 Symbol 作为对象的属性名,能够保障属性不重名。
绑定 key 与 value 值不同。
、
Symbol 值作为属性名时,该属性是私有属性不是公有属性,能够在类的内部拜访。然而不会呈现在 for…in、for…of 的循环中,也不会被 Object.keys()、Object.getOwnPropertyNames() 返回。如果要读取到一个对象的 Symbol 属性,能够通过 Object.getOwnPropertySymbols() 和 Reflect.ownKeys() 取到。
扩大运算符
两种运算符
1. 扩大运算符
扩大运算符用 3 个点示意 (…) 用于将一个数组或者类数组对象转化为逗号分隔符的值序列。
拆解数组和字符串。
const array = [1,2,3,4];
console.log(...array);
const str = 'string';
console.log(...str);
拓展运算符代替 apply()函数
获取数组最大值时,应用 apply()函数
let arr = [1,4,6,8,2];
console.log(Math.max.apply(null,arr))
拓展运算符
let arr = [1,4,6,8,2];
console.log(Math.max(...arr));
拓展运算符代替 contact()函数合并数组
console.log([...arr1,...arr2]);
2.rest 运算符
rest 运算符同样应用 … 示意,用于将逗号分隔的值序列转化成数组。
构造组合的应用
let arr = ['one','two','three','four'];let[arg1,...arg2] = arr;console.log(arg1);//oneconsole.log(arg2)//[two,three,four]
rest 运算符代替 arguments 解决函数参数
function foo(...args){for(let arg of args){console.log(arg); } } foo('one','two','three','four');
模板字符串
$('#result').append(` There are <b>${basket.count}</b> items in your basket, <em>${basket.onSale}</em> are on sale!`);
let x = 1;let y = 2;`${x} + ${y} = ${x + y}`// "1 + 2 = 3"`${x} + ${y * 2} = ${x + y * 2}`// "1 + 4 = 5"let obj = {x: 1, y: 2};`${obj.x + obj.y}`// "3"
includes(), startsWith(), endsWith()
三个函数都是返回布尔值,示意是否找到了参数字符串
padStart(), padEnd()
padStart()用于 1 头部补全,padEnd()用于尾部补全。
console.log('x'.padStart(5,'ax'));//axaxx console.log('x'.padEnd(5,'ba'));//xbaba
字符提醒格
console.log('12'.padStart(10, 'YYYY-MM-DD')); // "YYYY-MM-12"console.log('09-12'.padStart(10, 'YYYY-MM-DD'));
trimStart(),trimEnd()
打消头部或者尾部的空格
replaceAll()
字符串代替所有的指定数值
console.log('aabbcc'.replaceAll('b', '_'));// 'aa__cc'
数值新增的办法
Number.isInteger()
判断一个数值是否为整数,boolean 值。
25.0 和 25 都是整数,返回 true。
Math.trunc()
用于去除一个数的小数局部,返回整数。
对于非数值,它会将非数值转化成数值。
对于空值和无奈取证的数值,就返回 NaN.
Math.sign()
它来判断一个数到底是负数还是正数还是零。对于非数值,会将其先转换为数值。
负数返回 +1;
正数返回 -1;
参数为 0 返回 0;
参数 -0,返回 -0;
其余值返回 NaN;
函数参数的默认值
ES6 容许函数的参数设置为默认值,间接写在参数定义的前面。
function Point(x=0,y=0){this.x=x; this.y=y;}const p=new Point();console.log(p);
解构赋值默认值联合应用
function foo({x, y = 5}) {console.log(x, y);}foo({}) // undefined 5foo({x: 1}) // 1 5foo({x: 1, y: 2}) // 1 2foo() // TypeError: Cannot read property 'x' of undefined
函数的 length 属性
指定了默认值当前,函数的 length 属性,将返回没有默认指定默认值的参数个数,指定了默认值当前,length 属性将失真。
(function (a) {}).length // 1(function (a = 5) {}).length // 0(function (a, b, c = 5) {}).length // 2
(function (a, b, c = 5) {}).length // 2
原本应该是 3 个参数,长度为 3,然而有一个定义了默认值,所以要减去一个。
作用域
一旦设置了参数的默认值,函数进行申明初始化时,参数会造成一个独自的作用域 context,等初始化完结,这个作用域就会隐没,没有设置参数默认值时就不会呈现。
var x=1;function f(x,y=x){console.log(y);}f(2);
参数 y 的默认值等于变量 x。调用函数 f 时,参数造成一个独自的作用域。在这个作用域外面,默认值变量 x 指向第一个参数 x,而不是全局变量 x,所以输入是 2。
let x = 1;function f(y = x) {let x = 2; console.log(y);}f() // 1
箭头函数
ES6 能够让箭头 => 定义函数
var f = () => 5;// 等同于 var f = function () {return 5};var sum = (num1, num2) => num1 + num2;// 等同于 var sum = function(num1, num2) {return num1 + num2;}
如果箭头函数代码局部多于一条语句,就要应用 {} 把他们括起来。
并且应用 return 语句返回。
var sum = (num1, num2) => {return num1 + num2;}
因为大括号被解释为代码块,如果箭头函数间接返回一个对象,必修在对象里面加上括号,否则会报错。
// 报错 let getTempItem = id => {id: id, name: "Temp"};// 不报错 let getTempItem = id => ({id: id, name: "Temp"});
箭头函数能够与变量解构联合应用。
const full = ({first, last}) => first + '' + last;// 等同于 function full(person) {return person.first +' ' + person.last;}
箭头函数的应用留神点
1. 箭头函数没有本人的 this 对象
2. 不能够构造函数,也就是不能应用函数应用 new()
3. 不能够应用 arguments 对象,该对象在函数体内不存在,如果必须要用能够用 rest 参数代替。
4. 不能够应用 yield 命令,箭头函数不能用作 Generator 函数。
不应用场合
箭头函数从动静变成动态。
globalThis.s = 21;const obj = {s: 42, m: () => console.log(this.s)};obj.m() // 21
须要动静 this 的时候,也不应该应用箭头函数。
Array.from()
Array.from 办法用于将两类对象转为真正的数组:相似数组的对象(array-like object)和可遍历(iterable)的对象(包含 ES6 新增的数据结构 Set 和 Map)。
let arrayLike={'0':'a', '1':'b', '2':'c', length:3}let arr2=Array.from(arrayLike);console.log(arr2)
Array.of()
用于一组值转化为数组
用于补救 Array()的有余,因为参数个数的不同,会导致 Array(有
差别。只有参数个数不少于 2 个时,Array()才会返回由参数组成的新数组。
Array.of()总是返回参数值组成的数组,如果没有参数,就返回一个空数组。
function ArrayOf(){ return [].slice.call(arguments);}
数组实例的 fill()
fill 办法应用给定值,填充一个数组
['a', 'b', 'c'].fill(7)// [7, 7, 7]
数组实例的 flat()
应用 Array.prototype.flat() 用于将嵌套的数组“拉平”,变成一维的数组。该办法返回一个新数组,对原数据没有影响。
当应用一次 flat 时只能拉平一个 2 维数组,如果要拉平 3 维数组时,就到再应用一次了。
对象的拓展
const name = 'cao teacher';const age = 18;const obj={name,age};// 等同于 const obj = {name:'caoteacher', age:18
定义 obj 对象时,变量名 name 作为了对象的属性名,它的值作为了属性值,一次只须要写一个 name 就能够示意 {name:name} 的含意。
除了属性能够简写,函数也能够简写,即省略关键字 function。
属性遍历
一共有 5 种办法实现对象属性的变量。
1.for…in
2.Object.getOwnPropertyNames(obj)
3.Object.getOwnPropertySymbols(obj)
4.Object.keys(obj)
5.Reflect.ownKeys(obj)
Object.is()
和 ES5 很像 (==) 和(===)
和严格比拟运算符 (===) 行为基本一致
Object.assign()
用于对象的合并,将源对象的所有可枚举属性,复制到指标对象(target)
浅拷贝
Object.assign() 办法履行的是浅拷贝
Symbol
保障每个属性名的名字都是举世无双。
s 就是一个举世无双的值。typeof 运算符的后果,表明变量 s 是 Symbol 数据类型,而不是字符串之类的其余类型。
这个 symbol 函数不能应用 new 命令。
如果 symbol 参数是一个对象,那么就会调用 tostring 办法,将其转化为字符串,而后才生成一个 symbol 值。
Symbol 函数的参数只是示意对以后 Symbol 值的形容,因而雷同参数的 Symbol 函数的返回值是不相等的。
作为属性名的 symbol
因为每个 symbol 值都是不雷同的,对于对象的属性名,就可能保障不会呈现同名的属性,在多个模板够成的状况下,可能避免某一个键被不小心改写或者笼罩。
let mySymbol=Symbol();let a={};a[mySymbol]='hello';console.log(a);
let a={[mySymbol]:'hello'}console.log(a);
let a={};Object.defineProperty(a,mySymbol,{value:'hello'});console.log(a) ;
代码通过方括号构造和 Object.defineProperty,将对象的属性名指定为一个 Symbol 值。留神,Symbol 值作为对象属性名时,不能用点运算符。
应用 symbol 值定义属性时,symbol 值必须放在 [] 方括号外面。
应用 Symbol 最大的益处是,在 switch 语句时,也能够保障他的工作,Symbol 作为属性名时,该属性还是公开属性,不是公有属性。
const COLOR_RED=Symbol();const COLOR_GREEN=Symbol();function getComplement(color){switch (color){case COLOR_GREEN: return COLOR_GREEN; case COLOR_RED: return COLOR_RED;}}
实例:打消魔术字符串
在代码中屡次呈现,与代码造成强耦合的某一个具体字符串或者数值,为了代码的健壮性,尽量打消魔术字符串,改为清晰的变量。
function getArea(shape,options){let area=0; switch(shape){case 'tra':// 魔术字符串 area=.5*options.width*options.height; break;} return area;}getArea('tra',{switch:100,height:100})// 魔术字符串
tra 就是一个魔术字符串,他屡次呈现,与代码造成了强耦合,不利于代码的保护,咱们能够把他写成为一个变量。
function getArea(shape, options) {let area = 0; switch (shape) {case shapeType.triangle: area = .5 * options.width * options.height; break;} return area;}getArea(shapeType.triangle, { width: 100, height: 100})
shapeType.triangle 等于哪个值并不重要,只须要确保他不会和其余 shapeType 重名就好,所以特地适宜 symbol 值。
属性的遍历
Symbool 作为属性名时,该属性不会呈现在 for…in for…of 循环中,也不会被 object.keys(),object.getOwnPropertyNames()
JSON.stringify()返回
然而他也不是公有属性,他有一个 Object.getOwnPropertySymbols()办法,能够获取指定对象的所有 Symbol 属性名,该办法返回一个数组,成员是以后对象所有作用域属性名的 symbol 值。
const obj={};let a=Symbol('a');let b=Symbol('b');obj[a]='hello';obj[b]='world';const objectSymbols=Object.getOwnPropertySymbols(obj);console.log(objectSymbols);
const obj = {};const foo = Symbol('foo');obj[foo] = 'bar';for (let i in obj) {console.log(i); // 无输入}console.log(Object.getOwnPropertyNames(obj) ) // []console.log(Object.getOwnPropertySymbols(obj)) ;//[Symbol(foo)]
能够看到,应用 for…in 循环和 Object.getOwnPropertyNames 并没有获取到 symbol 的键名,须要应用 Object.getOwnPropertySymbols 办法。
另一个是 Reflect.ownKeys() 办法
能够返回所有类型的键名,包含惯例键名和 Symbol 键名。
let obj = {[Symbol('my_key')]: 1, enum: 2, nonEnum: 3 }; console.log(Reflect.ownKeys(obj));//["enum", "nonEnum", Symbol(my_key)]
用于 symbol 值作为键名,不会被惯例办法遍历失去,咱们能够利用这个个性,为对象定义一些非公有,但又只用于外部的办法
let size = Symbol('size');class Collection {constructor() {this[size] = 0;} add(item) {this[this[size]] = item; this[size]++;} static sizeOf(instance) {return instance[size];}}let x = new Collection();Collection.sizeOf(x) // 0x.add('foo');Collection.sizeOf(x) // 1Object.keys(x) // ['0']Object.getOwnPropertyNames(x) // ['0']Object.getOwnPropertySymbols(x) // [Symbol(size)
set 和 Map 的数据结构
set()的用法
ES6 提供了数据结构 set,他相似于数组,然而成员是惟一的,没有反复的值。类数组
const s=new Set();[1,2,2,3,3,4,4,5,4,4,6].forEach(x=>s.add(x));for(let in s){console.log(i);}console.log(s)
通过 add()办法向 set 构造中加入成员,结果表明 set 后果不会增加反复的值,set 函数能够承受一个数组,作为参数,用来初始化。
const set = new Set([1, 2, 3, 4, 4]);[...set]// [1, 2, 3, 4]// 例二 const items = new Set([1, 2, 3, 4, 5, 5, 5, 5]);items.size // 5// 例三 const set = new Set(document.querySelectorAll('div'));set.size // 56// 相似属 const set = new Set();document.querySelectorAll('div').forEach(div => set.add(div));set.size // 56
set()实例的属性和办法
set 有以下属性
Set.prototype.constructor:构造函数,默认就是 Set 函数。
Set.prototype.size:返回 Set 实例的成员总数。
四个操作方法
Set.prototype.add(value):增加某个值,返回 Set 构造自身。
Set.prototype.delete(value):删除某个值,返回一个布尔值,示意删除是否胜利。
Set.prototype.has(value):返回一个布尔值,示意该值是否为 Set 的成员。
Set.prototype.clear():革除所有成员,没有返回值
Array.from()办法能够将 set 构造转化为数组
const items=new Set([7,2,3,4,4,5,4,4,5]);const array=Array.from(items);console.log(array);
与 set()提联合供数组去重办法。
set()的罕用办法
繁多数组的去重,用于 set 成员具备唯一性,因而能够应用 Set 来进行数组的去重。
let arr = [1,2,2,3,3,3,4,4,5,5,6,6];console.log(new Set(arr));
多个数组的合并去重
Set 能够用于繁多数组的合并去重,也能够用做多个数组的合并去重。
let arr1=[1,2,3,3,4,4,5];let arr2=[1,1,2,3,3,4,4,5,5,8];let set1=new Set([...arr1,...arr2]);console.log(set1);
Set 与数组的转化
Set()与数组都有便当的数据处理函数,然而两者的互相转换也很简略,咱们能够抉择对两者进行转化,并调用对应的函数。
Array.from 办法能够将 Set 构造转为数组
const items = new Set([1, 2, 3, 4, 5]);const array = Array.from(items);
set 的遍历
forEach()函数的第一个参数示意的是 Set 中的每个元素,第二个参数示意的元素的索引,第三个就是他的全值
- keys():返回键名的遍历器。
- values():返回键值的遍历器。
-
entries():返回键值对的遍历器
上述函数或者对象都是遍历对象 iterator,通过 for 循环能够取得每一项都值。
let set = new Set(['red','blue','yellow']);for(let item of set.keys()){console.log(item);}for(let item of set.values()){console.log(item);}for(let item of set.entries()){console.log(item);}
Map 的用法
ES6 新减少了一种数据结构 Map,与传统的对象字面量相似,他的实质还是一种键值对的组合,对于非字符串的值会强制性转化为字符串,而 Map 的键却能够由各种类型的值组成。
Map
对象保留键值对,并且可能记住键的原始插入程序。任何值(对象或者原始值) 都能够作为一个键或一个值。
一个 Map 对象在迭代时会依据对象中元素的插入程序来进行 — 一个 for...of
循环在每次迭代后会返回一个模式为 [key,value] 的数组
const data = {};const element = document.getElementById('myDiv');data[element] = 'metadata';data['[object HTMLDivElement]'] // "metadata"
以上代码只是将 DOM 节点作为对象 data 的值,然而因为对象只承受字符串作为键名,所以有以 element 被主动转化为字符串。
const m=new Map();const o={p:'hello world'};m.set(o,'content');console.log(m.get(o)) ;console.log(m.has(o)) ;console.log(m.delete(o)) ;console.log(m.has(o)) ;
展现了如何向 Map 增加成员,作为构造函数,map 也能够承受一个数组作为参数。
Map 构造函数承受数组作为参数,实际上是执行以下的算法。
一个 Map 对象在迭代时会依据对象中元素的插入程序来进行 — 一个 for...of
循环在每次迭代后会返回一个模式为 [key,value] 的数组。
const items = [['name', '张三'],['title', 'Author']];const map = new Map();items.forEach(([key, value]) => map.set(key, value));
不仅仅是数组,任何具备 lterator 的接口,且每一个成员都是一个双元素数组的数据结构都能够当作 Map 的构造函数的参数。
const set = new Set([['foo', 1],['bar', 2]]);const m1 = new Map(set);m1.get('foo') // 1const m2 = new Map([['baz', 3]]);const m3 = new Map(m2);m3.get('baz') // 3
对一个键进行屡次赋值,后者就要会笼罩前者的值。
const map = new Map();map.set(1, 'aaa').set(1, 'bbb');map.get(1) //bbb
如果读取一个未知的键,则返回 undefined。
new Map().get('asfddfsasadf')// undefine
set 和 get()办法一样,外表是针对同一个键,然而实际上是两个不同的数组实例。内存地址也一样。
const map = new Map();const k1 = ['a'];const k2 = ['a'];map.set(k1, 111).set(k2, 222);map.get(k1) // 111map.get(k2) /
map.size
size 属性返回 Map 构造的成员总数
Map.prototype.set(key, value)
set 办法设置键名 key 对应的键值为 value,而后返回整个 Map 构造。如果 key 曾经有值,则键值会被更新,否则就新生成该键。
Map.prototype.get(key)
get 办法读取 key 对应的键值,如果找不到 key,返回 undefined。
Map.prototype.has(key)
Map.prototype.delete(key)
Map.prototype.clear()
遍历办法
提供三个遍历器生成函数和一个遍历办法。
Map 的遍历程序就是插入程序。
const map = new Map([['F', 'no'],['T', 'yes'],]);for (let key of map.keys()) {console.log(key);}for (let value of map.values()) {console.log(value);}// "no"// "yes"for (let [key, value] of map.entries()) {console.log(key, value);}for (let [key, value] of map) {console.log(key, value);}// "F" "no"// "T" "yes"
map[Symbol.iterator] === map.entries
Map 转化为数组构造的,疾速办法是应用扩大运算符(…)
const map = new Map([[1, 'one'],[2, 'two'],[3, 'three'],]);[...map.keys()]// [1, 2, 3][...map.values()]// ['one', 'two', 'three'][...map.entries()]// [[1,'one'], [2, 'two'], [3, 'three']][...map]// [[1,'one'], [2, 'two'], [3, 'three']]
联合数组的 map 办法,filter 办法,能够实现 Map 的遍历和过滤
const map0 = new Map().set(1, 'a').set(2, 'b').set(3, 'c');const map1 = new Map([...map0].filter(([k, v]) => k < 3));// 产生 Map 构造 {1 => 'a', 2 => 'b'}const map2 = new Map([...map0].map(([k, v]) => [k * 2, '_' + v]) );// 产生 Map 构造 {2 => '_a', 4 => '_b', 6 => '_c'}
forEach 办法还能够承受第二个参数,用来绑定 this
Map 转化为数组
后面咱们试过用 … 转化
数组转化为 Map
将数组传入 Map 构造函数,就能够转化为 Map
new Map([[true, 7],[{foo: 3}, ['abc']]])
Map 转化为对象
如果所有 Map 的键值是字符串,那么他能够完整无缺的转化为对象
function strMapToObject(strMap){let obj=Object.create(null); for(let [k,v]of strMap){obj[k]=v; } return obj;}const myMap=new Map().set('yes',true).set('no',false);console.log(strMapToObject(myMap)) ;
如果有非字符穿的键名,那么这个键值会被转化成字符串。
对象转化为 Map
对象转化为 Map 能够通过 object.entries()
MAP 转化为 JSON
JSON.stringify
JSON 转为 Map
JSON.parse
Proxy
代理器
次要用于扭转对象的默认拜访行为,理论体现是在拜访对象之前减少一层拦挡,任何对象的拜访行为都会通过这层拦挡,在拦挡中,咱们能够减少自定义行为。
const proxy = new Proxy(target,handler);
构造函数,承受 2 个参数,一个指标对象 target,另一个配置对象是 handler,用来定义拦挡行为。
const person={name:'cao', age:18, sex:'woman'};let handler={get:function(target,prop,receiver){console.log('你拜访了 person 属性'); return target[prop]; }}const p=new Proxy(person,handler);console.log(p.name);console.log(p.age);
你拜访了 person 属性 es6.js:481 caoes6.js:476 你拜访了 person 属性 es6.js:482 18
必须通过代理实例拜访
配置对象不能为空对象
Proxy 实例函数以及其根本应用
- get(target,propKey,receiver)
- set(target,propKey,value,receiver)
- has(target.propKey)
- ……..
读取不存在的属性
失常状况下当读取一个对象不存在的属性时,会返回 undefined,然而通过 Proxy()的 get()函数能够设置读取不存在的属性时抛出异样,从而防止对 undefined 的兼容解决
let person={name:'cao'}const proxy=new Proxy(person,{ get:function (target,propKey){if(propKey in target){return target[propKey]; }else{throw new ReferenceError(` 拜访的属性 ${propKey}不存在 `); } }});console.log(proxy.name);console.log(proxy.age)
读取读索引的值
通过 proxy()减少索引的查找速度
target[target.length+index];
禁止拜访公有属性
公有属性会以_结尾,因为咱们并不想拜访到他的属性,同样能够设置 Proxy.get()函数;来实现
const person = {name:'cao teacher', _pwd:'123456'} const proxy = new Proxy(person,{ get:function(target,prop){if(prop.indexOf('_') ===0){throw new ReferenceError('不能间接拜访公有属性'); }else{return target[prop]; } } }); console.log(proxy.name); console.log(proxy._pwd)
实现真正的公有
通过 proxy 解决下滑线来真正实现公有
不能拜访,批改,不能遍历公有值,遍历进去的属性中也不会蕴含公有属性。
get:function(target,prop){if(prop[0] === '_'){return undefined;
减少日志记录
针对那些迟缓或者资源密集型的接口,咱们能够先应用 Proxy 进行拦挡,通过 get()函数拦挡调用的函数名,如何用 apply()函数进行函数调用。
const apis = {_apiKey:'12ab34cd56ef', getAllUsers:function(){console.log('这是查问全副用户的函数'); }, getUserById:function(userId){console.log('这是依据用户 ID 查问用户的函数'); }, saveUser:function(user){console.log('这是保留用户的函数'); }};// 记录日志的办法 function recordLog(){ console.log('这是记录日志的函数');}const proxy = new Proxy(apis,{ get:function(target,prop){const value = target[prop]; return function(...args){// 此处调用记录日志的函数 recordLog(); // 调用实在的函数 return value.apply(null,args); } }});proxy.getAllUsers();
Reflect
Reflect 对象与 Proxy 对象一样,也是 ES6 为了操作对象而提供的新 API。
名为 Reftect 的全局对象,下面挂载了对象的某些非凡函数,这些函数能够通过相似于 Reflect.apply()这种模式来调用,所有在 Reflecl 对象上的函数要么能够在 Object 原型链中找到,要么能够通过命令式操作符实现,
Reflect 动态函数
Reflect.apply(target, thisArgument, argumentsList)
和 Function.prototype.apply()性能相似。
Reflect.construct(target, argumentsList[, newTarget])
…………..
Reflect.has(obj, name)
Reflect.has 办法对应 name in obj 外面的 in 运算符。
Reflect.apply(func, thisArg, args)
相似于 Function.prototype.apply.call(func, thisArg, args),用于绑定 this 对象后执行给定函数。
应用 Proxy 实现观察者模式
实现主动察看数据对象
一旦有变动函数就会主动执行
const person = observable({name: '张三', age: 20});function print() { console.log(`${person.name}, ${person.age}`)}observe(print);person.name = '李四'
Promise
解决 Ajax 申请代码
以前因为耦合太重大,执行多个异步申请,每一个申请又须要依赖上一个申请的后果,依照回调函数。
// 第一个申请 $.ajax({url:'url1', success:function(){// 第二个申请 $.ajax({ url:'url2', success:function(){// 第三个申请 $.ajax({ url:'url3', success:function(){// 第四个申请 $.ajax({ url:'url4', success:function(){// 胜利的回调} }) } }) } }) }})
因为行为产生的异步申请,导致代码嵌套太深,引发“回调天堂”
导致问题:
1. 代码臃肿,可读性差
2. 耦合度高,可维护性差,难以复用。
3. 回调函数都是匿名函数,不不便调试。
为了解决此问题,咱们应用 promise
promise 中有三种状态,即 Pending,fulfill 和 reject
promise 执行胜利,pending 状态扭转为 fulfilled 状态,promise 执行失败时,pending 变成 rejected 状态。
promise 对象自身就是一个构造函数,能够通过 new 操作符生成 promise 实例。
const promise = new Promise((resolve,reject)=>{// 异步解决申请 if(/ 异步申请标识 /){resolve(); }else{reject(); }})
promise 执行过程中,在承受函数时解决异步申请,而后判断异步申请的后果,如果返回 true,则示意异步申请胜利,调用 resolve()函数,一旦执行,就从 pending 变成 fulling,如果是 false,则示意异步申请失败,调用 reject()函数,reject 函数一旦执行,promise 就会从 pending 变为 reject。
let promise=new Promise(function(resolve,reject){console.log('Promise'); resolve();});promise.then(function(){console.log('resolve');});console.log('hello');
打印后果如下:
Promisees6.js:610 helloes6.js:608 resolve
先执行 hello 再执行 resolve
如果把 resolve()改成 reject,你们 promise.then 会返回 undefined,只会输入 Promise,hello
也就是所有同步代码执行结束后,会执行 then()函数,输入 resolve.
function ajaxGetPromise(url){const promise = new Promise(function(resolve,reject){const handler = function(){if(this.readyState !== 4){return;} // 当状态码为 200 时,示意申请胜利,执行 resolve()函数 if(this.status === 200){// 将申请的响应体作为参数,传递给 resolve()函数 resolve(this.response); }else{// 当状态码不为 200 时,示意申请失败,reject()函数 reject(new Error(this.statusText)); } } // 原生 ajax 操作 const client = new XMLHttpRequest(); client.open("GET",url); client.onreadystatechange = handler; client.responseType="json"; client.setReqestHeader("Accept","application/json"); client.send();}); return promise;
then()和 catch()
解决胜利或者失败的异步解决
then()示意在 promise 实例状态扭转时执行的回调函数。
他有 2 个参数,第一个在 promise 执行胜利后,函数参数通过 resolve()函数传递的参数,第二个参数是可选的,示意 promise 在执行失败后,执行的回调函数。
then()函数返回的是一个新的 promise 实例,因而能够应用链式调用 then()函数,在上一轮 then()函数外部 return 值会作为新一轮的 then()函数承受的参数值。
const promise=new Promise((resolve,reject)=>{resolve(1);});promise.then((result)=>{console.log(result); return 2;}).then((result)=>{console.log(result); return 3;}).then((result)=>{console.log(result); return 4;}).then((result)=>{console.log(result);
catch()函数
catch()函数与 then()函数成对存在,then()函数在 promise 执行胜利后回调,而 catch()函数是 promise 执行失败后回调。
const promise=new Promise((resolve,reject)=>{try{ throw new Error('err11111'); }catch(err){reject(err); }});promise.catch((err)=>{console.log(err);})
只有 promise 执行过程中呈现了异样,就会主动抛出,并触发 reject(err),而不要咱们去应用 try…catch,在 catch()函数中手动调用 reject()函数。
也能够间接改写为如下所示:
const promise=new Promise((resolve,reject)=>{throw new Error('err1111');});promise.catch((err)=>{console.log(err);})
promise.race()
利用多个 Promise 实例,包装成为一个新的实例。
const p = Promise.race([p1, p2, p3]);
只有 p1,p2,p3 中有一个实例率先扭转状态,p 就会跟着扭转,那个率先扭转 promise 实例的返回值,就传递给 p 的回调函数。
如果没有在指定工夫取得后果,就将 promise 的状态变为 reject,否则就是 resolve。
const p=Promise.race([fetch(''), new Promise(function (resolve,reject){setTimeout(() => {reject(new Error('request timeout')) }, 5000); })]);p.then(console.log);p.catch(console.error);
如果在指定工夫没有取得后果,就会将 promise 的状态变成 reject。
promise.reject()
Promise.reject(reason) 办法也会返回一个新的 Promise 实例,该实例的状态为 rejected。
const p=Promise.reject('出错了');p.then(null,function(s){console.log(s);});
生成一个 promise 对象实例,状态为 rejected, 回调函数会立刻执行。
lterator 和 for 循环
汇合的概念,次要是数组和对象 object,ES6 又增加的 Map 和 Set。
他就是一种遍历起器,一种接口,为不同的数据结构提供了对立的拜访机制,任何数据只有部署了 lterator 接口,他就能够实现遍历操作。
作用:
1. 为各种数据提供对立,简便的拜访接口
2. 使得数据结构的成员可能依照某种秩序排列
3.ES6 发明了一种新的遍历命令,for…of 循环。lterator 接口次要提供 for…of 生产。
遍历过程如下:
1. 创立一个指针,指向以后数据结构的起始地位。
2. 第一次调用指针对象的 next 办法,能够将指针指向数据结构的第一个成员。
3. 第二次调用指针对象的 next 办法,指针就指向数据结构的第二个成员。
4. 一直调用指针的 next 办法,直到他指向数据结构的完结位子。
默认的 iterator 接口
为了所有的数据结构,提供了一种对立的拜访机制,即 for…of 循环,当应用 for…of 循环遍历某种数据结构时,该循环就会主动去寻找 lterator 接口。
Symbol.iterator 属性他自身就是一个函数,以后数据结构默认的遍历器生成函数,执行这个函数就会返回一个遍历器。类型为 Symbol 的非凡值,所以要放在方括号外面。
const obj={[Symbol.iterator]:function(){ return { next:function(){return { value:1, done:true} } } }}
原生 iterator 接口的数据结构有 6 种
1.Array
2.Map
3.Set
4.String
5. 函数的 arguments 对象
6.nodeList 对象
let arr = ['a', 'b', 'c'];let iter = arr[Symbol.iterator]();console.log(iter.next()) // {value: 'a', done: false}console.log(iter.next()) // {value: 'b', done: false}console.log(iter.next()) // {value: 'c', done: false}console.log(iter.next()) // {value: undefined, done: true}
应用 [Symbol.iterator] 遍历循环[‘a’, ‘b’, ‘c’]
for…of 循环
只有部署了 Symbol.iterator 属性,就被视作为 iterator 接口,就能够用 for…of 循环他的成员。
数组
原生数组具备了 iterator 接口,for…of 循环实质上就是调用这个接口产生的遍历器。
const arr=['red','green','blue'];const obj={};obj[Symbol.iterator]=arr[Symbol.iterator].bind(arr);for(let v of obj){console.log(v);}
输入后果:red
es6.js:680 green
es6.js:680 blue
Symbol.iterator 属性,后果 obj 的 for…of 循环,产生了与 arr 齐全一样的后果。
set 和 map 构造
他们也具备 iterator 接口,能够间接应用 for…of 循环
let map=new Map().set('a',1).set('b',2);for (let pair of map){console.log(pair);}for(let [key,value]of map){console.log(key +':'+value);}
相似数组的对象
包含 DOM NodeList 对象,arguments 对象。
let str="hello";for(let s of str){console.log(s);}function printArgs(){ for (let x of arguments){console.log(x); }}printArgs('a','b');
Generator 函数
它是 ES6 提供的一种异步编程解决的计划,语法与传统函数不同。
能够把他当成一个状态机。外面封装了多个外部函数状态。
执行 Genertaor 函数会返回一个遍历对象,除了状态机,他还是一个遍历对象生成函数,返回遍历器对象,能够顺次遍历 Generator 函数中的每一个状态。
function 关键字与函数名之间有一个 * 号,函数外部应用 yield 表达式。
function* helloGenerator(){ yield 'hello'; yield 'world'; return 'ending';}var hw=helloGenerator();console.log(hw);
Generator 函数调用后,该函数并不执行,返回的也不是函数运行的后果,而是一个指向外部状态的指针对象。
下一步调用遍历器对象中的 next()办法,使得指针移向下一个状态,每次调用 next 办法,外部指针就从函数头部或者上一次停下来的中央开始执行,始终遇到下一个 yield 表达式(或者为 return)Generator 函数是分段执行的,yield 表达式是暂停执行的标记。next 办法能够复原执行。
yield
yield 表达式前面的表达式,只有调用 next 办法,指针指向该语句时才会执行。
如果 Generator 函数没有应用 yield 表达式,这时候就变成了一个单纯的暂缓执行函数。
function*f(){ console.log('xxxxx')}var generator=f();setTimeout(() => {generator.next()}, 5000);
没有 yield 返回时,变成了一个暂缓执行函数。
异步操作同步化表白
异步操作放在 yield 表达式上面,要等到 next 办法再执行,Generator 函数的一个实际意义就是来解决异步操作,改写回调函数
先把 JSON 反序列化。再申请。
function*main(){ var result=yield request("http:"); var resp=JSON.parse(result); console.log(resp.value);}function request(url){makeAjaxCall(url,function(response){it.next(response); });}var it =main();it.next();
通过 Generator 函数部署 Ajax 操作,能够用同步的形式表白。
class
引入 class 类作为对象的模板,通过 class 关键字,能够定义类。
class Point {constructor(x, y) {this.x = x; this.y = y;} toString() { return '(' + this.x + ',' + this.y + ')';}}
外面的 constructor()是构造方法,而 this 关键字就是代表实例对象。
constructor()办法是类的默认办法,通过 new 生成对象实例的时,主动调用该办法,一个类中必须有 constructor()办法。如果没有,那就会被默认增加。
必须要应用 new。
如果遗记加上 new 就会报错。
实例中的非显示调用在其自身,否则都是定义在 class 上。