es 知识点解读

let 和 const

作用域的概念

  • 全局作用域
  • 函数作用域
  • 块作用域
    如何使用let和const

使用let

1、形成块级作用域
2、es6下强制开启严格模式,而在es5下,需要"use strice"才能开启严格模式;

const

1、声明的常量不能修改;但是对象可以修改,因为对象是对地址的引用,我们可以在内存空间中更改对象

function last() {
           const k={
               a:1
           };
           k.a=123;
           console.log(k)
}

2、声明的时候,必须赋值;
3、const也有块作用域的概念;

Symbol

Symbol的概念:用这种方式声明的数据类型,永远是独一无二的值;

Symbol的作用:避免属性名相同的问题
注意:对象中,有用到symbol做key值的话,是取不到的;即let...of只能拿到非Symbol对象的值;

    let a1=Symbol.for('abc');
    let obj={
        [a1]:'123',
        'abc':345,
        'c':456
    };
    console.log(obj)
    for(let [key,value] of Object.entries(obj) ){
        console.log('let of',key,value)
    }

解决办法:通过以下代码可以取到Symbol的值;Object.getOwnPropertySymbols可以拿到Symbol对象的值;

    Object.getOwnPropertySymbols(obj).forEach(function (item) {
        console.log(obj[item])
    })

返回了所有key和value值;通过es6最增的Reflect.ownKeys(obj)

    Reflect.ownKeys(obj).forEach(function (item) {
        console.log(item,obj[item])
    });//返回了所有key和value值;

Set的用法

Set的用法:set数据类型的元素,必须是唯一的;添加重复的元素不会报错,只是不会生效;

他在转换元素的时候,不会进行数据类型的隐式转换;
可以用它来去重;

let arr=[1,2,3,4,2,1,2,3,2];
let list=new Set(arr);
console.log(list)

Set()实例的方法:

1、add() 添加元素
2、delete() 移出
3、clear() 清空
4、has() 判断元素中是否有某个内容

let arr=['add','delete','clear','has'];
let list=new Set(arr);
console.log(list.has('add'))
console.log(list.delete('add'),list)
console.log(list.clear(),list)

Set实例的遍历

//1:遍历属性名
for(let key of list.keys()){
    console.log(key)
}
//2:遍历属性值
for(let value of list.values()){
    console.log(value)
}
//3:遍历属性名和属性值

for(let [key,value] of list.entries()){
    console.log(key,value)
}

Set实例的 forEach

list.forEach(function (item) {
    console.log(item)
})

WeakSet的用法

let weakList=new WeakSet()

WeakSet和set的区别:

1、WeakSet和set支持的数据类型不一样;
2、WeakSet中的对象都是若引用;不会检测地址是否被垃圾回收掉;
3、他的属性,没有size属性,没有clear方法,不能遍历;

Map的用法

map的属性名可以是任意数据类型;
map增加值,用set,获取值用get
map的两种写法
//第一种写法:
let map=new Map();
let arr=['123'];
map.set(arr,456);
console.log('map',map,map.get(arr))

//第二种写法
let map=new Map([['a',123],['b',456]])
console.log(map)
map常用的属性值和方法
map.size 长度
set设置,get获取
delete() 删除; clear()清空
WeakMap的用法

weakMap和map的区别:

前者接收的值只能是对象
他没有set属性,不能使用clear()
不能遍历; 跟weakSet和set的区别一样;

数据结构-和数组的对比

Map与Array的对比,从增删改查出发

//数据结构横向对比,增,查,改,删
let map=new Map();
let ary=[];
//增
map.set('t',1);
ary.push({t:1});
//console.info('map-array',map,ary)
//查
let map_exits=map.has('t');
let ary_exites=ary.find(item=>item.t);
/*console.log(map_exits)  //返回true,表示存在
console.log(ary_exites) //返回当前对象*/
//改
map.set('t',2);
ary.forEach(item=>item.t?item.t=2:'');
console.log(map,ary)
//删除
map.delete('t');
let index=ary.findIndex(item=>item.t);
ary.splice(index,1);
console.log(map,ary)

Set与Array的对比

