ECMAScript6

ES6

  • ECMAScript和JavaScript的关系是,前者是后者的规格,后者是前者的一种实现

  • 在webstrom中使用时需要配置

在这里插入图片描述

  • 流程图

在这里插入图片描述

babel是什么

是一个工具链,主要用于在旧的浏览器或环境中奖ECMAScript2015+代码转换为向后兼容版本的JavaScript代码

  • 转换语法
  • Polyfill实现目标环境中缺少的功能
  • 源代码转换
安装babel
  • 先安装cnpm

    • npm install -g cnpm --registry=https://registry.npm.taobao.org
  • 再安装babel

    • npm install babel-cli -g-dev
    • npm install babel-preset-es2015 -g-dev
  • 配置一个package.json文件

    {
        "presets":[
            "latest"
        ],
        "plugins":[],
        "devDependencies": {
         "babel-cli": "^6.26.0",
         "babel-preset-es2015": "^6.24.1" 
        },
        "scripts":{
            "build":"babel src -d lib"
        }
    }
    
  • 运行命令npm run build 完成转换

块级作用域

/*
    在ES6提供了块级作用域
    * 使用let关键字定义块级作用域的变量
*/
if(true){
    //块级作用域 - 定义的变量只能在当前块级作用域中被访问
    let v = 100;
    console.log(v);
}
//在全局作用域中访问变量v
console.log(v);//v is not defined

在这里插入图片描述

let与var的区别
/*
    let与var关键字的区别 - 都是定义变量
    * let - 提供了块级作用域
        * 也可以在全局作用域和函数作用域定义变量
    * var - 提供了全局作用域和函数作用域
*/
//全局变量 - 在全局作用域中定义
var m = 100
let n = 1000

console.log(m);
console.log(n);

BnrFbV.png

let不允许声明提前
//使用var关键字定义变量 - 存在声明提前的现象
console.log(m);
var m = 10
//等价于
//只声明变量,并不初始化 - 默认值为undefined
var m
console.log(m);
m = 10

在这里插入图片描述

//使用let关键字定义变量时 - 不存在声明提前
console.log(v);
let v = 10

在这里插入图片描述

暂时性死区

ECMAScript6标准明确规定,如果在一个代码块中使用let或const声明变量或常量时,当前代码块中对这些声明的变量或常量形成了一个封闭的区域

在这个代码块中,在使用let或const声明之前,该变量或常量都是不可用的,称为“暂时性死区”

let不允许重复声明
//使用let关键字不允许重复声明
let v = 100;
console.log(v);
let v = 1000;
console.log(v);

在这里插入图片描述

let允许重新赋值
//使用let关键字允许重新赋值
let v = 100;
console.log(v);
v = 1000;
console.log(v);

Bn4png.png

与函数的关系
//使用var允许声明提前
var v = 100
function fn(){
    console.log(v);
    var v = 10
    console.log(v);
}
fn()

BuV13R.png

//使用let关键字声明变量将当前环境封闭
let v = 100
function fn(){
    //函数作用域封闭 - 全局作用域中的变量与当前函数作用域物无关
    console.log(v);
    let v = 10
    console.log(v);
}
fn()

在这里插入图片描述

与函数参数的关系
//使用var关键字声明局部变量与形参的关系
function fn(a){
    console.log(v);//undefined
    var v = 10
}
fn(100)
function fn(a){
    console.log(v);
    let v = 20//Cannot access 'v' before initialization
}
fn(10)
块级作用域
  • 块级作用域只能使用let关键字
  • let关键字不仅可以声明块级作用域,还可以用在全局作用域和函数作用域
//全局作用域
let a = 100 //全局变量
(function(){
    //函数作用域
    let b = 1000//局部变量 b is not defined
})()
if(true){
    //块级作用域
    let c = 10 //局部变量
}
console.log(a);
console.log(b);
为什么需要块级作用域
  • 局部变量可能覆盖全局变量
  • 在循环体中用于计数的变量泄漏为全局变量
//全局作用域
for(var i = 0;i<10;i++){
    console.log(i);
}
console.log(i);//10
//块级作用域
for(let i = 0;i<10;i++){
    console.log(i);
}
//全局作用域
console.log(i);//i is not defined
面试题(经典)
var arr = []
for(var i = 0;i<10;i++){
    arr[i] = function(){
        return i
    }
}
//值都是10
console.log(arr[0]());

在这里插入图片描述

函数的声明
/*
if(true){
    //块级作用域
    let fn = function(){
        console.log("111");
    }
}
//全局作用域
fn() //fn is not defined
*/

if(true){
    //全局作用域
    function fn(){
        console.log("111");
    }
}
//全局作用域
fn() //111

变量的解耦赋值

解耦赋值是什么
  • ECMAScript允许按照一定模式从数组或对象中提取值,对变量进行赋值

  • 变量的解耦赋值 - 从指定的数组或对象中提取值,为指定变量进行赋值

    • 语法结构
      • var/let[变量名称1,变量名称2,…] = 数组或对象
      • 注意 - 变量的索引值对应值的索引值
    let [a,b,c] = [1,2,3]
    console.log(a,b,c);//1 2 3
    
解耦赋值失败
  • 变量的的索引值应该对应值的索引值

    //解耦赋值失败
    let [a] = []
    console.log(a);//Identifier 'a' has already been declared
    
  • 避免解耦赋值失败 - 定义变量的数量与值的数量保持一致

不完全解耦赋值
  • 不完全解耦赋值 - 定义变量的数量小于值的数量

    let [a,b] = [1,2,3]
    console.log(a,b);//1 2
    
默认值
  • 解耦赋值失败时,变量的默认值为undefined

  • 默认值 - 指的就是在解耦赋值失败时,重写undefined默认值

    let [a = true] = [100]
    console.log(a);//100
    
    let [x,y = 100] = [10]
    console.log(x,y);// 10 100
    
  • ES6底层将为变量赋值的值与undefined进行比较(全等于),指定的默认值生效

    let [m,n = 100] = [10,undefined]
    console.log(m,n); //10 100
    
  • ES6底层将为变量赋值的值只是与undefined进行比较(null等没有意义的)

    let [m,n = 100] = [10,null]
    console.log(m,n); //10 null
    
对象的解耦赋值
  • 对象的解耦赋值 - 从对象中提取值,为变量进行赋值

    • 变量名称与对象的属性名称一一对应

      • 如果不对应,导致解耦赋值失败
      let {x,y} = {
          x:10,
          y:20
      }
      console.log(x,y);//10 20
      
    • 解耦赋值 - 赋值运算符的量变格式保持一致

      let [m,n] = {
          x:10,
          y:20
      }
      console.log(m,n);//{(intermediate value)(intermediate value)} is not iterable
      
  • 注意:

    • 数组的解耦赋值 - 变量的索引值与值的索引值保持一致

    • 对象的解耦赋值 - 变量的名称与对象属性的名称保持一致

      let [[a,b],c] = [[1,2],3]
      console.log(a,b,c);//1 2 3
      
      let {m:{name,age},n} = {
          m:{
              name:'12',
              age:19
          }
      }
      console.log(name,age); //12 19
      
字符串的解耦赋值
  • 变量的数量与字符串中字符的数量进行对应

    /*
    let [a,b,c] = 'xyz'
    console.log(a,b,c);//x y z
    */
    
    /*
    let [a,b,c] = 'xxyyzz'
    console.log(a,b,c);//x x y
    */
    
    let [a,b,c] = '大前端'
    console.log(a,b,c); //大 前 端
    
数值与布尔值的解耦赋值
  • 数字值的解耦赋值 - 作为值的是一个数字值

    • 结果 - 报错:数字值是不能被迭代遍历的

    • 解耦赋值 - 作为值的类型必须是可迭代遍历的

      /*
      let [a] = 100
      console.log(a); //100 is not iterable
      */
      
      /*
      let num = new Number(100)
      console.log(typeof num.toString()); //string
      */
      
      let {toString:m} = 100
      //console.log(m);//[Function: toString]
      console.log(m()); //Number.prototype.toString requires that 'this' be a Number
      

在这里插入图片描述

