ES6学习记录2,扩展的对象的功能,Symbol,set, WeakSet, Map,数组的扩展功能,Iterator迭代器,generator函数,next 方法的参数, Promise及方法

扩展的对象的功能

1、ES6直接写入变量和函数,作为对象的属性和方法。

const name = "lw",age = 21;
    const  person = {
        name,//等价于name:name
        age,
        sayName(){
            console.log(this.name);
        }
    }
    person.sayName();//lw
function fn(x,y) {
        return{x,y};
    }
    console.log(fn(10,20));//Object { x: 10, y: 20 }

2、属性名的表达式

const name = "a";
    const obj = {
        isShow:true,
        [name+"nc"]:123,
        ["f"+name]() {
            console.log(this);
        }
    }
    console.log(obj);

3、对象的方法
is()等价于===,比较两个值是否严格相等

console.log(Object.is(NaN,NaN));

assign(),对象的合并Object.assign(target,obj1,obj2)把obj1,obj2合并到target,返回合并之后的新对象。

    let newObj = Object.assign({}, {name:"lw"}, {age:12});
    console.log(newObj);//Object { name: "lw", age: 12 }

Symbol

原始数据类型,它表示是独一无二的值。
最大用途:用来定义对象的私有变量

    const  name = Symbol("name");
    const  name2 = Symbol("name");
    console.log(name === name2);//false

如果用Symbol定义的对象中的变量,取值时一定要用[变量名]

 let s1 = Symbol("s1");
    let obj = {
        [s1]:"lw"
    };   
console.log(obj[s1]);//lw

可以利用Object.getOwnPropertySymbols(对象名)Reflect.ownKeys(对象名)取该被Symbol定义的对象中的变量。

    let s1 = Symbol("s1");
    let obj = {};
    obj[s1]="lw";
    console.log(obj[s1]);//lw
    let s = Object.getOwnPropertySymbols(obj);
    console.log(s[0]);//Symbol("s1")
    let m = Reflect.ownKeys(obj);
    console.log(m[0]);

set

集合:表示无重复值的有序列表

    let set = new Set();
    //添加元素
    set.add(3);
    set.add([1,2,3])
    //删除元素
    set.delete(2);
    //校验某个值是否在set中
    console.log(set.has(4));
    //set的长度
    console.log(set.size);
    //将set转换成数组
    let set2 = new Set([1,2,"d",4,4,4,6]);
    console.log(set2);//Set(5) [ 1, 2, "d", 4, 6 ]
    //扩展运算符
    let arr = [...set2]
    console.log(arr);//Array(5) [ 1, 2, "d", 4, 6 ]

注意:set中对象的引用无法被释放

    let set3 = new Set(),obj={};
    set3.add(obj);
    //释放当前资源
    obj = null;
    console.log(set3);//Set [ {} ],未被释放

WeakSet

1、不能传入非对象类型的参数
2、不可迭代
3、没有forEach()
4、没有size属性

Map

Map类型是键值对的有序数列,键和值是任意的类型。

    let map = new Map();
    map.set("name","lw");
    map.set("age","23");
    console.log(map.get("name"));
    //校验
    map.has("name");
    //删除
    map.delete("name");
    //直接清楚
    map.clear();
    console.log(map);//Map(0)
    let m = new Map([
        ["a",1],
        ["b",2]
        ]);
    console.log(m);//Map { a → 1, b → 2 }

事实上,不仅仅是数组,任何具有 Iterator 接口、且每个成员都是一个双元素的数组的数据结构都可以当作Map构造函数的参数。这就是说,Set和Map都可以用来生成新的 Map。

    const set = new Set([
        ['foo', 1],
        ['bar', 2]
    ]);
    const m1 = new Map(set);
    console.log( m1.get('foo')) // 1

    const m2 = new Map([['baz', 3]]);
    const m3 = new Map(m2);
    console.log(m3.get('baz')) // 3

注意:
1、如果对同一个键多次赋值,后面的值将覆盖前面的值。
2、Map 的键实际上是跟内存地址绑定的,只要内存地址不一样,就视为两个键。

数组的扩展功能

数组的方法 from()

将伪数组转换成真正的数组

    function add() {
        // console.log(arguments);
        //es5中转换
        // let arr = [].slice.call(arguments);
        // console.log(arr);

        //es6中转换
        let arr = Array.from(arguments);
        console.log(arr);
    }
    add(1,3,4)
    let lis = document.querySelectorAll("li");
    console.log(Array.from(lis));
    //用扩展运算符将伪数组转换成真正的数组
    console.log([...lis]);

from()还可以接收第二个参数,用来对每个元素进行处理。

    let arr2 = Array.from(lis,bc => bc.textContent);
    console.log(arr2);

