前端入门之旅——ES6

274 阅读9分钟

一.定义变量

1,var
2,let

  • let和var的区别:
    1.let声明的变量不存在变量提升;
    2.let不可以重复声明变量;
    3.块作用域;{}代码块包含的区域; let声明的变量在块作用域,只在块作用域中有效
    for(let i=0;i<ali.length;i++){
        ali.onclick=() =>{console.log(i)//i=0,1,2
        }
    } 
    console.log(i);//会报错,因为let声明的变量只在块作用域内有效
    
    4.暂时性死区
    在块作用域内,let声明的变量必须在定义后调用,否则会报错;

3,const

  • const声明的变量不能二次赋值;必须在定义声明时直接赋值;
  • const定义引用类型的常量时,栈中存储的指针地址不可以修改,但堆中对应的内容可以改变(类比C++中的指针常量 int*const p)

二,解构赋值

1,数组

let a-1;
let b=2;   <=>let[a,b,c]=[1,2,3];
let c=3;

2, 对象

obj={
    name:'xx',
    age=2
}
let{name,age}=obj;
对象的解构,按照key赋值,想用某一变量代表某一属性时,可以写成{name:x}

3,字符串
把字符串中的每一项提取出来,按照顺序一一对应,分别赋值;

let a=1;
let b=2  
交换变量a,b的值  
方法一:[a,b]=[b,a];  
方法二:let tem=a;   
        a=b;
        b=tem;  
方法三:{a:b,b:a}={a:1,b:2}

三,当给方法传入默认值时,只有当实参==undefined时,方法的参数才会等于默认值

四,扩展运算符

用途

  • 作为数组的一部分;
  • 数组复制,可以实现深拷贝;
  • 数组合并,但不会改变原数组,类似.concat()
  • 合并对象(不同属性直接合并,相同属性后边会覆盖前面的对象属性)
  • 把类数组转化成数组 let ali=[...ali]

五,rest

function fun(){
    coonsole.log(arguments,callee)//当没有设置形参时,argument可以用来接收实参,是一个数组  
                                  //callee是这个函数本身
    }(1,2,3,4)

六,函数的扩展

1,fun.length 可以获取没有默认值以外的形参的个数;
2,fun.name 获取方法名fun;
3,箭头函数
形式:定义var fun=()=>{}
区别:箭头函数中的this 指针指向父作用域中的this,且箭头函数不可以使用arguments获取额外实参,可以用rest代替;

七,字符串扩展

1,拼接