函数参数的解耦赋值
  • 函数定义 - 形参,相当于在函数作用域中定义了一个局部变量(没有赋值)

  • 函数调用 - 实参,相当于在函数作用域中为定义的变量进行赋值

    function fn(a,b){
        console.log(a,b);
    }
    fn(10,20)//10 20
    
    function f([a,b]){
        console.log(a,b);
    }
    f([1,2]) //1 2
    
    function f({n,m}){
        console.log(m,n);
    }
    f({
        m:10,
        n:10
    })//10 10
    
小括号问题
  • 对于解析器来讲,语句中到底是模式还是表达式,没有办法从开始就知道,必须解析到赋值运算符时才能知晓
  • ECMAScript6的规则是只要有可能导致解耦赋值的歧义,就不得使用小括号
  • 建议只要有可能就不要再模式中使用小括号
  • 不能使用小括号的内容
    • 变量声明语句
    • 函数参数:函数参数也属于变量声明,因此不能带有小括号
    • 赋值语句的模式
解耦赋值的用途
  • 交换变量的值

    let x = 1,y = 2;
    [x,y] = [y,x]
    console.log(x,y);//2 1
    
  • 从函数返回多个值

    let [a,b,c] = fn()
    console.log(a,b,c);//1 2 3
    
  • 函数参数的定义

    function f([a,b,c=2]){
        console.log(a,b,c);
    }
    f([2,3])//2 3 2
    
  • 提取JSON数据

字符串的扩展

字符串判断是否包含
  • ES5提供判断是否包含的方法

  • string.indexOf(searchStr)方法

    • 作用 - 返回指定字符串中包含指定子字符串的索引值

    • 结果

      • 包含 - 返回第一个匹配的索引值
      • 不包含 - 返回-1
      let str = 'solongxueyuan'
      console.log(str.indexOf('o'));//1
      console.log(str.lastIndexOf('o'));//3
      
  • ES6提供的判断是否包含的方法

    • includes()方法是区分大小写的

      console.log(str.includes('o'));//true
      console.log(str.includes('o',3));//true
      console.log(str.includes('o',5));//false
      console.log(str.includes('O'));//false
      
    • 基于includes()方法实现一个不区分大小写的判断

      function fun(str,searchStr,index){
          //toLowerCase()将字符串全部转化为小写格式
          str = str.toLowerCase()
          if(typeof index === 'number'){
              return str.includes(searchStr,index)
          }else{
              return str.includes(searchStr)
          }
      }
      console.log(fun(str,'o'));//true
      
    • startsWith()也区分大小写

      • startsWith()方法不是表示指定字符串是以另一个字符串开始的

        • 表示指定字符串的指定索引值开始是否以另一个字符串开始的

          console.log(str.startsWith('long',2));//true
          
重复字符串
  • repeat()方法用于将原字符串重复n次,返回一个新字符串

    • number - 表示将原字符串重复的次数

      • 如果number参数小数的话,则会向下取整
      • 如果number参数为负数或者无穷大的话,则会报错
      • 如果number参数为NaN的话,则为0
      • 如果number参数为字符串,则会先转换为数字值
      //重复字符串
      let str = 'abc'
      console.log(str.repeat(3));//abcabcabc
      //仅仅返回一个新的字符串(不会改变原有字符串的内容)
      let result = str.repeat(3)
      console.log(str,result);//abc abcabcabc
      //Number为小数,向下取整的
      console.log(str.repeat(2.5));//abcabc
      //number为NaN,不报错
      console.log(str.repeat(NaN));//没有任何输出
      //number为负数,报错
      //console.log(str.repeat(-2));//Invalid count value
      //number为零
      console.log(str.repeat(0));//没有任何输出
      //number为字符串或布尔值,先转换成数字值
      console.log(str.repeat('3'));//abcabcabc
      console.log(str.repeat(true));//abc
      
模板字符串
  • 替代原有的普通字符串

    //定义一个普通的字符串
    let str1 = 'this is 111'
    //定义一个模板字符串 - 充当普通字符串来使用
    let str2 = `this is 111`
    console.log(str1,str2);//this is 111 this is 111
    
  • 多行字符串

    
    //定义一个普通的字符串
    let str3 = 'this is\n111'
    console.log(str3);//this is
                        //111
    let str4 = 'this is'
                +'111'
    console.log(str4);//this is111
    
    //定义一个模板字符串 - 充当普通字符串来使用
    let str5 = `this is
                111`
    console.log(str5);/*this is
                        111*/
    
  • 字符串与变量配合使用

    let name = '111'
    //定义一个普通的字符串
    let str6 = 'hello' + name + '!'
    console.log(str6);//hello111!
    //定义一个模板字符串 
    let str7 = `hello ${name} !`
    console.log(str7);//hello 111 !
    
带标签的模板字符串
  • 带标签的模板字符串

    • 不是模板字符串的用法,而是函数调用的一种特殊形式
    • 整体结构
      • 函数名称
      • 将模板字符串作为函数的参数
    let str = '111'
    //普通字符串
    console.log('this is'+ str + '.');//this is111.
    //模板字符串
    console.log(`this is ${str}`);//this is 111
    //带标签的模板字符串
    console.log`this is ${str}`;//[ 'this is ', '' ] 111
    
    function fn(a){
        console.log(a instanceof Array);//true
    }
    //fn('this is' + str + '.')
    //fn(`this is ${str}`)
    fn`this is ${str}`//[ 'this is ', '' ]
    
原始字符串
  • 应用在带标签的模板字符串

  • 在函数的第一个参数中,存在着raw属性 - 获取到模板字符串的原始字符串

    • 所谓的原始字符串
      • 模板字符串被定义时的内容,而不是处理之后的内容
    let str = 'funtion'
    function fn(a){
        console.log(a.raw);//[ 'this is ', '.' ]
        console.log(a.raw[0]);//this is 
    }
    fn`this is ${str}.`
    

数组的扩展

扩展运算符的应用
  • 替代apply()方法

    //定义一个数组
    var arr = [1,2,3,4]
    console.log(...arr);//1 2 3 4
    //定义一个函数
    function f(a,b){
        console.log(a+b);
    }
    var arg = [1,2]
    f(...arg)//3
    /*
        call()与apply()方法的区别
        * call(this,arg1,arg2,...)
            * 接收的参数为多个参数
        * apply(this,arr)
            * 接收参数为一个数组
    */
    f.call(null,arg[0],arg[1])//3
    f.apply(null,arg)//3
    
  • 复制数组

    • 利用扩展符复制数组为深复制

      /*
          数组的深复制和浅复制
          * 深复制 - 复制数组的元素内容(数据)
          * 浅复制 - 复制数组的内存地址
      */
      var arr1 = [1,2,3,4,5]
      /*
      //浅复制
      var arr2 = arr1
      arr2[2] = 7
      console.log(arr1,arr2);//[ 1, 2, 7, 4, 5 ] [ 1, 2, 7, 4, 5 ]
      */
      
      /*
      //深复制
      var arr2 = []
      for(var i=0;i<arr1.length;i++){
          arr2[i] = arr1[i]
      }
      console.log(arr1,arr2);//[ 1, 2, 3, 4, 5 ] [ 1, 2, 3, 4, 5 ]
      arr2[2] = 7
      console.log(arr1,arr2);//[ 1, 2, 3, 4, 5 ] [ 1, 2, 7, 4, 5 ]
      */
      
      //利用扩展运算符
      //var arr2 = [...arr1]
      var [...arr2] = arr1
      console.log(arr1,arr2);//[ 1, 2, 3, 4, 5 ] [ 1, 2, 3, 4, 5 ]
      arr2[2] = 7
      console.log(arr1,arr2)//[ 1, 2, 3, 4, 5 ] [ 1, 2, 7, 4, 5 ]
      
    • 合并数组

      var arr1 = [1,2,3]
      var arr2 = [4,5,6]
      //ES5合并数组的方法
      console.log(arr1.concat(arr2));//[ 1, 2, 3, 4, 5, 6 ]
      //利用扩展运算符
      console.log([...arr1,...arr2]);//[ 1, 2, 3, 4, 5, 6 ]
      
    • 与解耦赋值配合使用

      var arr = [1,2,3,4,5]
      /*
      //ES5
      var v = arr[0]
      var list = arr.splice('')
      console.log(v,list);//1 [ 1, 2, 3, 4, 5 ]
      */
      
      //利用扩展运算符
      //var [v,...list] = arr
      //console.log(v,list);//1 [ 2, 3, 4, 5 ]
      var [...list,v] = arr
      console.log(v,list)//Rest element must be last element
      
    • 将字符串转换为数组

      var str = 'hello'
      //ES5
      console.log(str.split(''));//[ 'h', 'e', 'l', 'l', 'o' ]
      //ES6
      console.log([...str]);//[ 'h', 'e', 'l', 'l', 'o' ]
      
    • 与对象的使用

      //注意 - 扩展运算符必须与可迭代(遍历)的对象配合使用
      /*
      var obj = {
          name:'222',
          age:23,
          job:'333'
      }
      //console.log(...obj);//Found non-callable @@iterator
      console.log([...obj]);//obj is not iterable
      */
      
      //注意 - 关联数组。不会报错,但没有结果
      var arr = []
      arr['name'] = '222'
      arr['age'] = 23
      console.log(...arr);
      
