目录
2.6 Symbol
2.7 Map 和 Set
2.8 迭代器和生成器
2.9 Promise对象
2.10 Proxy对象
2.11 async的用法
2.22 类class
2.23 模块化实现
2.6 Symbol
原始数据类型,它表示是独一无二的值。它属于 JavaScript 语言的原生数据类型之一,其他数据类型是:undefined
、null
、布尔值(Boolean)、字符串(String)、数值(Number)、大整数(BigInt)、对象(Object)。
Symbol值通过Symbol() 函数生成。
最大的用途:用来定义对象的私有变量,用Symbol定义的对象中的变量,取值时一定要用 [变量名] 。
let s1 = Symbol('s1');
let obj = {[s1]: '张三'
}
console.log(obj[s1]); // 张三
console.log(obj.s1); // undefined
Symbol值作为属性名,遍历对象的时候,该属性不会出现在for..in,for...of循环中,也不会被Object.keys()等返回。它有一个Object.getOwnPropertySymbols()方法,获取指定对象的所有Symbol属性名,该方法返回一个数组,成员是当前对象的所有用作属性名的Symbol值。
另一个API:Reflect.ownKeys() 方法,可以返回所有类型的键名,包括常规键名和 Symbol 键名。
let s1 = Symbol('s1');
let obj = {[s1]: '张三',[Symbol('s2')]: '李四',s3: '王五'
}
// console.log(obj[s1]); // 张三
// console.log(obj.s1); // undefined// 获取symbol声明的属性名(作为对象的key)
let s = Object.getOwnPropertySymbols(obj);
console.log(s); // [Symbol(s1), Symbol(s2)]
let m = Reflect.ownKeys(obj);
console.log(m); // ['s3', Symbol(s1), Symbol(s2)]
注意:
1、Symbol() 函数不能使用new命令,否则会报错,生成的Symbol是一个原始类型的值,不是一个对象;
2、 由于Symbol值不是对象,不能添加属性。
2.7 Map 和 Set
一、Set 集合
1、Set 集合:表示一个无重复值的有序列表,类似于数组,本身是一个构造函数,用来生成Set数据结构。
let set = new Set();
console.log(set);
2、方法:
1)添加元素
set.add(2);
set.add('4');
set.add('4');
set.add([1,2,3]);
console.log(set); // {2, "4", [1,2,3]}
2)删除元素
// 删除元素
set.delete(2);
console.log(set); //{ "4", [1,2,3]}
3)校验某个值是否在set中,存在true,不存在false
console.log(set.has('4')); //true
4)集合的长度
console.log(set.size); //2
5)将set集合转化为数组
// 将set转换成数组
let set2 = new Set([1,1,2,3,3,4,5,5]);
let arr = [...set2];
console.log(arr); // [1, 2, 3, 4, 5]
6)清除所有成员,没有返回值
set.clear();
7)WeakSet
WeakSet结构与Set类似,也是不重复的值的集合。可以用于储存DOM节点,而不用担心这些节点从文档移除时会引发内存泄漏。
(1)WeakSet 的成员只能是对象,而不能是其他类型的值;
(2)WeakSet 中的对象都是弱引用;
(3)不可迭代;
(4)没有forEach();
(5)没有size属性。
let set3 = new WeakSet(), obj = {};
set3.add(obj);
// 释放当前的资源
obj = null;
console.log(set3);
二、Map 类型
Map类型是键值对的有序列表,键和值是任意类型,类似于对象。
let map = new Map();
map.set('name','张三');
map.set('age',20);
console.log(map); // {'name' => '张三', 'age' => 20}
console.log(map.get('name')); // 张三
map.has('name'); // true
map.delete('name');
console.log(map); //{'age' => 20}
map.clear();
console.log(map); //{size: 0}map.set(['a',[1,2,3]],'hello');
console.log(map); //{Array(2) => 'hello'}let m = new Map([['a',1],['c',2]]);
console.log(m); //{'a' => 1, 'c' => 2}
遍历方法:
1、.keys() 返回键名的遍历器
2、.values() 返回键值的遍历器
3、.entries() 返回所有成员的遍历器
4、.forEach() 遍历Map的所有成员
let m = new Map([['A',1],['B',2]]
)
for(let key of m.keys()){console.log(key);
}
// A
// Bfor(let val of m.values()){console.log(val);
}
// 1
// 2
for(let item of m.entries()){console.log(item);console.log(item[0],item[1]);
}
// ['A', 1]
// A 1
// ['B', 2]
// B 2
m.forEach((val,key,map)=>{console.log(val,key,map);
})
// 1 'A' {'A' => 1, 'B' => 2}
// 2 'B' {'A' => 1, 'B' => 2}
.forEach() 方法可以接受第二个参数,用来绑定this
const reporter = {report: function(key, value) {console.log("Key: %s, Value: %s", key, value);}
};m.forEach(function(value, key, map) {this.report(key, value);
}, reporter);
// Key: A, Value: 1
// Key: B, Value: 2
Map 结构转为数组结构,使用扩展运算符
let m0 = new Map([[1,'one'],[2,'two'],[3,'three']
]);
console.log([...m0.keys()]); //[1, 2, 3]
console.log([...m0.values()]); //['one', 'two', 'three']
console.log([...m0.entries()]); //[[1,'one'], [2, 'two'], [3, 'three']]
console.log([...m0]); //[[1,'one'], [2, 'two'], [3, 'three']]
2.8 迭代器和生成器
一、 Iterator 迭代器
一种新的遍历机制,两个核心:
1. 迭代器是一个接口,能快捷的访问数据,通过Symbol.iterator来创建迭代器,通过迭代器的next() 获取迭代之后的结果;
2. 迭代器是用于遍历数据结构的指针(数据库的游标)。
const items = ['one','two','three','four'];
const ite = items[Symbol.iterator]();
console.log(ite.next()); //{value: 'one', done: false} done如果为false表示遍历继续,如果为true表示遍历完成
console.log(ite.next()); // {value: 'two', done: false}
console.log(ite.next()); // {value: 'three', done: false}
console.log(ite.next()); // {value: 'four', done: false}
console.log(ite.next()); // {value: undefined, done: true}
二、生成器 Generator
可以通过yield关键字,将函数挂起,为改变执行流程提供了可能,同时为做异步编程提供了方案。
与普通函数的区别:
1. function 后面,函数名之前有个 * ;
2. 只能在函数内部使用 yield 表达式,让函数挂起。
function* func(){yield 2;yield 3;
}
// 返回一个遍历器对象,可以调用next()
let fn = func();
console.log(fn.next());//{value: 2, done: false}
console.log(fn.next());//{value: 3, done: false}
console.log(fn.next());//{value: undefined, done: true}// generator函数是分段执行的,yield语句是暂停执行,而next() 是恢复执行
function* add(){let x = yield '2';// x 不是yield '2'的返回值,它是next() 调用,恢复当前 yield 执行传入的实参console.log("one:",x);let y = yield '3';console.log("two:",y);return x+y;
}
const fn = add();
console.log(fn.next()); // {value: '2', done: false}
console.log(fn.next(20)); // {value: '3', done: false}
console.log(fn.next(30)); // {value: 50, done: true}
// 使用场景:为不具备Interator接口的对象提供了遍历的操作
function* objectEntries(obj){// 获取对象所有的key保存到数组 const propKeys = Object.keys(obj);for(const propkey of propKeys){yield [propkey,obj[propkey]]}
}
const obj = {name: '张三',age: 18
}
obj[Symbol.iterator] = objectEntries;
console.log(obj);
for(let [key,value] of objectEntries(obj)){console.log(`${key}:${value}`);
}
//name:张三
//age:18
2.9 Promise对象
一、介绍
Promise 是异步编程的一种解决方案,它由社区最早提出和实现,ES6 将其写进了语言标准,统一了用法,原生提供了Promise对象。
相当于一个容器,保存着未来才会结束的事件(异步操作)的一个结果。
各种异步操作都可以用同样的方法进行处理 axios。
特点:
1、对象的状态不受外界影响,处理异步操作三个状态:pending(进行中)、fulfilled(resolved)(成功)、rejected(失败)。
2、pending(进行中)、fulfilled(resolved)(成功)、rejected(失败)一旦状态改变,就不会再变,任何时候都可以得到这个结果。
let pro = new Promise(function(resolved,rejected){// 执行异步操作
});
console.log(pro);
二、基本使用
let pro = new Promise(function(resolved,rejected){// 执行异步操作let res = {//code: 200,code: 201,data:{name: '张三',age: 20},error:'失败了!'}setTimeout(()=>{if(res.code == 200){resolved(res.data);}else{rejected(res.error);}},1000)
});
console.log(pro);
// then()方法
// 第一个参数是resolve回调函数,第二个参数是可选的,是reject状态回调函数
// 返回的是一个新的promise实例,可以采用链式编程
pro.then((val)=>{console.log(val); //{name: '张三', age: 20}
},(err)=>{console.log(err); //失败了!
})
const pro = new Promise(function(resolve,reject){throw new Error('test');
})
pro.catch(function(err){console.log(err); //Error: test
})
const promise = new Promise(function(resolve, reject) {try {throw new Error('test');} catch(e) {reject(e);}
});
promise.catch(function(error) {console.log(error);
});
方法:
1、resolve() 能将现有的任何对象转换成promise对象
let p = Promise.resolve('foo');
let p1 = new Promise(resolve => resolve('foo'));
console.log(p);
console.log(p1);
2、reject() 同resolve()方法
3、all() 用于将多个 Promise 实例,包装成一个新的 Promise 实例。
const p = Promise.all([p1, p2, p3]);
1)p1、p2、p3都是Promise实例,如果不是,会先调用Promise.resolve()方法,将参数转为Promise实例,再进一步处理。参数可以不是数组,但必须具有Iterator接口,且返回的每个成员都是Promise实例。
2)只有三个参数p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,三参的返回值组成一个数组,传递给p的回调函数。
3)三参中只要有一个rejected,p的状态就是rejected,此时第一个被reject的实力的返回值传递给p的回调函数。
4)多应用与游戏霍素材比较多时,等待图片、falsh、静态资源文件都加载完成,才进行页面的初始化。
4、race() 给某个异步请求设置超时时间,并且在超时后执行相应的操作
function requestImg(imgSrc){return new Promise((resolve,reject)=>{const img = new Image();img.onload = function(){resolve(img);}img.src = imgSrc;})
}
function timeout(){return new Promise((resolve,reject)=>{setTimeout(()=>{reject(new Error('图片请求超时'));},3000)})
}
Promise.race([requestImg('img.png'),timeout()]).then(data=>{console.log(data);document.body.appendChild(data);
}).catch(err=>{console.log(err); //Error: 图片请求超时
})
5、finally() 用于指定不管 Promise 对象最后状态如何,都会执行的操作。该方法是 ES2018 引入标准的。
2.10 Proxy对象
一、介绍
用于修改某些操作的默认行为,等同于在语言层面做出修改,所以属于一种“元编程”(meta programming),即对编程语言进行编程。
在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。Proxy 这个词的原意是代理,用在这里表示由它来“代理”某些操作,可以译为“代理器”。
二、方法
1、get() 用于拦截某个属性的读取操作
var proxy = new Prosy({},{// target - 目标对象; propKey - 属性名;proxy实例本身,可选get:function(target,propKey,[proxy]){}
});
2、set() 用来拦截某个属性的赋值操作,接收四个参数:目标对象、属性名、属性值和proxy实例本身,最后一个参数可选。
2.11 async的用法
一、async 异步操作
作用:使得异步操作更加方便。
基本操作 async 返回一个Promise对象
async是Genterator的一个语法糖
async function f(){// await不能单独使用,必须要在async中// return await 'hello async';let s = await 'hello async';let data = await s.split('');return data;
}
// 如果async函数中有多个await 那么then函数会等待所有的await指令执行完的结果才去执行
f().then(v=>console.log(v)).catch(e=>console.log(e));
// ['h', 'e', 'l', 'l', 'o', ' ', 'a', 's', 'y', 'n', 'c']
async function f2(){// throw new Error('出错了');await Promise.reject('出错了');await Promise.resolve('hello');
}
// 只要有一个await命令进入reject就不会继续执行
f2().then(v=>console.log(v)).catch(e=>console.log(e)); // 出错了
如果想要继续执行,修改代码如下:
async function f2(){// throw new Error('出错了');try {await Promise.reject('出错了');} catch (error) {}return await Promise.resolve('hello');
}
// 只要有一个await命令进入reject就不会继续执行
f2().then(v=>console.log(v)).catch(e=>console.log(e)); // hello
2.22 类class
通过class关键字,可以定义类,是一个语法糖。
class Person{// 实例化的时候会立即被调用constructor(name,age){this.name = name;this.age = age;}// sayName(){// return this.name;// }// sayAge(){// return this.age;// }}
// 通过Object.assign()方法一次性向类中添加多个方法
Object.assign(Person.prototype,{sayName(){return this.name;},sayAge(){return this.age;}
})
let p1 = new Person('张三',20);
console.log(p1);
console.log(p1.sayName()); // 张三
console.log(p1.sayAge()); // 20
类的继承
// 使用关键字extends
class Animal{constructor(name,age){this.name = name;this.age = age;}sayName(){return this.name;}sayAge(){return this.age;}
}
class Dog extends Animal{constructor(name,age,color){super(name,age); // 相当于Animal.call(this,name,age);this.color = color;}// 子类自己的方法sayColor(){return `${this.name},${this.age}个月,颜色是${this.color}`;}// 重写父类的方法sayName(){return this.name + super.sayAge() + this.color;}
}
let dog = new Dog('杜宾',12,'black');
console.log(dog); //{name: '杜宾', age: 12, color: 'black'}
console.log(dog.sayName()); // 杜宾
console.log(dog.sayColor()); //杜宾,12个月,颜色是black
console.log(dog.sayName()); //杜宾12black
2.23 模块化实现
ES6 module 两个命令构成:export 和 import
export 用于规定模块的对外接口,import用于输入其他模块提供的接口
一个模块就是一个独立的文件
index.js
export const name = '张三';
export const age = 18;
// 函数抛出在函数前面增加export
export function sayName(){return 'my name is 哈哈哈';
}
// 或抛出一个对象
function sayAge(){return 19;
}
export {sayAge}
class Person{constructor(){}sayColor(){console.log("red");}
}
export default Person;
1.html
<script type="module">
import Person,{name,age,sayName,sayAge} from './index.js';
console.log(name,age,sayName(),sayAge()); // 张三 18 my name is 哈哈哈 19
const p = new Person();
p.sayColor(); //red
</script>