of()

将任意的数据类型转换到数组

let arr3 = Array.of(2,3,[1,2,4],"lw",{id:1});
    console.log(arr3);

copywithin()

数组内部将制定位置的元素复制到其他的位置,返回当前的数组。

console.log([1,2,3,4,5,7,44].copyWithin(0,3));//用索引为3及以后的值替换索引为0及以后相应位置的值

find()

找出第一个符合条件的数组成员

let num = [1,3,4,5,-2,3-39,0].find(n => n<0);
console.log(num)//-2

findIndex()

找出第一个符合条件的数组成员的索引

let num = [1,3,4,5,-2,3-39,0].findIndex(n => n<0);
console.log(num)//4

entries() keys() values()

返回一个遍历器,可以使用for…of循环进行遍历
keys() 是对键名遍历

for(let index of[1,2,45,6,"a","b"].keys()){
       console.log(index);0 1 2 3 4 5
   }

values() 对值遍历

for(let index of[1,2,45,6,"a","b"].values()){
        console.log(index);//1,2,45,6,a,b
    }

entries() 对键值对遍历

for(let index of[1,2,45,6,"a","b"].entries()){
    console.log(index);//Array [ 0, 1 ][ 1, 2 ][ 2, 45 ][ 3, 6 ][ 4, "a" ][ 5, "b" ]
}

next()方法,遍历一次得到相应的值,超出范围返回undefind。

let letter = ["a","b","c"];
let it = letter.entries();
console.log(it.next().value);

include()

返回一个布尔值,表示某个数组是否包含给定的值。

console.log([1,2,3].includes(2));

之前indexOf(),包含取1,不包含取-1

console.log([1,2,3].indexOf(9));

Iterator迭代器

是一种新的遍历机制,有两个核心
1、迭代器是一个接口,能快捷访问数据,通过Symbol.iterator创建迭代器,通过迭代器的next()获得迭代器的结果。
2、迭代器是用于遍历数据结构的指针(数据库的游标)

//使用迭代
    const items = ["one","two","three"];
    //1、创建新的迭代器
    const ite = items[Symbol.iterator]();
    console.log(ite.next())
    //value: "one", done: false ,done如果为false表示遍历继续,如果为true表示遍历完成

注意:一个对象如果要具备可被for…of循环调用的 Iterator 接口,就必须在Symbol.iterator的属性上部署遍历器生成方法(原型链上的对象具有该方法也可)。

Iterator迭代器

for…of循环可以使用的范围包括数组、Set 和 Map 结构、某些类似数组的对象(比如arguments对象、DOM NodeList 对象)、后文的 Generator 对象,以及字符串。
JavaScript 原有的for…in循环,只能获得对象的键名,不能直接获取键值。ES6 提供for…of循环,允许遍历获得键值。

  var arr = ['a', 'b', 'c', 'd'];
    for (let a in arr) {
        console.log(a); // 0 1 2 3
    }
    for (let a of arr) {
        console.log(a); // a b c d
    }

注意:for…of循环调用遍历器接口,数组的遍历器接口只返回具有数字索引的属性。这一点跟for…in循环也不一样。

generator函数

可以通过yield关键字,将函数挂起,为了改变执行流提供了可能,同时为了做异步编程提供了方案。
与普通函数的区别:
1、function后面 函数名之前有个*
2、函数体内部使用yield表达式,定义不同的内部状态(yield在英语里的意思就是“产出”)。

    function* func() {
        yield  2;
    }
    //返回一个遍历器对象 可以调用next()
    let o = func();
    console.log(o.next());

总结:generator函数是分段执行的,yield语句是暂停执行,而next()恢复执行。
注意:
1、x不是yield "2"的返回值,它是next()方法调用恢复当前yield()执行传入的实参。
2、next()仿佛带的参数会被当作上一个yield表达式的返回值。
使用场景:为不具备Interator接口的对象提供了遍历操作

function* objectEntries(obj) {
        //获取对象所有的key保存到数组
        const propKeys = Object.keys(obj);
        for(const propkey of propKeys){
            yield [propkey,obj[propkey]]
        }
    }
    const obj ={
        name:"lw",
        age:11
    }
    obj[Symbol.iterator] = objectEntries;
    console.log(obj);
    for (let [key,value] of objectEntries(obj)){
        console.log(`${key},${value}`);
    }

遍历器对象的next方法的运行逻辑如下:
(1)遇到yield表达式,就暂停执行后面的操作,并将紧跟在yield后面的那个表达式的值,作为返回的对象的value属性值。
(2)下一次调用next方法时,再继续往下执行,直到遇到下一个yield表达式。
(3)如果没有再遇到新的yield表达式,就一直运行到函数结束,直到return语句为止,并将return语句后面的表达式的值,作为返回的对象的value属性值。
(4)如果该函数没有return语句,则返回的对象的value属性值为undefined。