Array提供的方法
  • Array.from()方法 - 从一个类似数组或可迭代对象中创建一个新的数组实例

    //构建一个类数组的对象 - 1.可迭代 2.有效的length
    var obj = {
        0:'111',
        1:'222',
        2:'333',
        length:3
    }
    //console.log(obj);//{ '0': '111', '1': '222', '2': '333', length: 3 }
    /*
    for(var i=0;i<obj.length;i++){
        console.log(obj[i]);
    }
    */
    //ES5
    console.log([].slice.call(obj));//[ '111', '222', '333' ]
    //ES6
    console.log(Array.from(obj));//[ '111', '222', '333' ]
    /* 
    //扩展运算符不能使用
    console,log([...obj])
    */
    console.log(...Array.from(obj));//111 222 333
    
    function fn(){
        //arguments对象 - 用于接收所有的实参
        console.log(...arguments);
    }
    fn(1,2,3)//1 2 3
    
  • Array.of()方法 - 用于创建一个具有可变数量参数的新数组实例,而不考虑参数的数量或类型

    • 主要目的是为了弥补构造函数Array()的不足,因为参数个数不同,导致行为差异
    //Array.of()如果传递一个参数时,表示一个元素内容
    console.log(Array.of(5));//[ 5 ]
    console.log(Array.of(1,2,3));//[ 1, 2, 3 ]
    
    console.log(new Array(1,2,3));//[ 1, 2, 3 ]
    //new Array()如果只传递一个参数时,表示length
    console.log(new Array(5));//[ <5 empty items> ]
    
    console.log(Array(1,2,3));//[ 1, 2, 3 ]
    //new Array()如果传递一个参数时,表示length
    console.log(new Array(5));
    
    console.log(Array.of());//[]
    console.log(new Array());//[]
    console.log(Array());//[]
    console.log([]);//[]
    
Array对象的方法
  • copyWithin()方法用于浅复制一部分到同一数组中的另一位置,并返回他,而修改其大小

    • 作用 - 检索指定数组中从start到end区间的元素,复制到当前数组中的指定索引值

    • 参数

      • target - 该参数的值最大等于当前数组的length属性值-1
      • start - 表示当前截取开始的索引值
        • 如果当前参数值省略,自动从数组的开始位置进行截取
      • end - 表示当前截取结束的索引值(不包括当前索引值的元素)
        • 如果当前参数值省略,自动截取到当前数组的最后
    • 注意

      • 该方法不能改变数组的长度
      • 修改了原有的数组
      let arr = [1,2,3,4,5]
      
      //console.log(arr.copyWithin(3,0,4)); //[ 1, 2, 3, 1, 2 ]
      //console.log(arr.copyWithin(0,3));//[ 4, 5, 3, 4, 5 ]
      console.log(...arr.copyWithin(2));//[ 1, 2, 1, 2, 3 ]
      console.log(arr);//[1,2,3,4,5]
      
  • find(callback)方法

    • 作用 - 返回find()方法的回调函数中符合表达式的第一个元素的值

    • callback参数 - 调用find()方法时的回调函数

    • funtion(element,index,array){}

      • element - 指定数组中每一项元素的值
      • index - 指定数组每一项元素的索引值
      • array - 指定数组的本身
    • 特点

      • 数组调用find()方法,将制定数组进行遍历
      let arr = [1,2,3,4,5]
      var result = arr.find(function(a,b,c){
          return b>1
      })
      console.log(result);//3 
      
    • findIndex()方法返回符合表达式结果的第一个元素的索引值

      var result = arr.findIndex(function(a,b,c){
          return b>1
      })
      console.log(result);//2
      
  • fill()方法

    • 作用 - 将制定内容替换指定数组中的指定位置

    • 参数

      • value - 表示替换的内容(没有类型要求)
      • start - 表示替换开始的位置
      • end - 表示结束的位置(不包含)
    • let arr = [1,2,3,4]
      var result = arr.fill([6,7],2,3)
      console.log(result);//[ 1, 2, [ 6, 7 ], 4 ]
      

函数的扩展

函数参数的默认值
  • 函数参数指定默认值

    • ES5中不允许为函数的形参设置其默认值

      • 当定义形参,而不传递实参时 - 形参的默认值为undefined

      • 人为的解决形参默认值的问题 (arg = arf || 0)

      • /*
        //ES5
        function fn(a){
            a = a ||  0
            console.log(a);
        }
        fn()//0
        */
        
        //ES6
        function fn(a=1){
            console.log(a);
        }
        //fn(0)//0
        fn()//1
        
  • 与解耦赋值的配合使用

  • 参数的作用域

    • 如果为函数的参数设置默认值的话,当函数声明进行初始化时,参数会形成一个独立的作用域,这个作用域会在函数初始化完毕时消失

    • let x = 1
      function fn(y = x ){
          let x = 2
          console.log(x);
      }
      fn()//2
      

在这里插入图片描述

rest参数
  • 用于获取函数多余的参数 - 定义的形参少于实参的个数

  • /* //ES5 - 利用arguments对象接收多余的参数
    function fn(a,b){
        console.log(a,b,arguments[2]);
    }
    fn(1,2,3)//1 2 3 */
    
    //ES6 - 利用rest参数接收多余的参数(数组类型)
    function f(a,b,...arry){
        console.log(a,b,arry);//1 2 [ 3, 4, 5 ]
        //console.log(a,b,...arry);//1 2 3 4 5
    }
    f(1,2,3,4,5)
    
箭头函数
  • 箭头函数是什么

    • 相比函数表达式具有较短的语法并以词法的方式绑定this,箭头函数总是匿名的

    • /* //ES5 定义函数的方式
      function fn(){}
      var fun = function(){}
      bar f = new Function() */
      //ES6 箭头函数
      var n = () => 5
      /* //等价于
      var n = function(){
          return 5
      }
       */
      console.log(n());//5
      
      /* function fn(a,b){
          var result = a + b
          return result
      } */
      //改为箭头函数
      var f = (a,b) => a + b
      console.log(f(1,2));//3
      
      /* function fn(x,y){
          var t = x+y
          console.log(t);
      } */
      //改为箭头函数
      var h = (x,y) => {
          var t = x+y
          console.log(t);
      }
      h(1,3)//4
      
    • //ES5 定义函数时,使用this -> 指向调用函数时的上下文
      function fn(){
          console.log(this);
      }
      //将fn作为函数进行调用
      fn()//当前执行环境中的全局对象
      
      //使用call()或apply()方法调用函数fn
      let obj = {}
      fn.call(obj)//{} 
      //函数作为对象obj2的方法
      let obj2 = {
          sayMe:fn
      }
      obj2.sayMe()//{ sayMe: [Function: fn] }
      
      //ES6 声明箭头函数,函数中的this -> 指向的是定义箭头函数时的上下文对象
      var n = () =>{
          console.log(this);
      }
      n()//{}
      
      var obj3 = {
          sayMe:n
      }
      obj3.sayMe()//{}
      
  • 箭头函数的语法结构有

    • 基本语法结构
    • 高级语法结构
  • 箭头函数的注意事项

    • 函数体内的this,就是定义时所在的对象,而不是使用时所在的对象

    • 不可以当做构造函数

    • 不可以使用arguments对象,该对象在函数体内不存在

    • /* //箭头函数不能当做构造函数使用
      var fn = () => {
          this.name = '222'
      }
      var f = new fn()
      console.log(f);//fn is not a constructor */
      
      let obj = {
          name:'222',
          sayMe:() => {
              console.log('1111');
          }
      }
      obj.sayMe()//1111
      
