ECMAScript 6 之二

目录

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 语言的原生数据类型之一,其他数据类型是:undefinednull、布尔值(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
// B

for(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>

路漫漫其修远兮,吾将上下而求索!

猜你喜欢

转载自blog.csdn.net/weixin_38817361/article/details/131612950