let a='url='_start+'count='+_count  =>let a=`url=${_start}&count=${_count}; 

2, 方法
1,includes
判断字符串中是否含有某字符
str.includes('') 有,返回true,没有,返回false; 类似方法:str.indexof('')有,返回该字符的索引值,没有,返回-1;
2,startsswith、endwith
检索参数字符串或字符是否在字符串的头部/尾部;返回true/false
3,padstart/padend
padstart(num,'b')num传入数值,指定字符串的总长度;'b'是指传入的指定字符,利用字符从头部补全字符串到指定位置; padsend(num,'b')num传入数值,指定字符串的总长度;'b'是指传入的指定字符,利用字符从尾部补全字符串到指定位置; 4,repeat
str.repeat(num)数值代表重复几次字符串;

八,数值的扩展

1,将es5中window下面的方法转化成number下的方法

  • Number.isFinite()判断是否为数字;
  • Number.isNaN()只有当括号内内容为NaN时返回值为true,其他时为false;
  • Number.isInteger()判断是否为整数;
  • Number.ParseFloat()保留小数;
  • Number.Int()保留整数;

2,math下新增的方法

  • math.trunc()除去小数部分,返回整数;
  • Math.sign()判断一个数是正数(返回1),负数(返回-1),0(返回0),还是NaN;当传入字符串'67'会自动转化成67;

九,数组的扩展

1,Array from把类数组转化为数组(利用拓展运算符也可以)
2,Array of把值转化成数组

var a=new Array(3)长度为三的空数组;  
a=Array of(3)[3]

3,arr.copywithin替换数组中的内容;

    let arr = [1,2,3,4,5,6,7,8,9,10]
    console.log(arr.copyWithin(0,2,3))
    console.log(arr)
    // [3, 4, 5, 4, 5, 6, 7, 8, 9, 10]
    // [3, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    // 返回第一个符合判断条件的内容

4,arr.find(function(value,index,array){})
返回第一个满足条件的值

let arr1 = [1,2,5,2,7,8]
let a1 = arr1.find(function(val, index ,arr){
return val>3
})

5,arr.fill()
补全数组
arr.fill(a1,a2,a2)a1代表补全数组所利用的字符,a2表示从哪个位置开始补全数组,a3表示在哪个位置之前结束
6,arr.includes()
判断数组中是否包含某个数值,返回布尔值;
7,for of

let a=[1,2,4];
for(values of a){
    console.log(values)=>1,2,4
}
循环后取出每一项的值
把a变成a.keys(),循环后拿到索引值;
把a变成a.values(),循环后拿到每一项的值;
把a变成a.entries(),循环后拿到每一项对应索引及数值;是一个数组;

8,foreach()
遍历

p.forEach(function(value, key){
console.log(value)
console.log(key)
})  
遍历后取出的是每一项对应的值和索引;

9,filter
过滤
返回所有符合条件的值,是一个数组;和find()功能类似;

十,对象的扩展

1,属性和方法的简写
当属性等于某一变量时,且属性名和变量名刚好相等时,可以省区变量名;
定义对象时可以省略function;

let name='zs';
let age=1;
let obj={
    name:name,
    age:age,
    eat:function(){}
}
可以简写为  
let obj{
    name,
    age,
    eat(){}
}

2,属性名的表达式
例:obj[age+'name']=aaa;
3,obj.is(a,b)
判断a,b是否严格相等,多数情况下等价于===;

特例:
    console.log(NaN===NaN)//false  
                (object.is(NaN,NaN)//true;  
    console.log(+0===-0)//true  
                (object.is(+0,-0)//flase;

4,object.assign(obj1,obj2)
合并对象 不同属性值合并,相同属性值后面覆盖前面
等价于object=(...obj1,...obj2)
返回后的obj1是合并后的数组 若不想改变原数组的值,可以写成object.assign({},obj1,obj2)
5,obj.keys()/values()/entries()
同数组意义相同;keys拿到的是对象的属性;values拿到的是对象的值;entries拿到的是属性和值
6,for of

let a={
    name:'xx',
    age:12
}  
for(values of a){
    console.log(values)
}
循环后取出每一项的值
把a变成a.keys(),循环后拿到索引值;
把a变成a.values(),循环后拿到每一项的值;
把a变成a.entries(),循环后拿到每一项对应索引及数值;是一个数组;

7,a in obj
判断该对象下是否有某个属性;当a为数字时,则是判断某数组对应索引下是否有某个数值

十一,symbol

基本数据类型,表示独一无二的值;

  • var a=symbol();
    obj[a]='';

  • var[symbol()]=''
    注:当数据类型为symbol时,不管是否属性名与已有属性名相同,都不会被覆盖

十二,set

可以实现数组的去重,返回的是一个类数组,默认的属性是size,相当于数组的length;

数组去重的两种方法
* var a1=[1,2,2,3,3];    
var a2=new set(a1);  

* for(var i=0;i<a1.length;i++){
    if(!a2.includes(a1[i])){
        a2.push(a1[i]);
    }
}

var b=new set(a1); set定义数组具有的方法:
b.add();追加
b.delect();删除返回布尔值
b.has(); 返回布尔值

十三,map

创建的是一个类对象

let p1=new map();  
p1.set('name',value)设置一个属性;  
p1.get(key)获取一个属性对应的值;  
p1.has(key)判断是否含有某属性,返回布尔值;  
p1.delect(key)删除某个属性

将类对象转化为对象

1,let p2={};  
   p1.forEach(function(value,key){  
        p2[key]=value;  
2,for(item of p1){p1[item(0)]=item[1];  

十四,AJAX

可以实现不刷新页面而请求数据
1,原生方法

过程:
     1.创建XMLHttpRequest对象
    var xmlhttp;
    if (window.XMLHttpRequest){// code for IE7+, Firefox, Chrome, Opera, Safari
      xmlhttp = new XMLHttpRequest();
    } else {// code for IE6, IE5
      xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
    }

    2.请求
    xmlhttp.open("GET"/"POST","getData.json",true/flase);//true表示异步请求,false表示同步请求
    xmlhttp.send();

    3.响应
    xmlhttp.onreadystatechange = function(){
      if (xmlhttp.readyState == 4 && xmlhttp.status == 200){
        console.log(xmlhttp.responseText); // string
        console.log(JSON.parse(xmlhttp.responseText))
      }
    }
    xmlhttp.readyState返回值:
      0: 请求未初始化
      1: 服务器连接已建立
      2: 请求已接收
      3: 请求处理中
      4: 请求已完成,且响应已就绪
    xmlhttp.status返回值  
    200: ok
    304: Not Modified  客户端有缓存的文档并发出了一个条件性的请求(一般是提供If-Modified-Since头表示客户只想比指定日期更新的文档)。服务器告诉客户,原来缓冲的文档还可以继续使用。
    400: Bad Request 请求出现语法错误
    404: 找不到资源
    500: 服务器错误
    505: HTTP Version Not Supported 服务器不支持请求中所指明的HTTP版本

2,利用Jquery实现AJAX

$.ajax({
      url: 'getData.json',
      data: {
        start: 0,
        count: 10,
        _: Math.random()//防止因请求数据相同只调用一次的现象
      },
      method: "GET",
      success: function(res){
        console.log(res)

        $.ajax({
          url: 'getData.json',
          data: {
            start: 0,
            count: 10,
            _: Math.random()
          },
          method: "GET",
          success: function(res){
            $.ajax({
              url: 'getData.json',
              data: {
               start: 0,
               count: 10,
               _: Math.random()
              },
              method: "GET",
              success: function(){
                 }
            })
          }
        })
      }
    });  

3,AJAX回调地狱——利用setTimeout模拟发送请求

setTimeout(function(){
      console.log('1-success')
      setTimeout(function(){
        console.log('2-success')
        },2000)
    },1000)  

十五,promise ?

1,异步请求的实现方式

// p 是一个 Object
    let p = new Promise((resolve, reject) => {
      if(true){
        reslove() //成功的回调
      } else {
        reject() // 失败的回调
      }
    }).then( (res) => {
      // success
    }).catch( err => {
      // fail
    })  
    
    let p1 = new Promise(function(reslove, reject){
      setTimeout(function(){
        console.log('1-success')
        // reslove()
        reject()
      })
    }).then(function(){
      console.log('1-success-doing')
      return new Promise(function(reslove, reject){
        setTimeout(function(){
          console.log('2-success')
          reslove()
        },2000)
      })
    }, function(){
      console.log('1-fail')
    }).then(function(){
      console.log('2-success-doing')
    })
    
    db.collection('todos').doc('todo-identifiant-aleatoire').get({
      success: function(res) {
        // res.data 包含该记录的数据
        console.log(res.data)
      },
      fail: function(){
      }
    })
    db.collection('todos').doc('todo-identifiant-aleatoire').get().then(res => {
      // res.data 包含该记录的数据
      console.log(res.data)
    }).catch(()=>{
    })

2,promise 生成的对象的方法
promise.all();判断所有的请求是否成功;
promise.race();判断最快的请求是否成功;

例:let p1 = new Promise(function(reslove, reject){
      setTimeout(function(){
        console.log('1-success')
        reslove();
        // reject()
      }, 400)
    })
    
    let p2 = new Promise(function(reslove, reject){
      setTimeout(function(){
        console.log('2-success')
        // reslove();
        reject()
      }, 100)
    })

    let p3 = new Promise(function(reslove, reject){
      setTimeout(function(){
        console.log('3-success')
        reslove();
      }, 600)
    })

    // Promise.all
    // Promise.all([p1, p2, p3]).then(function(){
    //   console.log('all-success')
    // }).catch(function(){
    //   console.log('fail')
    // })

    // Promise.race
    Promise.race([p1,p2,p3]).then(function(){
      console.log('race-success')
    }).catch(function(){
      console.log('race-fail')
    })
    

十六,类的继承

方法一:
定义:function person(name,age){
    name=name;
    age=age;
    function eat(){
        conosole.log(eat...);
    }
    }
    person.prototype.fun=function(){}  
    继承:function student(){
        person.call(this,_name,_age){
            this.name=_name;
            this.age=_age;
        }//只能够继承类内的属性和方法;
    student.prototype=new person();
    student.prototype.constructor=student;
    }
    //继承所有的属性和方法;
方法二:
定义:    class person{
        constructor(_name,_age){
            this.name=_name;
            this.age=_age
        }
        eat(){console.log(aaa);}
    }
    person.prototype.fun=function(){console.log(bbb)};
    class student extends person{
        constructor(_name,_age){
            super(_name,_age)
        }
        fun(){
            super.fun()
        }
        eat(){
            super.eat()
        }
    }
    var p=new student('aaa',2);
    console.log(p)

十七,Generato 异步编程

    function * fun(){
      console.log('start');
      let tmp = yield request();  // yield 语句执行完后停止
      console.log('tmp:', tmp);
      let tmp1 = yield request2(tmp); 
      console.log('tmp1:', tmp1)
      // console.log('end');
    } 

    // next()方法可以传参,是上一个yield表达式的返回值
    let _fun = fun(); // 指针对象
    console.log(_fun.next('llll')); // 调用 {value: yeild的返回值, done: false}???打印出了obj???
    // console.log(_fun.next('asdfghjk'));
    // _fun.next()

    function request(){
      let obj = {
        name: 'xm',
        age: 2
      }
      setTimeout(() => {
        console.log('1-requset-success')
        _fun.next()
      },1000)
      return obj
    }

    function request2(tmp){
      console.log('2-start')
      console.log(tmp)
      let obj2 = {
        name: 'jjjjjj',
        age: 1
      }
      setTimeout(() => {
        console.log('2-requset-success')
      },2000)
      return obj2
    }
    打印结果
        start
        Object//_fun.next('llll')?
        1-requset-success
        tmp: undefined2-start
        undefined2-requset-success

十八,Async 异步编程

async function fun(){
      console.log('start..')
      let data = await request();
      console.log(data)
      let aaa = await req1(data);
      console.log(aaa)
      console.log('end....')
    }
    function request(){
      return new Promise(function(resolve, reject){
        setTimeout(()=>{
          console.log('1-success')
          let obj = {
            name: 'xm',
            age: 2
          }
          resolve(obj);
        },1000)
      })
    }
    function req1(_tmp){
      console.log(_tmp)
      return new Promise(function(resolve, reject){
        setTimeout(()=>{
          console.log('2-success')
          resolve('success~~~~~');
        },1000)
      })
    }
    fun().then(res => {
      console.log(234567890)
    });  
    start...
    1-success
    Object
    Object
    2-success
    success~~~~~
    end....
    234567890

十九,proxy 拦截

let obj = {
      name: 'xm',
      age: 2
    }
    // 拦截对象
    let pro = new Proxy(obj,{
      set: (target, key, property) => {
        // target 目标对象
        // key 表示的是修改的key
        // property 想要修改的值
        // console.log(target, key, property)
        // console.log('set function')
        target[key] = property;

        target[key] = '23456789'
      },
      get: (target, key, property) => {
        console.log(target, key, property)
        return target[key];
        // console.log('get function')
      }
    })
    // pro.name = 'jiujiu'
    // console.log(pro)
    // console.log(pro.name)
   
    let fn = function(data){
      return data
    }
    let handler =  {
      apply(target, ctx, arg){
        let data = {
          name: 'xxx',
          age: '111zz'
        }
        // console.log(target, ctx, arg)
        console.log(1234567)
        console.log(target, ctx, arg)
        return data
      }
    }

    let pp = new Proxy(fn,handler)
    console.log(pp('data'));
    // console.log(pp());

    function request (){
      let data;
      $.ajax({
        success(res){
          data = res
          console.log(res)
        }
      })
      return data
    }  
    打印结果:
       1234567
        ƒ (data){
          return data
        } undefined Array(1)
                    0: "data"length: 1__proto__: Array(0)
        Object

二十,事件

1.事件绑定  
 
* oDIv.onclick=function(){
}
* oDiv.addEventListener("clicl",{
})
**注:addEventListener可以绑定多个相同事件,且所有事件都可以执行**  
事件源,事件处理函数  
oDiv.onclick=function(){}//事件:onclick,事件处理函数:function;事件源:触发事件的函数(常用于冒泡时与this进行区别)this是指oDiv  
事件冒泡和事件捕获  
事件冒泡:从内到外,事件捕获:从外向内
oDiv.addEventListener('事件',方法,布尔值(true:事件捕获,false:事件冒泡)  
事件委托  
有动态生成的元素,需要绑定事件时,给已经存在的父元素上(利用事件冒泡)  
定时器:  
setinterval每隔一段时间执行()参数
settimeout等待一段时间后执行 属于异步执行,等任务队列执行完毕后再执行
引入了主线程和单线程;

2,变量提升 只用用var关键字定义一个变量时,才会出现变量提升;

fun();
var fun=function(){
}//会出现变量提升,报错  
fun();
function fun()={
}可以正常执行

3.闭包
闭包产生条件:
1,外部函数里有内部函数 2,内部函数会使用外部函数定义的局部变量
缺点:会造成内存泄露
4,关于建立索引的问题

for(var i=0,i<4,i++){
    ali[i].onclick=function(){
        console.log(i)
    }
}
返回结果i=4;
for(var i=0,i<4,i++){
    (function(index){ali[i].onclick=function(){
        console.log(i)
    }
    })(i)
}
利用闭包解决了索引问题

switch的两种用法
1.switch(变量)
case(具体的数值)
2.switch(true)
case:表达式
类/构造方法

function Person(_name){ this.name=_name//this指的是实例化对象 } var p1=new Person();this 指的是P的实例化对象p1;

this指针

对象下的this->当前对象  
构造函数/类的this->实例化对象  
函数/定时器的this->window  
dom对象绑定的事件中 this->dom对象  
this指针的绑定    

用法  在方法后}.apply/bind/call()  
call()多个参数 第一个是需要改变的指针  
apply() 两个参数  第一个是需要改变的指针
bind()多个参数 第一个是需要改变的指针  后面是所需要的参数  

21,es6的模块化

ES6的模块化分为导出(export)与导入(import)两个模块。
es6模块化是编译时模块化 export
可以输出单个变量,也可以将多个变量包装成模块输出
如果不想直接暴露变量名称,可以使用as来给变量重命名,然后用不同的名称引用

export{
	A as name
}

可以输出函数或类,不直接导出变量或函数定义语句时,需要用{}将导出值包裹;

var m=1
expirt m ;错  
var m=1;
export {m};或export var m=1;对

function f()
export f;错;
export {f}或export function f();

export命令可以出现在模块的任何位置,只要处于模块顶层就可以。如果处于块级作用域内,就会报错
import
命令接受一对大括号,里面指定要从其他模块导入的变量名。大括号里面的变量名,必须与被导入模块(profile.js)对外接口的名称相同。
如果想为输入的变量重新取一个名字,import命令要使用as关键字,将输入的变量重命名。

import { lastName as surname } from './profile.js';

import引入是只读的,不允许在加载模块里改写接口,但如果进入变量是对象,那么可以改写对象下的属性;
import命令具有提升效果,会提升到整个模块的头部,首先执行
export default
默认输出用export default;一个模块只有一个默认输出
默认输出的匿名函数,引入时可以用任意名称来命名;且对应的名称不需要使用大括号;
export default后面不能写变量的声明;

// 正确
export var a = 1;
// 正确
var a = 1;
export default a;
// 错误
export default var a = 1;

export和import的复合写法

export { foo, bar } from 'my_module';

// 可以简单理解为
import { foo, bar } from 'my_module';
export { foo, bar };   
只是相当于对外转发了这两个接口,导致当前模块不能直接使用foo和bar。  

es2020中允许import动态加载
import(specifier)

import函数的参数specifier,指定所要加载的模块的位置。import命令能够接受什么参数,import()函数就能接受什么参数,两者区别主要是后者为动态加载。

适用场合
下面是import()的一些适用场合。

(1)按需加载。
import()可以在需要的时候,再加载某个模块。
button.addEventListener('click', event => {
  import('./dialogBox.js')
  .then(dialogBox => {
    dialogBox.open();
  })
  .catch(error => {
    /* Error handling */
  })
});
上面代码中,import()方法放在click事件的监听函数之中,只有用户点击了按钮,才会加载这个模块。

(2)条件加载
import()可以放在if代码块,根据不同的情况,加载不同的模块。
if (condition) {
  import('moduleA').then(...);
} else {
  import('moduleB').then(...);
}
上面代码中,如果满足条件,就加载模块 A,否则加载模块 B。

(3)动态的模块路径
import()允许模块路径动态生成。
import(f())
.then(...);
上面代码中,根据函数f的返回结果,加载不同的模块。