函数的尾调用
  • 就是指某个函数的最后一步是调用另一个函数

  • function g(x){
        return x+2
    }
    
    function fn(x){
        return g(x)
    }
    
    console.log(fn(2));//4
    

对象的扩展

对象的属性
  • 属性表示法

    • 允许直接将变量和函数名

    • var name = '111'
      function fn(){
          console.log('333');
      }
      
      /* //ES5定义对象的属性和方法的方式
      var obj = {
          name:name,
          fn:fn
      } */
      //ES6 允许变量名和函数名直接作为对象的属性和方法的方式
      var obj = {
          name,
          fn
      } 
      console.log(obj.name);//111
      
Object的方法
  • Object.is()方法

    • 相等运算符在比较值钱,会自动转换数据类型

    • 全等运算符导致NaN与自身不等,+0等于-0等问题

    • //ES5
      console.log(+0 === -0);//true
      console.log(NaN === NaN);//false
      
      //ES6
      console.log(Object.is(+0.-0));//false
      console.log(Object.is(NaN,NaN));//true
      
  • Object.assign()方法

    • 用于将所有可枚举属性的值从一个或多个源对象复制到目标对象

    • var obj = {
          name:'222',
          age:23
      }
      var arr = {}
      var result = Object.assign(arr,obj)
      console.log(result,arr);//{ name: '222', age: 23 } { name: '222', age: 23 }
      
      arr.name = '333'
      console.log(result.name);//333
      console.log(obj.name);//222
      
super关键字
  • 用于指向当前对象的原型对象

  • 注意 - super关键字表示原型时,只能用在对象的方法中,用在其他地方都会报错

  • /* function Hero(){
        this.name = '111'
        this.fn = function(){
            console.log(this.name);
        }
    }
    Hero.prototype.age = 18
    var hero = new Hero()
    hero.fn()//111
    
    hero.sayYou = function(){
        console.log(this.age);
    }
    hero.sayYou()//18 */
    
    var prop = {
        age:19,
    }
    
    var obj = {
        name:'222',
        fn(){
            console.log(super.age);
        }
    }
    
    //将prop对象作为obj对象的原型对象
    Object.setPrototypeOf(obj,prop)
    // console.log(obj.name);//222
    // console.log(obj.age);//19
    
    obj.fn()//19
    
对象的扩展运算符
  • 用于取出参数对象的所有可遍历属性,拷贝到当前对象中

  • var obj = {
        name:'222',
        age:23
    }
    //将原对象的可枚举的属性复制到目标对象中
    var arr = {...obj}
    
    // Object.assign(arr,obj)
    console.log(arr);//{ name: '222', age: 23 }
    

键值对集合

Set集合
  • Set集合是什么

    • 是值的集合,可以按照插入的顺序迭代它的元素,Set集合中的元素只会出现一次

    • /*
          ECMAScript 6提供了Set构造函数,创建Set对象
          * 集合 - 值(唯一的)的集合
          * 应用 - 利用Set集合为数组元素去重
      */
      const arr = [1,1,2,2,3,4,5]
      let set = new Set(arr)
      console.log(set);//Set { 1, 2, 3, 4, 5 }
      
      /*
          NaN、undefined等值允许被存储在Set集合中
          * NaN值在Set集合中被认为是相等的
      */
      console.log(undefined === undefined);//true
      let set2 = new Set([NaN,NaN,undefined,undefined,null,null])
      console.log(set2);//Set { NaN, undefined, null }
      
      /*
          Set集合中存储复杂数据类型(数组、对象及函数等)
          * 多个空数组和空对象表示多个值
      */
      console.log([] === []);//false
      let set3 = new Set([[],[],{},{},function(){},function(){}])
      console.log(set3);//Set { [], [], {}, {}, [Function], [Function] }
      
  • Set集合的属性与方法

    • Set对象提供了size属性用于返回Set对象的个数

    • console.log(set.size);//5
      
    • add(value) - 向Set集合的尾部添加新的元素

      • 返回值 - 添加新元素后的Set集合
    • var result = set.add(8)
      console.log(set,result);//Set { 1, 2, 3, 4, 5, 8 } Set { 1, 2, 3, 4, 5, 8 }
      
    • delete(value) - 从Set集合删除指定元素

      • value - 表示Set集合中的元素内容(值)
      • 返回值 - 布尔值 true表示删除成功,false表示删除失败
    • var result = set.delete(1)
      console.log(set,result);//Set { 2, 3, 4, 5, 8 } true
      
    • has(value) - 判断指定Set集合中是否包含指定元素

      • value - 表示Set集合中的元素内容(值)
      • 返回值 - 布尔值 true表示包含,false表示不包含
    • var result = set.has(1)
      console.log(result);//false
      
  • Set对象提供了用于遍历Set集合的方法

    • value()方法 - 返回一个迭代器对象(SetIterator)

      • 没有length属性值 - 常规的循环语句无法使用
      • 不能for…in循环语句
      • 只能使用for…of进行循环
    • let set = new Set([1,2,3,4])
      /* var arr = set.values()
      for(var name of arr){
          console.log(name);//1 2 3 4 
      } */
      
      /*
          虽然Set集合具有size属性 - 表示当前Set集合中元素的个数
          但是Set集合获取每一个元素内容,不能使用set[索引值]的方式
      */
      /* for(let i=0;i<set;i++){
          console.log(set[i]);
      } */
      
      console.log(set.values());[Set Iterator] { 1, 2, 3, 4 }
      
    • keys()方法 - 返回当前Set集合中所有键的迭代器对象

    • console.log(set.keys());//[Set Iterator] { 1, 2, 3, 4 }
      
    • entries()方法 - 返回当前Set集合中所有键值的迭代器对象

    • console.log(set.entries());//[Set Entries] { [ 1, 1 ], [ 2, 2 ], [ 3, 3 ], [ 4, 4 ] }
      
    • Set集合提供forEach()方法

      • 作用 - 用于遍历当前的Set集合(为Set集合中每个元素调用callback函数)
      • 回调函数
        • funtion(value,key,set){}
          • value - 表示当前Set集合中每一个值
          • key - 表示当前Set集合中每一个键
          • set - 表示当前遍历的Set集合
    • set.forEach(function(v,k,s){
          console.log(v,k,s);
      })
      /* 1 1 Set { 1, 2, 3, 4 }
      2 2 Set { 1, 2, 3, 4 }
      3 3 Set { 1, 2, 3, 4 }
      4 4 Set { 1, 2, 3, 4 } */
      
  • Set集合与Array对比

    • 数组中用于判断元素是否存在的indexOf()函数效率低下
    • Set对象允许根据值删除元素,而数组中必须使用基于下标的splice()方法
    • 数组的indexOf()方法无法找到NaN值
    • Set对象存储不重复的值,所以不需要手动处理包含重复值的情况
WeakSet集合
  • WeakSet是什么

    • 是一些对象值的集合,并且其中的每个对象值只能出现一次
    • WeakSet对象与Set对象的区别
      • WeakSet对象中只能存放对象引用,不能存放值,而Set对象都可以
      • WeakSet对象中存储的对象值都是被弱引用的,如果没有其它的变量或属性引用这个对象值,则这个对象值会被当成垃圾回收掉,WeakSet对象是无法被枚举的,没有办法拿到WeakSet集合包含的所有元素
  • WeakSet集合的方法

  • var ws = new WeakSet()
    var obj = {}
    var obj2 = {}
    ws.add(obj)
    ws.add(obj2)
    //WeakSet集合不可枚举,无法打印
    console.log(ws);//WeakSet { <items unknown> }
    
