【 ECMAScript 6.0】es6-面向对象

ES6

1.两大编程思想

  • 面向过程编程POP(process-oriented programming)
    • 含义:分析问题的解决步骤,通过函数实现每一步,然后依次调用函数来完成;
  • 面向对象编程OOP(Object Oriented programming)
    • 含义:把事务分解成一个个对象,通过对象之间分工与合作解决;(拟人化,把万物写活
  • 例子:要把大象放冰箱:

    • 面向过程:
      • 函数把冰箱打开,函数把大象放进去,函数把冰箱关闭;
    • 面向对象:
      • 大象:(给它功能)进去
      • 冰箱:(给它功能)打开,关闭
      • 大象与冰箱之间配合就能完成,把大象装进冰箱这件事;

2.面向对象

  • 优点:灵活、代码可复用、易扩展、易维护
  • 特性:封装性、继承性、多态性
  • 缺点:(盖浇饭)性能比面向过程(蛋炒饭)低

2.1. ES6的类和对象

  • 事物:具体的事物、抽象的事物。
  1. 面向对象的思维:封装和实例化
  • 抽取对象的共用的属性和行为组织(封装)成一个类(模板);
  • 对类进行实例化,获取类的对象
  1. 对象:是一组无序的相关属性和方法的集合;
  2. 类:抽象了对象的公共的部分,使用class来声明;通过new来实例化;
2.1.1.类
  • class:

    • **构造函数:**使用constructor(参数1,参数2…){this.属性名 = 参数1;}定义共有的属性;实例通过new Class()时自动执行构造函数;this指向new的实例
    • **普通函数:**使用函数名(){}定义共有的方法;this指向当前类的构造函数中的属性;
  • 类的继承extends:

    • class Father {}

      class Son extends Father {}

    • 子类构造函数中使用super():

      • 调用父类的构造函数和普通函数;
      • 当父类函数中使用了this时,this指向的是父类的构造函数中属性;所以需要super()将数据传给父类的构造函数从而使用父类中带有this的函数;
      • super()必须放在子类自身的this.属性 前调用;
    • 继承属性或方法遵循:就近原则,虽然继承,但子类有的就不执行父类的,若想使用父类的同名方法,可以:super.同名方法()

  • 类没有变量提升,先定义类,再实例化:

  • 类中的属性和方法要使用this;

  • 类中构造函数constructor的this:就是实例化后的对象,调用者;

  • 类中普通函数的this:是这个方法的调用者;

2.1.2.面向对象案例
  • 功能需求:tab
2.1.3.构造函数和原型
构造函数
  • es6之前没有类的概念,就是利用构造函数模拟类(写属性和方法),创建对象;

  • 创建对象的方式:

    • 方式一:利用new Object():var obj = new Object()
    • 方式二:对象字面量创建对象:var obj = {}
    • 方式三:利用构造函数创建对象: function Star(){};var obj = new Star()
  • new在执行时做的四件事:

    • 在堆内存中创建一个新的空对象;
    • 让this指向这个新的对象;
    • 执行构造函数里面的代码,给这个新对象添加属性和方法;
    • 返回这个新对象(所以构造函数里面不需要return)
  • 构造函数内的成员:

    构造函数中的属性和方法就是成员;(与类中的构造函数不同,类中的构造函数只写属性,方法用普通函数写)

    • 实例成员:构造函数内部通过this添加的属性和方法;只能通过实例化的对象访问;

      function Star(name, age) {
      this.unmae = name;
      this.age= age;
      this.sing = function() {
      console.log('aaa')
      }
      }
      //var ldh = new Star('刘德华', 18)
      console.log(ldh.uname)
      
    • 静态成员:通过构造函数本身添加的成员;只能通过构造函数直接访问;

      Star.sex = '男'
      console.log(Star.sex)
      
原型的出现
  • 没有类之前,使用构造函数的问题:

    • 因为构造函数是通过new使用,每次new一个实例对象,会在堆内存开辟一块空间,这是正常的;
    • 只是当构造函数中的成员有方法时,就是有函数,函数又会在堆内存中开辟一块空间,而正常的属性不会;这样一来每次实例化一个对象就会占用两个或多个堆内存,公共方法内容都是一样的,显然就是浪费内存;
  • 构造函数的原型:prototype对象

    • 原型就是每个构造函数内的prototype属性指向的一个对象,用于存放公共的方法;
    • 原型单独占用一块堆内存,存放构造函数中的公共方法,构造函数中通过prototype指向这个对象,从而使得实例化的对象也能找到这个对象;
    • 从而每个实例化对象都会指向这一个原型对象,调用公共方法;从原来的自己找地存放方法到现在去公共地方找;节省了内存。
  • 实例化对象的原型__proto__

    实例化对象有个__proto__对象原型属性,这个属性跟构造函数的原型对象的指向是同一个对象;所以实例化对象可以访问构造函数原型上的方法;
    lbh.__proto__ === Star.prototype
    //proto、prototype都是系统自动添加的;
    
  • javascript成员查找规则:

    • 访问一个对象的属性或方法时:先查找对象自身是否有该属性;
    • 如果没有就是沿着原型链,**找上一级原型对象;也就是proto指向的原型对象;**不是找构造函数!
    • 再没有就继续往上,找原型对象的原型,直到找到null也没找到,就返回undefined
  • 构造函数以及原型对象中的this指向的都是实例化的对象;

2.1.4.继承

es6 之前没有提供 extends继承,可以通过构造函数+原型模拟继承,也成为组合继承

  • call():直接调用函数;

    fun.call(thisArg,arg1,arg2,...)
    thisArg:当前调用函数this的指向对象
    
    • 作用一:调用函数;
    • 作用二:改变this指向;
  • 在es6之前,实现继承方式:借用父构造函数继承属性

function Father(uname,age) {
this.uname = name;
this.age = age;
}
function Son(uname,age){
Father.call(this,uname,age)//直接执行了父构造函数
}
var son = new Son('aa',12)

  • 借用原型对象继承方法:

    • 想要Son的实例继承父构造函数原型上的money方法;

    • 让子构造函数的原型对象指向父构造函数实例

      Son.prototype = new Father(),这样就可以通过父构造函数实例的proto访问父构造函数原型对象上的方法money;

    • 此时,再通过Son.prototype.exam = function(){},创建的方法就添加到当前这个对象father实例上了,不会影响父构造函数的原型对象;

    • 但是现在Son的实例对象就不能指向Son构造函数的原型对象了,需要把

      Son.prototype.constructor = Son;
      
2.1.5.es6新出的类
  • 构造函数特点:

    • 构造函数有原型对象;(实例化对象有对象原型)
    • 构造函数原型对象上有constructor指向构造函数本身;
    • 构造函数可以通过原型对象添加方法;
    • 构造函数创建的实例,有proto 原型指向构造函数的原型对象;
  • es6通过类实现面向对象编程

    • 类本质就是一个函数:构造函数(属性)、普通函数(方法)
  • es6新增的方法

    • 遍历数组方法:forEach()、map()、filter()、some(只有some,利用return true可以终止循环,寻找唯一数组时效率高)、every()

      var arr = [1,2,3];
      var sum = 0;
      arr.forEach(function(value,index,array){
      console.log('每个数组元素'+value);
      console.log('每个数组元素的索引'+index);
      console.log('数组本身'+array);
      sum +=value
      })
      console.log(sum)//6
      
    • filter():筛选数组元素,返回新数组,需要接收;

      var arr = [11,22,33]
      var newArr = arr.filter(function(value,index){
      return value >=20;
      })
      console.log(newArr);//[22,33]
      
    • some():用于检测数组中元素是否满足某个条件,满足就返回true不再继续执行,否则返回false;

      var arr = [10,20,30]
      var flag = arr.some(function(value){
      //return value > 20;//true
      return value<3;//不直接返回true/false时就要返回条件,然后在外面接收;
      })
      console.log(flag);//false
      
      • filter、some,都是查找条件,filter将满足条件的所有元素返回到向新数组;some就是查看是否满足,返回true/false,并且中途满足了就不再向后执行;

      • 查找数组中唯一元素时,some比较合适;利用return true就不用外面接收了;

        data.some(function(value){
        if(value.pname == product.value){
        arr.push(value);//需要在方法内部把要做的事情做了
        return true;
        }//直接返回了true/false,就不需要外部接收了。
        
      • 获取按钮dom元素:querySelector(按css选择器获取第一个),querySelectorAll()
        var search_pro = document.querySelector('.search_pro')
        监听按钮点击(绑定点击事件是onclick,按钮有点击事件不用绑定):
        search_pro.addEventListener('click',function(){
        var arr = [];
        data.some(function(value){
        if(value.pname == product.value){
        arr.push(value);
        return true;
        }
        });
        setData(arr);
        })
        
    • trim()方法,去除字符左右两边的空格,并返回新字符串;

      var str1 = str.trim();
      -------------------------------
      var input = document.querySelector('input');
      var btn = document.querySelector('botton');
      var div = document.querySelector('div');
      btn.onclick = function(){
      var str=input.value.trim();
      if(str === ''){alert('请输入内容')}
      div.innerHTML=str;
      }
      
  • es5新增的方法

    • 对象方法:Object.defineProerty();定义新属性或者修改原有属性;

      //Object.defineProperty(对象名,属性名,{对象配置/描述})
      第一个参数:obj
      第二个参数:prop
      第三个参数配置:descriptor
      {
      value:999;//设置属性的值,默认undefined
      writable:false;//设置属性的值是否可以重写,默认false,不可重写
      enumerable:false;//设置属性是否可枚举,默认false,不可枚举
      configurable:false;//设置属性是否可以被删除或者是否可以修改配置,默认false,不可删除不可配置;
      }
      console.log(Object.keys(obj));//["id","name"],age,不可枚举的不会遍历出来
      

2.2.函数

2.2.1.函数的多种定义和调用方式
  • 三种定义方式:

    • 方式一:(声明函数)命名函数:function fn(){}
    • 方式二:(表达式),匿名函数:var fun = function(){}
    • 方式三:(使用构造函数)new Function(‘参数’,‘函数体’): var fun = new Function()

    //所有函数都是Function的实例,因为所有函数都有proto原型,所以所有函数都是对象

  • 六种调用方式:

    • 调用一:普通自调用:fn()
    • 调用二:对象的方法:star.sing()
    • 调用三:构造函数:new Star()
    • 调用四:绑定事件:btn.onclick = function(){}
    • 调用五:定时器函数:setInterval(function(){},1000)
    • 调用六:立即执行函数:(function(){})();
2.2.2.函数内部this指向
  • this的指向为调用者;(七种调用者就是七种指向情况)

    • fn():this指向:window
    • 对象方法中this指向对象:star
    • 构造函数this指向实例对象,原型对象也是指向实例对象;
    • 事件this指向事件调用者:btn
    • 定时器中this:window
    • 立即执行的this:window
    • 箭头函数中this,沿作用域链往外找,直到有this定义。
  • 改变this指向:

    • call():fn.call(obj,uname,age,sex)

      • 作用:1、调用执行函数;2、改变this为指定对象;3、实现继承,因为有调用效果,在子构造函数中执行:

        Father.call(this,uname,age,sex)

    • apply():fn.apply(obj,[参数,参数]):参数必须为数组

      • 作用:1、调用执行函数;2、改变函数this指向;3、Math.max.apply(null,arr):返回数组中最大值,标准写法:Math.max.apply(Math,arr);严格模式下用null有问题!
    • bind():var newfn = fn.bind()

      • 作用:1、不调用执行函数;2、改变函数内部this指向,但是是对原函数拷贝后的操作,返回改造后的新函数;
    • 应用场景:call经常做继承;apply经常与数组有关系;bind不调用函数,想改变this指向,例如定时器中使用,不立即执行函数;

2.2.3.严格模式特点
  • 特点

    • 消除js中语法上的一些不合理、不安全之处;
    • 提高编译器效率,增加运行速度;
    • 代码中禁用了es未来版本可能会使用的语法和保留字;
  • 使用严格模式方式:

    • 在脚本js中使用严格模式:

      
      
    • 只在函数中使用严格模式:

      function fn(){
      'use strict';
      }
      
  • 严格模式:

    • 必须先声明再使用;num =10;----> var num = 10;
    • 声明的变量不能删除;
    • 全局作用域中函数的this不再指向window,而是undefined;
    • 构造函数使用this,不实例化也会报错,需要使用new创造实例才行;
    • 定时器中this没问题,不受影响还是window;
2.2.4.(高阶函数)把函数作为参数或返回值传递
  • 高阶函数:是对其他函数进行操作,它接收函数作为参数(回调函数)、将函数作为返回值输出;
2.2.5.闭包函数(closure)
  • 变量作用域:全局变量(全局作用域)、局部变量(函数作用域)

  • 闭包:指有权访问另一个函数作用域中变量的函数。:首先是一个函数,然后可以访问并使用别的函数不能访问的函数变量。

  • 闭包作用:延长了变量生命周期,延伸了变量的作用范围;(这也造成了内存泄漏,闭包后不适用,变量就不销毁)

    function fn(){
    var num = 10;//局部变量本来在函数中使用完就销毁,不过闭包了还有函数要用,所以先不销毁;
    return function(){//直接把要对局部变量的操作写在这,返回出去,让外部决定何时执行;
    console.log(num)
    }
    }
    var f = fn();
    f();//变量num在这还要用,在这里使用完才销毁变量num;
    
    //闭包实现点击li输出对应索引
    for(var i = 0; i
2.2.6.递归的两个条件
  • 含义:函数内部自己调用自己,就是递归;

  • 注意:栈溢出问题!就是死循环;一定加return退出。

    var num = 1;
    function fn() {
    console.log('打印六句话')
    num +=1;
    if(num == 6){
    return;
    }
    fn();
    }
    
2.2.7.深拷贝和浅拷贝的区别
  • 浅拷贝:只是拷贝一层,更深层次对象级别的只拷贝引用;

    • 浅拷贝,拷贝了键值对,如果值也是对象,就属于深一层,此时只会拷贝这个属性值的引用地址,所以修改也会原对象;

      //浅拷贝方式一
      var o = {}
      for(var k in obj){
      o[k] = obj[k];//只是拷贝了栈内存中的数据,包括堆内存地址;所以对象o更改堆内存的数据也会影响对象obj;栈内存中的改不了,变量赋值只是改变了自身的指向地址;
      }
      //浅拷贝方式二:es6语法
      Object.assign(o,obj);
      
  • 深拷贝:每一级别的数据都会拷贝;(利用递归)

    • 思路:对每一层都拷贝到底,第一次对第一层拷贝;

    • 就是判断这个属性的值是不是基本数据类型,如果是那就是简单赋值;

    • 如果属性值是数组,就在属性名上新建一个空数组,调用递归,把数组的值拷贝过来;

    • 如果是对象也类似,递归操作,深拷贝子对象;

      //深拷贝对象obj:
      var obj = {id:1,name:'andy',msg:{age:18},color:['white','black']};
      var o = {};
      function deepCopy(newObj, oldObj){//这个函数就是传的新对象、旧对象,所以递归完美!!!!!
      for(var k in oldObj){
      var item = oldObj[k];//获取要拷贝的对象的每个属性的属性值
      -------------------------------------------
      if(item instanceof Array){
      newObj[k]=[];//就是给新对象创建一个数组属性:o.color=[]
      deepCopy(newObj[k],item);//递归,深拷贝obj.color数组对象;将这个属性名的数组对象拷贝给了o.color属性;
      ------------------------------------------------------
      else if(item instanceof Object){
      newObj[k]={};
      deepCopy(newObj[k],item);
      }//要拷贝的属性值是对象,需要深拷贝内部属性,所以采用递归;将这个属性名的对象拷贝给了o.msg属性;
      ---------------------------------------------------
      else{
      newObj[k] = item;//这个属性名的值是简单数据类型,存在栈内存中,直接赋值即可,对象o修改这个属性也不会影响对象obj,只是改了自身的栈地址;
      }
      ---------------------------------------
      }
      }
      }
      deepCopy(o,obj)
      

2.3.正则表达式 Regular Expression

2.3.1.正则的作用
  • 正则表达式(regular expression):用于匹配字符串中字符组合的模式;
  • 三大作用:
    • 第一:匹配:输入的内容与相应规则进行匹配;
    • 第二:替换:对输入的内容中特定的敏感词·进行替换;
    • 第三:提取:根据输入内容,获取我们想要的特定部分;
  • javascript中正则就是进行表单验证;
2.3.2.简单正则表达式
  • 在js创建正则表达式的两种方式:

    • 第一种:利用正则构造函数RegExp

      var reg = new RegExp(具体表达式);//在构造函数中传入具体表达式
      
    • 第二种:利用字面量创建正则表达式

      var reg = /123/;//直接写具体表达式(意思是:包含123就行)
      
  • 写好了正则表达式怎么使用:

    • 利用test()方法验证字符串是否符合验证规则,将指定的字符放入表达式中验证;返回值为true/false

      reg.test(‘abc’);//直接用正则表达式的test方法
      
  • 正则表达式的组成:

    • 可以由简单的字符构成;

    • 可以是简单和特殊字符组合;

      • 其中特殊字符就是元字符,在正则表达式中具有特殊意义的专用符号;
    • 组成部分之----边界符:^、$

      • ^:开始边界符;
      • $:结束边界符;
      • /$/:控制了字符的数量;/^abc$/:必须是abc;/[a-z]$/:必须是a-z中的一个
      var reg = new RegExp(/^abc/);//以abc开头
      var reg1 = new RegExp(/^abc$/);//又是开头又是结尾,精准为abc
      reg.test('abc');//true
      reg.test('aabc');//false
      reg.test('abcabc');//true
      -------------------------------
      reg1.test('abc');//true
      reg1.test('abcd');//false
      reg1.test('abcabc');//false
      
    • 组成部分之----字符类:[]、[-]、[^]

      • []:字符类,表示有一系列字符可选择,只要符合其中一个即可;
      • [-]:范围字符集:/^ [a-zA-Z0-9]$/
      • [^]:取反
      var reg = /[abc]/;//只要有abc中的其中一个都可以;
      var reg1 = /^[abc]$/;//只能是abc中其中一个;
      var reg2 = /^[a-z]$/;//只能是26个字母中的其中一个;
      --------------------------------
      reg.test('as');//true
      reg1.test('a');//true
      reg2.test('f');//true
      ------------------------
      var reg = /^[a-zA-Z0-9_-]$/;//表示只能是26个大小写字母0-9的数字下划线短横线中其中一个,都可以;(现在还是只能输一个字符)
      -----------------------------
      /^[a-zA-Z]$/.test('a');//
      
      • 只要用到/^$/,就是限定了字符串的个数;里面的每个[]只对应一个字符;有几个[]就必须输几个字符才正确返回true;
    • 量词符:设定某个模式出现的次数;/^a* / ; / [ a − z ] 3 , 16 /;/^[a-z]{3,16} //[az]3,16/

      • *:零次或多次都可以;
      • +:大于等于一次,至少出现一次;
      • ?:一次或零次;
      • {n}:重复n次;
      • {n,}:大于等于n次;
      • {n,m}:重复n次到m次范围内都可,包括n、m次;不能有空格;
2.3.3.使用正则对表单进行验证
  • 步骤:1.正则表达式得有;2.表单元素得获取,才能获得它的值;3.何时验证;4.验证出对错后进行啥操作。
//验证手机号码表单步骤:
//第一步:先有用于验证的正则表达式,没有正则怎么验证:
var regtel = /^1[3|4|5|8][0-9]{9}$/;
//第二步:获取表单元素,用于提供要验证的内容:
var tel = document.querySelector('#tel');//通过input标签的id获取元素
//第三步就是验证(什么时候验证,验证后怎么办。):两种情况:true符合/false不符合:分别操作;
tel.onblur = function(){//什么时候验证:表单失去焦点的时候;
if(regtel.test(tel.value)){
tel.nextElementSibling.className = 'success';//下一个兄弟(提示栏)添加success类;
tel.nextElementSibling.innerHTML = '恭喜您输入正确!'
}
else{
tel.nextElementSibling.className = 'error';//下一个兄弟(提示栏)添加error类;
tel.nextElementSibling.innerHTML = '手机格式不正确!'
}
}

  • 可以把正则验证封装到函数中,让外界执行这个函数时:传入正则表达式、表单元素;

    regexp(tel, regtel);
    function(el, reg){
    el.onblur = function(){
    if(reg.test(el.value)){}
    else{}
    }
    }
    
2.3.4.使用正则替换内容
  • replace():替换:字符串通过调用这个方法实现指定字符串替换,用来替换的参数可以是内部包含的字符串、或者是正则表达式匹配的字符串;
stringObject.replace(regexp/substr被替换的内容,replacement用于替换的内容)
:返回值是一个替换完的字符串,所以要接收;
------------------------------------------------------
var str = 'andy和red';
var newStr = str.replace('andy','body');
var newStr = str.replace(/andy/,'body');//替换第一个andy;
  • 正则表达式实现替换时的参数:/匹配内容|匹配内容/[switch]

    • g:全局匹配,查找所有;
    • i:忽略大小写;
    • gi:全局匹配并忽略大小写;
  • 正则表达式的验证、替换功能:

    • 验证:reg.test(‘要验证的字符串’);正则的test方法;
    • 替换:str.replace(正则表达式找要被替换的内容,‘用于替换的内容’),字符串的replace方法。

3.ES6内容

3.1.简介

  • es:ECMAScript,是ECMA国际标准化组织制定的一项脚本语言的标准价规范

  • 2015.6:ES2015(ES6);2016.6:ES2016;…

  • es6就是泛指es2015及以后版本;

3.1.1.为什么学es6:
  • 变量提升特性增加了程序运行时的不可预测性;
  • 以前语法过于松散,相同功能代码不一;
3.1.2.es6新增语法
  • let:声明变量

    • 特征一:使用let声明的变量具有块级作用域;

      • 在{}中:使用let声明的变量具有块级作用域;使用var声明的变量不具有块级作用域;
      • 相当于有了全局作用域、函数作用与、块级作用域;块级与函数类似,同样遵循内层作用域能访问外层作用域;
      • 作用域:就是用于不让外部访问内部;;;内部访问外部没有限制。
      • 好处:防止循环变量变成全局变量;
    • 特征二:不具有变量提升;

      • 必须先声明变量,才能使用let声明的变量;(变量提升其实是语言的bug,不好)

        console.log(a);
        let a = 1;//报错
        
    • 特性三:暂时性死区;

      var num = 100;
      if(true){
      console.log(num);//报错,因为let的暂时性死区特性,花括号内部只要使用let,相应的变量就会自动绑定这个括号里的,而不会去外部找全局变量(按常理是会向外找,但let声明的变量就不行),又因为没有变量提升,所以报错;
      let num = 20;
      }
      
    • 面试题:

      let arr = [];
      for(let i = 0;i<2;i++){
      arr[i] = function(){
      console.log(i);
      }
      }
      arr[0]();//0
      arr[1]();//1
      //let声明的变量会产生块级作用域,相当于:
      {let i = 0;arr[0] = function(){console.log(i)}};
      {let i = 1;arr[1] = function(){console.log(i)}};
      //var声明,相当于:
      var i = 2;
      {arr[0] = function(){console.log(i)}};
      {arr[1] = function(){console.log(i)}};
      
      
  • const:声明常量

    • 常量,就是指向的地址不能发生改变;

      因为基本数据类型就是在栈内存存储的不可变的值,所以指向基本数据类型的地址不改变数据就不会改变;

      而指向堆内存中的是引用类型,当引用类型的内容改变时,但是地址并没有不变也符合常量要求,不会报错。

    • 特性一:具有块级作用域;

    • 特性二:声明常量时,必须赋初值;

    • 特性三:声明常量为基本数据类型时,值不能修改;声明引用数据类型时,值可以修改,只要地址不变就行;

      const arr = [100, 200];
      arr[0] = 123;//正确;地址没有改变;
      arr = [1, 2];//错误;修改了常量地址;
      
    • js解析引擎不需要实时监听常量变化,性能高;

3.1.3. es6解构

按照一定模式,从数组或对象中提取值,将提取的值赋值给另外的变量;

  • []:数组解构

    let arr = [1,2,3];
    let [a,b,c,d] = arr;
    console.log(a);//1
    console.log(d);//undefined
    //变量数量与数组数量一一对应,
    
  • {}:对象解构

    let person = {name:'zhangsan', age:18};
    let { name,age } = person;
    console.log(name);//zhangsan
    console.log(age);//18
    //变量名与对象变量名对应;匹配成功就赋值;
    //想改名用冒号:{name:newName, age:newAge}
    console.log(newName);//zhangsan
    
3.1.4.箭头函数
  • ()=>{}:简化函数定义方式;类似:var fn = function(){};

    • 如果函数体只有一句代码,花括号和return可以省略:(n1,n2)=> n1+n2;

    • 如果形参只有一个,小括号可以省略:n1 => n1;

      const fn = n1=>console.log(n1);
      
  • 箭头函数的this指向:

    • 不同于普通函数:指向调用者;

    • 箭头函数this:指向函数定义位置的上下文(作用域:全局作用域、函数作用域);

      function fn(){
      console.log(this);
      return ()=>{ console.log(this) }
      }
      const obj = { name:'zhangsan' }
      fn.call(obj);//call方法直接执行函数,打印:{name:'zhangsan'};
      //返回的箭头函数,还没有执行;
      const resFn = fn.call(obj);
      resFn();//{name:'zhangsan'}{name:'zhangsan'}
      //不用箭头函数时,应该是指向window;但是箭头函数this指向函数定义时的位置,所以指向fn函数的调用者window,又函数被call改变了this,所以指向对象obj;
      
      • 面试题:
      var age = 100;
      var obj = {
      age:20,
      say:()=>{ alert(this.age) }
      }
      obj.say();//100
      //箭头函数this:指向定义时的执行上下文(作用域);对象没有作用域,所以是全局作用域下的window;
      
      
3.1.5.剩余参数:…[新数组名];
  • 使用一:**用于接收剩余函数参数:**当不确定函数会被传来多少参数,使用剩余参数,将所有参数以数组的形式接收;

    const sum = (a,...args)=>{
    console.log(args);//[2,3],1已经被a接收了;
    }
    sum(1,2,3);//不管传多少,都将没有被接收的参数,以数组形式保存给一个变量;使用的时候只需要对这个数组进行操作;
    
  • 使用二:剩余参数与解构进行结合使用:

    let arr = [1,2,3];
    let [s1,...s2] = arr;
    console.log(s1);//1
    console.log(s2);//[2,3],接收剩余数据,并以数组形式保存;
    
3.1.6.扩展运算符: …[已知数组或对象]:将数组或对象转为用逗号分隔的参数序列;
  • let arr = ['a','b','c']
    ...arr;//'a','b','c';实际就是这个样子,把括号去掉,打印的时候逗号被编译成分隔符所以看不到;在下面数组合并的效果中可以解释;
    console.log(...arr);//a b c
    console.log('a','b','c');//a b c
    
  • 用途:合并数组;push(…arr1);

    • 利用扩展运算符将已知的多个数组扩展成序列,再放到新数组中;

    • push一个元素没问题,如果直接push数组,相当于二维数组了,所以用展开运算符;

      let arr = ['a','b','c'];
      let arr1 = ['d',1,2];
      arr2 = [...arr,...arr1];
      console.log(arr2);//[ 'a', 'b', 'c', 'd', 1, 2 ]
      arr.push(...arr1);//[ 'a', 'b', 'c', 'd', 1, 2 ]
      arr.push(arr1);//[ 'a', 'b', 'c', [ 'd', 1, 2 ] ]
      
  • 扩展运算符与剩余参数:写法相似,作用不同;

    • 剩余参数:将不确定参数转为新数组;…[新数组名];
    • 扩展运算符:将已知的对象或数组展开为序列;…[已知数组或对象]
3.1.7.伪数组转为真正数组
  • 利用扩展运算符:将伪数组展开再用 [] 包裹;

  • 利用数组方法:Array.from(伪数组名);

    var arrayLike = {
    '0':'a',
    '1':'b',
    '2':'c',
    'length':3
    }
    var arr = Array.from(arrayLike);
    console.log(arr);//[ 'a', 'b', 'c' ]
    
3.1.8. es6 数组扩展的方法:四个;Array.from、find()、findIndex()、includes()
  • find():查找数组中第一个满足条件的值,并返回值;

    let newArr =  arr.find(item=>item.id == 2)
    
  • findIndex():查找数组中第一个满足条件的值的索引,并返回索引;

    let index =  arr.findIndex(item=>item.id == 2)
    
  • includes():判断数组中是否包含某个值,返回布尔值;

    let arr = ['a','b','c']
    let result = arr.includes('a');
    console.log(result);//true
    
3.1.9. es6 字符串扩展方法:三个;模板字符串、startsWith()、endsWith()、repeat()
  • 第一个:模板字符串:可以解析变量;模板字符串内容可以换行写;可以调用函数。

    `你好,${变量名}`;
    `${fn()}`;//直接显示执行后的返回值,前提是函数执行有返回值
    
  • 第二个:startsWith()、endsWith():判断字符串是否以某个字符开头或结尾;返回布尔值。

    let r1 = str.startsWith('Hello');
    console.log(r1);//true
    
  • 第三个:repeat():表示将原字符串重复n次,返回一个新字符串;

    'x'.repeat(3);//'xxx'
    

3.2. Set数据结构:类似数组

3.2.1. Set(构造函数)基本作用
  • 用途:用于存储数据,且重复的数据不会多次存放;

  • 场景:浏览器记录用户搜索数据时,可以把用户输入的记录存到Set数据结构中,重复的记录只保存一次,节省空间。

  • Set数据结构怎么创建:

    const s = new Set();
    const s = new Set([1,2,3]);//初始化一些数据,因为类似数组,所以传入数组;
    
  • 作用:做数组去重;

    let arr = ['a','a','b',1,2,1];
    const set = new Set(arr);
    console.log(set.size);//4
    //虽然set类似数组,但终究还是Set数据结构,不是真正的数组,所以要当做伪数组对待;利用扩展运算符转为真正数组;
    const newArr = [...set];或者const newArr = Array.from(set);
    console.log(newArr);//[ 'a', 'b', 1, 2 ]
    
    
3.2.2. Set数据结构的自带方法:
  • add(value):添加值,并返回添加后;可以链式调用;

    const s = new Set();
    s.add('a').add('b');
    
  • delete(value);删除值,返回布尔值,表示是否删除成功;

  • has(value):返回布尔值,检查是否属于Set成员;

  • clear():清空成员,没有返回值。

    有返回值想知道就要接收返回值;

  • 遍历set数据结构:类似数组

    const s = new Set([1,2,3]);
    s.forEach(value=>{
    console.log(value)
    })
    

你可能感兴趣的:(ECMAScript,6.0)