let set=new Set();
let ary=[];
let item={t:1};
//增加
set.add(item);
ary.push({t:1})
console.log(set,ary)
//查
let set_exist=set.has(item);
let ary_exist=ary.find(item=>item.t)
console.log(set_exist,ary_exist)
//改
set.forEach(item=>item.t?item.t=2:'');
ary.forEach(item=>item.t?item.t=2:'');
//删
set.forEach(item=>item.t?set.delete(item):'');
let index=ary.findIndex(item=>item.t)
ary.splice(index,1)
console.log(set,ary)

数据结构- 和对象Object的对比

###Map,Set与Object的对比

//map,set,object对比
let item={t:1};
let set=new Set();
let map=new Map();
let obj={};
//增
map.set('t',1);
set.add(item);
obj['t']=1;
console.log('map-set-obj',map,set,obj)

//查
console.info({
    map_exist:map.has('t'),
    set_exist:set.has(item),
    obj_exist:'t' in obj
})
//改
map.set('t',2);
item.t=2;
obj['t']=2;
console.log('map-set-obj',map,set,obj)
//删
map.delete('t')
set.delete(item)
delete obj['t'];
console.log('map-set-obj',map,set,obj)

小总结:数据开发中,涉及数据结构,能使用map,不使用数组;如果对数据要求比较高,比如数据唯一性,考虑使用

类的基本定义和生成实例: class

class Parent{
    constructor(name='leilei'){
        this.name=name;
    }
}
let v_parent=new Parent('ymy');
console.log(v_parent.name)

类的继承: extends

class Parent{
    constructor(name='leilei'){
        this.name=name;
    }
}
class Child extends Parent{
    //继承:子类怎么在自己的构造函数中传递参数
    constructor(name='child'){
        super(name);//如果不传参,子类使用的是父类默认的参数;super一定放在构造函数的第一行;
        this.type='child';
    }
}
console.dir(new Child('hello'))

类中的getter和setter

分别用来获取属性和设置属性

class Parent{
  constructor(name='leilei'){
      this.name=name;
  }
  get longName(){
      return 'ymy '+this.name;
  }
  set longName(value){
      this.name=value;
  }
}
// 创建实例
let p1=new Parent();
console.log(p1.longName) //获取属性
p1.longName='tangtang'; //设置属性

给类中添加静态方法 static

注意:static属性只能用来设置类的静态方法,不能用来设置类的静态属性
类的静态属性只能通过: 类.key=value;来设置
类的静态方法,只有类能使用,实例不能使用,实例只能使用原型上的属性和方法;

class Parent{
  constructor(name='leilei'){
      this.name=name;
  }
  //设置静态方法
  static tell(){
      console.log('tell');
  }
}
Parent.sex='gril';  //设置类的静态属性
Parent.tell() //调用类的静态方法;

es6 Iterator 和 for...of 循环

什么是Iterator接口

ES6中内置了一些Symbol,其中最重要的一个恐怕就是Symbol.iterator了,相当于迭代器的接口,只有对象里有这个symbol的属性,才可以认为此对象是可迭代的。
我们先看一下规范中对这个symbol的描述:
A method that returns the default Iterator for an object. Called by the semantics of the for-of statement.
js中哪些对象里实现了这个接口呢?常见的有Array,String,arguments,还有后面高级的数据结构,如Set,Map等。

Iterator的基本用法

for...of

for...of循环的过程,其实就是通过不断调用Iterator接口来达到这种形式;
也就是说,不同的数据结构,通过for...of这种统一的形式,来达到读取不同数据结构的目标;但是背后的Iterator接口其实不同;
数组自动帮我们带了iterator接口

let arr=['hello','world'];
let map=arr[Symbol.iterator]();
console.log(map.next());
console.log(map.next());
console.log(map.next());

Object {value: "hello", done: false};done代表,是否做完了所有操作,true:代表是; false:代表无,还有其他操作;

Object对象不是一个iterator,那么如何把它变成一个iterator呢?

let obj={
   start:[1,3,2],
    end:[7,8,9],
    [Symbol.iterator](){
        let self=this;
        let index=0;
        let arr=self.start.concat(self.end);
        let len=arr.length;
        return {
            next (){
                if(index<len){
                    return {
                        value:arr[index++],
                        done:false
                    }
                }else{
                    return {
                        value:arr[index++],
                        done:true
                    }

                }
            }
        }
    }
}
for(let key of obj){
    console.log(key);
}