Map集合
  • Marp集合是什么

    • 是键值对的集合,任何值都可以作为Map集合的键或值,Map集合可以按照插入的顺序迭代它的元素

    • let map = new Map()
      let num  = 10,str = '222',obj = {},fn=function(){}
      map.set('num',num)
      map.set('fn',fn)
      map.set('obj',obj)
      map.set('str',str)
      
      console.log(map);
      /* Map {
          'num' => 10,
          'fn' => [Function: fn],
          'obj' => {},
          'str' => '222'
        } */
      
      console.log(map.get('str'));//222
      map.delete('num')
      console.log(map);//Map { 'fn' => [Function: fn], 'obj' => {}, 'str' => '222' }
      /* map.clear()
      console.log(map);//Map {} */
      var result = map.has('str')
      console.log(result);//true
      
  • Map集合的属性与方法

    • console.log(map.values());//[Map Iterator] { [Function: fn], {}, '222' }
      console.log(map.keys());//[Map Iterator] { 'fn', 'obj', 'str' }
      console.log(map.entries());/* [Map Entries] {
                                  [ 'fn', [Function: fn] ],
                                  [ 'obj', {} ],
                                  [ 'str', '222' ]
                                  } */
      map.forEach(function(v,k,s){
          console.log(v,k,s);
      })
      /* [Function: fn] fn Map { 'fn' => [Function: fn], 'obj' => {}, 'str' => '222' }
      {} obj Map { 'fn' => [Function: fn], 'obj' => {}, 'str' => '222' }
      222 str Map { 'fn' => [Function: fn], 'obj' => {}, 'str' => '222' } */
      
  • Map集合键的相等

    • 判断使用与 === 相似的规则
    • -0和+0相等
    • NaN与自身相等
  • Map集合与Object对比

    • Object的键均为String类型,在Map里键可以是任意类型的
    • 必须手动计算Object的尺寸,但是可以很容易地获取使用Map的尺寸
    • Object的遍历循环元素的插入顺序
    • Object有原型,所以映射中有些缺省的键
WeakMap集合
  • 同WeakSet集合

Promise对象

Promise对象是什么
  • Promise对象是什么

    • 该对象允许对延迟和异步操作流程进行控制,一个Promise对象就是一个代表一个异步操作最终完成或者失败的对象
    • 开发人员可以使用由其他函数创建并返回的Promise对象,Promise对象本质上就是一个绑定了回调的对象,而不是将回调传进函数内部
    • Promise的几种状态
      • pending:初始状态,既不成功,也不是失败状态
      • fulfilled:意味着操作成功完成
      • rejected:意味着操作失败
  • 创建Promise对象

    • Promise构造函数执行时立即调用executor函数,resolve和reject两个函数作为参数传递给executor(executor函数在Promise构造函数返回新建对象前被调用,executor表示带有resolve和reject两个参数的函数)

    • resolve和reject函数被调用时,分别将Promise的状态改为fulfilled(完成)或rejected(失败)

    • /*
          创建Promise对象
          let promise = new Promise(funtion(resolve,reject){})
          * 当前的构造函数Promise接收一个回调函数
              funtion(resolve,reject){}
              * resolve - 是一个函数,将Promise的状态改为fulfilled(完成)
              * reject - 是一个函数,将PromiseDe状态改为rejected(失败)
      */
      
      /* let promise = new Promise(function(res,rej){
          setTimeout(function(){
              res("测试成功")
              //rej("测试失败")
          },200)
      })
      
      promise.then(function(value){
          console.log(value);//测试成功
          /*(node:19392) UnhandledPromiseRejectionWarning: 测试失败
            (node:19392) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
            (node:19392) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code. */
      // }) 
      
      //Promise对象由其他函数创建并返回
      function fn(){
          return new Promise((res,rej) => {
              setTimeout(() => {
                  res('111')
              },200)
          })
      }
      var promise = fn()
      
  • Promise对象的约定

    • 在JavaScript事件队列的当前运行完成之前,回调函数永远不会被调用
    • 通过then实行添加的回调函数,甚至都在异步操作完成之后才被添加的函数,都会被调用
    • 通过多次调用then,可以添加多个回调函数,他们会按照插入顺序并且独立运行
  • Promise对象的链式操作

    • 连续执行两个或者多个异步操作

    • //创建Promise对象
      let promise = new Promise((res,rej) => {
          setTimeout(() => {
              res('成功了')
          },200)
      })
      //then()方法返回一个新的Promise对象
      let promise2 = promise.then((data) => {
          console.log(data);//成功了
      })
      //promise和promise2是两个不同的对象
      // console.log(promise === promise2);//false
      // console.log({}==={});//false
      
Promise对象原型的方法
  • then()方法

    • 第一个回调函数,当Promise变为接收状态(fulfillment)时,该参数作为回调函数被调用,该函数有一个参数,即接受的最终结果
    • 第二个回调函数,当Promise变成决绝状态(rejection)时,该参数作为回调函数被调用,该函数有一个参数,即拒绝的原因
  • catch()方法

    • 返回一个Promise对象,并且处理决绝的情况,同then()方法
    • 回调函数:当Promise呗rejected时,被调用该回调函数,该函数具有一个参数,即rejected的原因
  • finally()方法

    • 返回一个Promise对象,在执行then()和catch()后,都会执行finally指定的回调函数
  • //创建Promise对象
    let promise = new Promise((res,rej) => {
        setTimeout(() => {
            //res('成功了')
            rej('失败了')
        },200)
    })
    //成功时执行then()方法,失败时执行cathc()放法,不管成功还是失败都会执行finally()方法
    promise.then((data) => {
        console.log(data);//成功了
    }).catch((value) => {
        console.log(value);//失败了
    }).finally(() => {
        console.log('111');
    })
    
Promise对象的方法
  • Promise.all()方法

    • 是以所有Promise对象的状态都改变时,表示整合后的Promise对象成功或失败
  • Promise.race()方法

    • 是以某个Promise对象的状态改变时,表示整合后的Promise对象成功或失败
  • Promise.resolve()方法

  • Promise.reject()方法

  • let promise1 = new Promise((res,rej) => {
        setTimeout(() => {
            res('111')
        },100)
    })
    let promise2 = new Promise((res,rej) => {
        setTimeout(() => {
            res('222')
        },200)
    })
    let promise3 = new Promise((res,rej) => {
        setTimeout(() => {
            res('333')
        },300)
    })
    
    //Promise.all()方法将多个Promise对象整合成一个Promise对象
    let promise = Promise.all([promise1,promise2,promise3])
    //Promise.race()方法不管Promise成功还是失败都快执行最先完成的
    Promise.race([promise1,promise2,promise3]).then((data) => {
        console.log(data);//111
    })
    promise.then((data) => {
        console.log(data);//[ '111', '222', '333' ]
    })
    
Promise对象的应用
  • 加载图片

    • const fun = function(path){
          return new Promise((res,rej) => {
              const image = new Image()
              //图片加载成功
              image.onload = res
              //图片加载完毕
              image.onerror = rej
              image.src = path
          })
      }
      
  • 通过Ajax加载图片

    • function imga(url){
          return new Promise((res,rej) => {
              var request = new XMLHttpRequest()
              request.open('GET',url)
              request.onload = function(){
                  if(request.status === 200){
                      res(request.response)
                  }else{
                      rej(Error('error code:'+request.statusText))
                  }
              }
              request.onerror = function(){
                  rej(Error('It is a network error.'))
              }
              request.send()
          })
      }
      
Promise对象的原理剖析

在这里插入图片描述

async函数

async函数是什么
  • 最主要的目的就是简化使用Promise异步调用的操作,并对一组Promise执行某些操作

  • function fn(){
        return new Promise((res) => {
            setTimeout(() => {
                res('111')
            },200)
        })
    }
    
    /* async function fun(){
        console.log('222');
        var result = await fn()
        console.log(result);
    }
    fun()//222 111 */
    
    let promise = fn()
    promise.then((data) => {
        console.log(data);//111
    })
    