Generator 函数可以不用yield表达式,这时就变成了一个单纯的暂缓执行函数。

function* f() {
  console.log('执行了!')
}
var generator = f();
setTimeout(function () {
  generator.next()
}, 2000);
next 方法的参数

yield表达式本身没有返回值,或者说总是返回undefined。next方法可以带一个参数,该参数就会被当作上一个yield表达式的返回值。

    function* add() {
        console.log("start");
        let x = yield "2";
        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(10));//value: "3", done: false
    console.log(fn.next(20));//value: 30, done: true

for…of循环可以自动遍历 Generator 函数运行时生成的Iterator对象,且此时不再需要调用next方法。

function* foo() {
  yield 1;
  yield 2;
  yield 3;
  yield 4;
  yield 5;
  return 6;
}

for (let v of foo()) {
  console.log(v);
}
// 1 2 3 4 5

异步和同步

所谓"异步",简单说就是一个任务不是连续完成的,可以理解成该任务被人为分成两段,先执行第一段,然后转而执行其他任务,等做好了准备,再回过头执行第二段。相应地,连续的执行就叫做同步。由于是连续执行,不能插入其他任务,所以操作系统从硬盘读取文件的这段时间,程序只能干等着。

Promise 承诺

相当于一个容器,保存着未来才会结束的事件(异步操作)的一个结果。
Promise对象的两个特点:
1、对象的状态不受外界影响。处理异步操作,三种状态:pending(进行中)、resolved(已成功)和rejected(已失败)
2、一旦状态改变,就不会再变,任何时候都可以得到这个结果。两种可能:从pending变为fulfilled和从pending变为rejected。

执行过程:Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject。Promise实例生成以后,可以用then方法分别指resolved状态和rejected状态的回调函数。

以下是指定多少秒后,状态从进行中变为已成功或失败,分别返回不同的值。

function timeout(ms) {
        return new Promise((resolve, reject) => {
            setTimeout(()=>{
                if(ms<=1000){
                    resolve("已经过了"+ms+"秒了");}
                else{
                reject("超时了")}},ms);
        });
    }
    //指定状态转换之后的操作
    timeout(1200).then((value) => {
        console.log(value);},
        (error) =>{
        console.log(error)
    });//超时了

用Promise对象实现的 Ajax 操作的例子

const getJSON = function(url) {
  const promise = new Promise(function(resolve, reject){
    const handler = function() {
      if (this.readyState !== 4) {
        return;
      }
      if (this.status === 200) {
        resolve(this.response);
      } else {
        reject(new Error(this.statusText));
      }
    };
    const client = new XMLHttpRequest();
    client.open("GET", url);
    client.onreadystatechange = handler;
    client.responseType = "json";
    client.setRequestHeader("Accept", "application/json");
    client.send();

  });
  return promise;
};

getJSON("/posts.json").then(function(json) {
  console.log('Contents: ' + json);
}, function(error) {
  console.error('出错了', error);
});

采用链式的then,可以指定一组按照次序调用的回调函数。这时,前一个回调函数,有可能返回的还是一个Promise对象(即有异步操作),这时后一个回调函数,就会等待该Promise对象的状态发生变化,才会被调用。

resolve() reject()

能将现有的任何对象转换成promise对象。

let p = new Promise(resolve => resolve("123"));
    p.then((data)=>{
        console.log(data);
    });
all()

应用:一些游戏素材较多,等待图片等资源文件都加载完成,然后才进行页面的初始化

let p1 = new Promise((resolve, reject) => {});
    let p2 = new Promise((resolve, reject) => {});
    let p3 = new Promise((resolve, reject) => {});
    
    let p4 =Promise.all([p1,p2,p3])
    
    p4.then(()=>{
        //三个都成功才能成功
    }).catch(err=>{
        //只要有一个失败就失败
    })
race()

给某个异步请求设置超时时间,并且在超时后执行相应的操作。Promise.race()方法的参数与Promise.all()方法一样,如果不是 Promise 实例,就会先调用下面讲到的Promise.resolve()方法,将参数转为 Promise 实例,再进一步处理。

  const p = Promise.race([
  fetch('/resource-that-may-take-a-while'),
  new Promise(function (resolve, reject) {
    setTimeout(() => reject(new Error('request timeout')), 5000)
  })
]);

p
.then(console.log)
.catch(console.error);
finally()

finally()方法用于指定不管 Promise 对象最后状态如何,都会执行的操作。finally本质上是then方法的特例。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小婵婵不怕鬼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值