let...of的使用

let arr=['hello','world'];
for(let value of arr){
   console.log(value);
}

Generator

基本概念

Generator函数有多种理解角度。从语法上,首先可以把它理解成,Generator函数是一个状态机,封装了多个内部状态。

执行Generator函数会返回一个遍历器对象,也就是说,Generator函数除了状态机,还是一个遍历器对象生成函数。返回的遍历器对象,可以依次遍历Generator函数内部的每一个状态。

形式上Generator函数是一个普通函数,但是有两个特征。
function关键字与函数名之间有一个星号*;
函数体内部使用yield语句,定义不同的内部状态(yield语句在英语里的意思就是“产出”)。

let tell=function* () {
    yield 'a';
    yield 'b';
    yield 'c';
};
let k=tell();
console.log(k.next());
console.log(k.next());
console.log(k.next());
console.log(k.next());

上面代码定义了一个Generator函数tell,它内部有三个yield语句'a','b'和'c' ; 即该函数有三个状态:'a','b'和'c'语句(结束执行)。

总结一下,调用Generator函数,返回一个遍历器对象,代表Generator函数的内部指针。以后,每次调用遍历器对象的next方法,就会返回一个有着value和done两个属性的对象。value属性表示当前的内部状态的值,是yield语句后面那个表达式的值;done属性是一个布尔值,表示是否遍历结束。true:表示遍历结束,false:表示遍历没结束;

yield

需要注意的是,yield语句后面的表达式,只有当调用next方法、内部指针指向该语句时才会执行,因此等于为JavaScript提供了手动的“惰性求值”(Lazy Evaluation)的语法功能。

function* gen() {
yield 123 + 456;
}
上面代码中,yield后面的表达式123 + 456,不会立即求值,只会在next方法将指针移到这一句时,才会求值。

yield语句注意事项

yield语句不能用在普通函数中,否则会报错。
yield语句如果用在一个表达式之中,必须放在圆括号里面。
console.log('Hello' + yield); // SyntaxError
console.log('Hello' + yield 123); // SyntaxError

console.log('Hello' + (yield)); // OK
console.log('Hello' + (yield 123)); // OK
yield语句用作函数参数或赋值表达式的右边,可以不加括号。
foo(yield 'a', yield 'b'); // OK
let input = yield; // OK
暂缓执行函数

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

function* f() {
  console.log('执行了!')
}

var generator = f();

setTimeout(function () {
  generator.next()
}, 2000);

上面代码中,函数f如果是普通函数,在为变量generator赋值时就会执行。但是,函数f是一个Generator函数,就变成只有调用next方法时,函数f才会执行。

Generator 与 Iterator接口的关系

任意一个对象的Symbol.iterator方法,等于该对象的遍历器生成函数,调用该函数会返回该对象的一个遍历器对象。

由于Generator函数就是遍历器生成函数,因此可以把Generator赋值给对象的Symbol.iterator属性,从而使得该对象具有Iterator接口。

//generator对象的新应用:给obj对象部署Iterator;

let obj={};
obj[Symbol.iterator]=function* () {
    yield 1;
    yield 2;
    yield 3;
};
for(let value of obj){
    console.log(value);
}

用Generator写抽奖

let draw=function (count) {
    //具体抽奖逻辑
    console.info(`剩余${count}抽奖次数`);
};
let residue=function* (count) {
    while(count>0){
        count--;
        yield draw(count);
    }
};
let star=residue(5);
let btn=document.createElement('button');
btn.innerHTML='点击抽奖';
document.body.appendChild(btn);
btn.onclick=function () {
    star.next();
}

前端定时的去接收服务端的变化

两种办法:1)websocket-兼容性不好 ; 2)常轮询-看如下代码

let ajax=function* () {
    yield new Promise((resolve,reject)=>{
        setTimeout(function () {
            resolve({code:0})
        },200)
    })
};
let pull=function () {
    let generator=ajax();
    let step=generator.next();
    //拿回后台的数据
    step.value.then(function (d) {
        if(d.code!=0){
            setTimeout(function () {
                console.info('wait');
                pull();
            },1000)
        }else{
            console.log(d);
        }
    })
};
pull();
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值