语法结构
  • 异步函数声明式

    • 用于定义一个返回Promise对象的异步函数
    • 异步函数是指通过事件循环异步执行的函数,它会通过一个隐式的Promise返回其结果
    • async funtion name([param[,param[,…param]]]){statements}
      • name - 表示函数名称
      • param - 要传递给函数的参数的名称
      • statements - 表示函数体语句
  • 异步函数表达式

    • 用于在表达式中定义异步函数
    • let name = async funtion([param[,param[,…param]]]){statements}
      • name - 表示函数名称
      • param - 要传递给函数的参数的名称
      • statements - 表示函数体语句
  • 返回Promise对象

    • async函数内部return语句返回的值,会成为then方法回调函数的参数

    • //async函数返回Promise对象
      async function fn(){
          return '111'
      }
      let promise = fn()
      // console.log(promise);//Promise { '111' }
      
      promise.then((data) => {
          console.log(data);//111
      })
      
await表达式
  • 用于等待一个Promise对象,它只能在异步函数中使用

  • function fn(){
        return new Promise((res,rej) => {
            setTimeout(() => {
                res('111')
            },200)
        })
    }
    
    async function fun(){
        console.log('2222');
        var result = await fn()
        console.log(result);
    }
    fun()//2222 111
    
注意事项
  • 使用try…catch语句

    • function fn(){
          return new Promise((res,rej) => {
              setTimeout(() => {
                  res('成功了')
                  //rej('111')
              },200)
          })
      }
      
      async function fun(){
          console.log('2222');
          try{
              var result = await fn()
              console.log(result);
          }catch(e){
              console.log(result);
          }
      }
      fun()
      
  • 多个await同时触发

    • let promise1 = new Promise((res,rej) => {
          setTimeout(() => {
              res('111')
          },100)
      })
      
      let promise2 = new Promise((res,rej) => {
          setTimeout(() => {
              res('222')
          },200)
      })
      
      let promise3 = new Promise((res,rej) => {
          setTimeout(() => {
              res('333')
          },300)
      })
      
      async function fn(){
          let result1 = await promise1
          console.log(result1);
      
          let result2 = await promise2
          console.log(result2);
      
          let result3 = await promise3
          console.log(result3);
      }
      fn()//111 222 333
      
  • await表示的限制

    • await表达式只能用于async函数之中

迭代器与生成器

Symbol
  • Symbol是什么

    • 新增的第六种原始类型Symbol(符号)类型,Symbol类型是唯一的并且是不可修改的

    • /*
          JavaScript五种原始类型
          * number - Number
          * string - String
          * boolean - Boolean
          * undefined - Undefined
          * null - null
      
      */
      let num = 100;
      let str = '111'
      let boo = true
      
      /*
          Symbol类型是ES6新增的第六种原始类型
          * Symbol 类型是唯一的并且是不可以修改的,只能修改变量的值
          let symbol = Symbol()
      */
      let symbol = Symbol()
      console.log(typeof symbol);//symbol
      let symbol2 = Symbol('222')
      console.log(symbol2);//Symbol(222)
      let symbol3 = Symbol(5)
      console.log(symbol3);//Symbol(5)
      
      
  • Symbol的注意事项

  • Symbol的方法

    • Symbol.for()方法

      • 该方法会根据给定的键key,来从运行时的symbol注册表中找到对应的symbol

      • /*
            Symbol.for()方法
            * 作用 - 从Symbol类型中查找指定的key
                * 如果存在这个key,返回
                * 如果不存在这个key,创建
        */
        let t = Symbol('foo')//创建
        console.log(t);
        let t = Symbol('foo')//查找
        console.log(t);
        
    • Symbol.keyFor() - 同for()方法

  • Symbol与for…in

    • Symbols在for…in迭代中不可枚举,Object.getOwnPropertyNames()不会返回symbol对象的属性,但是可以使用Object.getOwnPropertySymbols()得到

    • var obj = {}
      obj[Symbol('a')] = 'a'
      obj[Symbol('b')] = 'b'
      obj['c'] = 'c'
      obj['d'] = 'd'
      
      for(var i in obj){
          console.log(i);//c d
      }
      
迭代器
  • ECMAScript5规范表示集合的数据结构有数组(Array)和对象(Object),ECMAScript6规范又新增了Set和Map两种集合,这样在JavaScript中就具有四种集合,需要一种统一的机制进行操作

  • 迭代器(Iterator)就是这样的一种机制,为各种不同的数据结构提供统一的访问机制,任何数据结构只要部署Iterator接口,就可以完成遍历操作

  • 迭代器(Iterator)具有三种作用

    • 为各种数据结构,提供一个统一的、简便的访问接口
    • 使得数据结构的成员能够按某次次序排列
    • ECMAScript6新增了for…of循环语句,用于遍历迭代器
  • Iterator接口

    • 是一个对象,该对象提供了next()方法用于返回序列中的下一项,该方法返回包含done和value两个属性的对象

    • function fn(arr){
          var index = 0
          return {
              next:function(){
                  return index<arr.length?{
                      done:false,
                      value:arr[index++]
                  }:{
                      done:true
                  }
              }
          }
      }
      var arr = ['11','22','33','44']
      let iterator = fn(arr)
      console.log(iterator.next());//{ done: false, value: '11' }
      console.log(iterator.next());//{ done: false, value: '22' }
      console.log(iterator.next());//{ done: false, value: '33' }
      console.log(iterator.next());//{ done: false, value: '44' }
      
    • 一种数据结构只要部署了Iterator接口,就可以称这种数据结构“可遍历的”

    • Symbol.iterator属性本身是一个函数,就是当前数据结构默认的迭代器生成函数

    • const obj = {
          [Symbol.iterator]:function(){
              return{
                  next:function(){
                      return{value:1,done:true}
                  }
              }
          }
      }
      
  • 迭代协议

    • 允许JavaScript对象去定义或定制他们的迭代行为
    • 就是这个对象(或者它原型链上的某个对象)必须有一个名字是Symbol.iterator的属性
  • 迭代器协议

    • 定义了一种标准的方式来产生一个有限或无线序列的值
    • 当一个对象被认为是一个迭代器时,它实现了一个next()的方法并且有以下含义
      • 返回一个对象的无参函数,被返回对象拥有两个属性
        • done(boolean)
          • 如果迭代器已经经过了迭代序列时为true,这时value可能描述了该迭代器的返回值
          • 如果迭代器可以产生序列中的下一个值,则为false,这等效于连同done属性也不指定
        • value - 迭代器返回的任何JavaScript值,done为true时可省略
for…of语句
  • for…of语句的用法

    • 用于遍历迭代器

    • let arr = [1,2,3,4,5]
      for(let attr of arr){
          //得到数组的元素内容
          
      
  • 返回迭代器对象的方法

    • entries()方法 - 返回一个新的迭代器对象,这个对象的元素是用来遍历[键名,键值]组成的数组

    • keys()方法 - 返回一个新的迭代器对象,用来遍历所有的键名

    • values()方法 - 返回一个新的迭代器对象,用来遍历所有的键值

    • let set = new Set(arr)
      for(let attr of set){
          //得到set集合的元素内容
          console.log(attr);//1 2 3 4 5
      }
      
      let map = new Map()
      let num  = 10,str = '222',obj = {},fn=function(){}
      map.set('num',num)
      map.set('fn',fn)
      map.set('obj',obj)
      map.set('str',str)
      for(let attr of map){
          //得到map集合的key/value对
          console.log(attr);//[ 'num', 10 ] [ 'fn', [Function: fn] ] [ 'obj', {} ] [ 'str', '222' ]
      }
      
      let string = 'hahahha'
      for(let attr of string){
          console.log(attr);//h a h a h h a
      }
      
  • 与forEach()方法的区别

    • forEach()方法无法跳出循环,break语句和continue语句无效
    • for…of语句不仅可以使用break语句和continue语句,还可以配合使用return语句
  • 与for…in语句的区别

    • for…in不仅遍历自身,还会遍历手动添加的,甚至包括原型链的

    • 如果用于遍历数组的话,遍历得到的键名为字符串类型的数字值

    • Object.prototype.objCustom = function(){}
      Object.prototype.arrCustom = function(){}
      
      let iterator = [3,5,7]
      iterator.foo = 'hello'
      
      /* for(let i in iterator){
          console.log(i);//0 1 2 foo objCustom arrCustom
      } */
      
      for(let i of iterator){
          console.log(i);//3 5 7
      }
      
生成器
  • Generator函数是什么

    • 作为生成一个迭代器的特殊函数,该函数被调用时返回一个Generator对象,该对象是符合可迭代协议和迭代器协议的

    • Generator函数与普通函数的区别

      • funtion*这种声明方式会定义一个生成器函数,它返回一个Generator对象

      • yield关键字用来暂停和恢复一个生成器函数

      • function* fn(){}
        let result = fn()
        console.log(result);//Object [Generator] {}
        
  • funtion*表达式

    • 定义一个生成器函数,它返回一个Generator对象
  • yield表达式

    • 用来暂停和恢复一个生成器函数

    • //定义一个生成器函数
      function* fn(){
          let arr = ['11','22','33','44']
          for(let i=0;i<arr.length;i++){
              yield arr[i]
          }
      }
      //生成器函数调用返回生成器对象
      let t = fn()
      //生成器对象就是ES6提供的迭代器
      console.log(t.next());//{ value: '11', done: false }
      console.log(t.next());//{ value: '22', done: false }
      console.log(t.next());//{ value: '33', done: false }
      console.log(t.next());//{ value: '44', done: false }
      console.log(t.next());//{ value: undefined, done: true }
      
  • yield*表达式

    • 用于委托给另一个Generator或可迭代对象

    • function* fn(){
          yield 2;
          yield 3;
      }
      
      function* fnu(){
          yield 1
          yield* fn()
          yield 4
      }
      var t = fnu()
      console.log(t.next());//{ value: 1, done: false }
      console.log(t.next());//{ value: 2, done: false }
      console.log(t.next());//{ value: 3, done: false }
      console.log(t.next());//{ value: 4, done: false }
      console.log(t.next());//{ value: undefined, done: true }
      
  • Generator对象的方法

    • next()方法 - 返回一个包含属性done和value的对象,该方法也可以通过接受一个参数用以向生成器传值
    • return()方法 - 返回给定的值并结束生成器
    • throw()方法 - 用于向生成器抛出异常,并恢复生成器的执行,返回带有done及value两个属性的对象

class关键字

类的声明
  • 类是什么

    • 类作为对象的模板,只是一个语法糖。class关键字只是让对象原型的写法更加清晰、更像面相对象编程的语法而已

    • /* //ES5创建构造函数
      function Hero(){
          this.name = '111'
          this.sayMe = function(){
              console.log('222');
          }
      }
      Hero.prototype = {
          age:19,
          fun:function(){
              console.log('333');
          }
      }
      
      var hero = new Hero()
      console.log(hero.sayMe());//222 */
      
      //ES6
      class student{
          //构造器
          constructor(){
              this.name = '111'
              this.sayMe = function(){
                  console.log('222');
              }
          }
      }
      var t = new student()
      console.log(t.name);//111
      
  • 类的声明

    • 类的声明方式

    • 类的表达式方式

      • 不同于类表达式,类声明不允许再次声明已经存在的类,否则将会抛出一个类型错误
    • /*
          1.类的声明方式
          class className{
              内部结构
          }
          * class关键字 - 用于创建类
          * className - 表示创建的类名
      */
      class Hero{}
      
      /*
          2.类的表达式方式
              const/var/let myClass = class[className]{
                  内部结构
              }
              * class关键字 - 用于创建类
              * myclass/className - 表示创建的类名
                  * myClass - 类名,用于后面的代码逻辑进行调用
      */
      let hero = new Hero()
      
  • 构造函数

    • 在一个类中只能有一个名为“constructor”的特殊方法。一个类中出现多次构造函数(Constructor)方法将会抛出一个SyntaxError错误

    • 在一个构造方法中可以使用super关键字来调用一个父类的构造方法

    • 如果没有显示指定构造方法,则会添加默认的constructor方法

    • 如果不指定一个构造函数(constructor)方法,则使用一个默认的构造函数

    • /*
          创建类 - 结构
          * 外层的类的语法结构
          * 内层的构造器的语法结构
      */
      class Hero{
          //构造器
          constructor(){
              this.name = '111'
              this.sayMe = () => {
                  console.log('22');
              }
          }
      }
      let t = new Hero()
      console.log(t);//Hero { name: '111', sayMe: [Function] }
      
  • getter与setter

    • 对某个属性设置存值函数和取值函数,拦截该属性的存取行为

    • /* //ES5
      function fn(){
          var v = 10//局部变量
          return{
              get:() =>{
                  return v
              },
              set:(data) => {
                  v = data
              }
          }
      }
      var obj = fn()
      obj.set(20)
      console.log(obj.get());//20 */
      
      /* function fn(){
          var v = 20
          this.get =  () => {
              return v
          }
          this.set = (data) => {
              v = data
          }
      }
      var obj = new fn()
      obj.set(220)
      console.log(obj.get());//220 */
      
      //ES6
      class fn{
          constructor(){
              this.v = 10
          }
          get t(){
              return this.vs
          }
          set s(data){
              v = data
          }
      }
      var obj = new fn()
      obj.v = 22
      console.log(obj.v);//22
      // console.log(obj);//fn { v: 10 }
      // obj.t()//obj.t is not a function
      
  • 不允许声明提前

  • 不允许重复声明

静态方法
  • 静态方法的语法

    • statochi关键字为一个类定义了一个静态方法,静态方法不会在类的实例上被调用,被类本身调用
    • /* class fn{
          constructor(){
              this.name = '111'
          }
          static t(){
              console.log('222');
          }
      

    }
    //通过类直接调用方法
    fn.t()//222

    let v = new fn()
    console.log(v);//fn { name: ‘111’ } */

    //ES5 构造函数和对象的概念
    function fn(){
    this.name = ‘111’
    }
    fn.hero = () => {
    console.log(222);
    }
    var t = new fn()
    console.log(t);//fn { name: ‘111’ }
    fn.hero()//222

    
    
  • 静态方法的语法

    • 从另一个静态方法调用
    • class Hero{
          constructor(){
              //构造器 - 创建对象时,初始化的属性和方法
              this.name = '111'
              this.sayMe = () => {
                  console.log('222' + this.name);
                  //在构造器中调用静态方法的话,类名直接调用
                  //Hero.sayYou()
                  this.constructor.sayYou()
              }
          }
          toString(){
              console.log('333' + this.name);
          }
          static sayYou(){
              console.log('444' + this.name);
          }
          static sayHe(){
              //当前静态方法中,调用另一个静态方法
              console.log('555' + this.name);
              this.sayYou()
          }
      

    }

    let t = new Hero()
    //t.sayMe()//222111
    // console.log(t);//Hero { name: ‘111’, sayMe: [Function] }
    // t.toString()//333111
    // Hero.sayHe()//555Hero 444Hero
    //t.sayYou()//t.sayYou is not a function
    t.sayMe()//222111 444Hero

    
    
    
    
类的继承
  • 实现类的继承

    • class fn{
          constructor(){
              this.name = '111'
              this.sayMe = () => {
                  console.log('222');
              }
          }
          sayYou(){
              console.log('333');
          }
          static sayHe(){
              console.log('444');
          }
      }
      class fun extends fn{
          constructor(){
              super() //super - 指向当前子类的父类的构造器
              this.age = 19
          }
      }
      
      let t = new fun()
      console.log(t);//fun { name: '111', sayMe: [Function], age: 19 }
      //类中的普通方法不能用类名直接调用
      console.log(t.sayYou());//333
      console.log(fun.sayHe());//444
      
  • 继承与内置对象

    • class fun extends Date{
          constructor(){
              super()
          }
          Time(){
              var month = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec']
              return this.getDate() + '--' + month[this.getMonth()] + '--' + this.getFullYear
          }
      }
      let t = new fun()
      console.log(t.Time());//29--Oct--function getFullYear() { [native code] }
      
      var arr = [1,2,3,4,5]
      class array extends Array{
          constructor(){
              super()
          }
          say(a){
              return new Set(a)
          }
      }
      let a = new array()
      console.log(a.say(arr));//Set { 1, 2, 3, 4, 5 }
      
  • super关键字

    • super关键字作为函数调用时,代表父类的构造函数,ECMAScript6要求子类的构造函数必须执行一次super函数
    • super作为对象时,在普通方法中,指向父类的原型对象,在静态方法中,指向父类

完整示例

//定义一个类
class Parent{
    //表示当前类的构造器(如果省略,JavaScript会自动生成) - 创建实例对象时的初始化
    constructor(name){
        this.name = name;
    }
    //当前类的(实例对象的)方法,不是当前类地原型方法
    toString(){
        console.log('Parent toString');
    }
    static staticMethod(){
        console.log('Parent staticMethod');
        return 'Parent staticMethod'
    }
}
//定义类原型上的方法
Parent.prototype.sayMe = () => {
    console.log('Parent sayMe');
    return 'Parent 11 sayMe'
}
class Child extends Parent{
    constructor(name,age){
        super(name);//指向父类的构造器
        this.age = age
        //以下用法 - 指向父类的实例对象(具有隐式原型),自动调用一次对应的方法
        super.sayMe();//指向父类的原型对象
        super.toString()//指向父类的实例对象
    }
    sayMe(){
        //super -> 指向父类的原型对象
        console.log('Child sayMe' + super.sayMe());
    }
    static staticMethod(){
        //指向父类
        console.log('Child staticMethod' + super.staticMethod());
    }
}
let t = new Child('你好',29)
//console.log(t);//Child { name: '你好', age: 29 }
//父类和子类的相同方法同时调用
t.sayMe()
/* Parent sayMe
Child sayMeParent sayMe */
Child.staticMethod()
/* Parent staticMethod
Child staticMethodParent staticMethod */  

前端模块化

前端开发领域发展到目前阶段
  • 零件化 - 最终呈现给用户是一个完整的产品(由各个零件组成的)
    • 降低生成成本 - 多人协作(每个人各司其职)
    • 降低使用成本 - 各个零件之间是低耦合的
  • 组件化 - 将一个完整的产品划分成各个组件
    • 目前,前端开发中更多是指HTML页面和CSS样式
  • 组件化与模块化的关系
    • 将一个完整的产品,划分成若干的组件
    • 将每一个组件划分成若干的模块
  • 组件化与模块化的特点
    • 是低耦合的 - 软件开发的统一原则
    • 是热插拔的 - 指的就是需要时使用,不需要时去掉
前端模块化是什么
  • 模块化的特点
    • 独立性 - 可以针对一个模块单独进行设计、研发、相对工作量和难度变小
    • 复用性 - 一些通用模块(例如登录或注册)可以被重复使用,而不用每次重新开发
    • 解耦性 - 模块与模块之间,将相互影响降到最低,使得更换、升级或添加某个模块,不影响其他模块的工作
    • 灵活性 - 通过选择和组合不同的模块,可以快速构建一个新的产品
ECMAScript5的模块化
  • 没有模块化概念

  • 函数的封装、

    • 污染了全局命名空间(无法在全局作用于再定义一个outer()函数)
  • 对象的定义

    • 解决了全局命名空间可能出现的冲突问题,因为所有的模块成员都是作为一个对象的属性或方法存在的
    • 模块成员之间也存在着某种关系,因为被定义在同一个JavaScript对象中,作为属性或方法存在,而这个对象名称为了所有模块成员对外的一个统一的模块名称
  • 自调函数

    • 会产生一些意外的安全问题,而这个问题可以通过自调函数来进行解决
  • 最终模块化结构

    • var t = (function(){
          var v = '111'
          var interface = {
              getAttr:function(){
                  return v;
              },
              inner:function(){
                  return 'this is inner funtion'
              }
          }
          return interface
      })()
      
ECMAScript6的模块化
  • ECAMSCript6的模块化
    • ECMAScript2015的模块自动开启严格模式即使没有写use strict
    • 可以在模块中使用import和export命令
  • export命令
    • 将当前JavaScript文件当作是一个模块
      • 当前的JavaScript模块文件自动开启严格模式
      • 使用export命令将当前模块内容导出(给其他模块使用)
  • import命令
    • ECMAScript6提供import命令导入其他模块
    • import{…}from modulePath
      • {…} - 与导入模块的导出部分保持一致
      • modulPath - 表示导入模块的路径
      • import导入其他模块时,允许定义别名
        console.log(‘Parent toString’);
        }
        static staticMethod(){
        console.log(‘Parent staticMethod’);
        return ‘Parent staticMethod’
        }
        }
        //定义类原型上的方法
        Parent.prototype.sayMe = () => {
        console.log(‘Parent sayMe’);
        return ‘Parent 11 sayMe’
        }
        class Child extends Parent{
        constructor(name,age){
        super(name);//指向父类的构造器
        this.age = age
        //以下用法 - 指向父类的实例对象(具有隐式原型),自动调用一次对应的方法
        super.sayMe();//指向父类的原型对象
        super.toString()//指向父类的实例对象
        }
        sayMe(){
        //super -> 指向父类的原型对象
        console.log(‘Child sayMe’ + super.sayMe());
        }
        static staticMethod(){
        //指向父类
        console.log(‘Child staticMethod’ + super.staticMethod());
        }
        }
        let t = new Child(‘你好’,29)
        //console.log(t);//Child { name: ‘你好’, age: 29 }
        //父类和子类的相同方法同时调用
        t.sayMe()
        /* Parent sayMe
        Child sayMeParent sayMe /
        Child.staticMethod()
        /
        Parent staticMethod
        Child staticMethodParent staticMethod */

### 前端模块化

#### 前端开发领域发展到目前阶段

- 零件化 - 最终呈现给用户是一个完整的产品(由各个零件组成的)
  - 降低生成成本 - 多人协作(每个人各司其职)
  - 降低使用成本 - 各个零件之间是低耦合的
- 组件化 - 将一个完整的产品划分成各个组件
  - 目前,前端开发中更多是指HTML页面和CSS样式
- 组件化与模块化的关系
  - 将一个完整的产品,划分成若干的组件
  - 将每一个组件划分成若干的模块
- 组件化与模块化的特点
  - 是低耦合的 - 软件开发的统一原则
  - 是热插拔的 - 指的就是需要时使用,不需要时去掉

#### 前端模块化是什么

- 模块化的特点
  - 独立性 - 可以针对一个模块单独进行设计、研发、相对工作量和难度变小
  - 复用性 - 一些通用模块(例如登录或注册)可以被重复使用,而不用每次重新开发
  - 解耦性 - 模块与模块之间,将相互影响降到最低,使得更换、升级或添加某个模块,不影响其他模块的工作
  - 灵活性 - 通过选择和组合不同的模块,可以快速构建一个新的产品

#### ECMAScript5的模块化

- 没有模块化概念

- 函数的封装、

  - 污染了全局命名空间(无法在全局作用于再定义一个outer()函数)

- 对象的定义

  - 解决了全局命名空间可能出现的冲突问题,因为所有的模块成员都是作为一个对象的属性或方法存在的
  - 模块成员之间也存在着某种关系,因为被定义在同一个JavaScript对象中,作为属性或方法存在,而这个对象名称为了所有模块成员对外的一个统一的模块名称

- 自调函数

  - 会产生一些意外的安全问题,而这个问题可以通过自调函数来进行解决

- 最终模块化结构

  - ```
    var t = (function(){
        var v = '111'
        var interface = {
            getAttr:function(){
                return v;
            },
            inner:function(){
                return 'this is inner funtion'
            }
        }
        return interface
    })()
    ```

#### ECMAScript6的模块化

- ECAMSCript6的模块化
  - ECMAScript2015的模块自动开启严格模式即使没有写use strict
  - 可以在模块中使用import和export命令
- export命令
  - 将当前JavaScript文件当作是一个模块
    - 当前的JavaScript模块文件自动开启严格模式
    - 使用export命令将当前模块内容导出(给其他模块使用)
- import命令
  - ECMAScript6提供import命令导入其他模块
  - import{....}from modulePath
    - {...} - 与导入模块的导出部分保持一致
    - modulPath - 表示导入模块的路径
    - import导入其他模块时,允许定义别名
    - import{导出的名称 as 别名} from modulePath
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值