day13

98 阅读11分钟

1.ES6的箭头函数

ES6 的箭头函数
    + ES6 语法内一种定义函数表达式的方式
      => 注意: 声明式函数不能用
      => 所有匿名函数位置都可以使用
        -> var fn = function () {}
        -> var obj = { f: function () {} }
        -> xxx.forEach(function () {})
        -> setTimeout(function () {})
        -> xxx.onclick = function () {}
        -> ...
    + 语法: () => {}
      () 书写 形参 的位置
      => 箭头函数的标志
      {} 书写函数体的位置

  箭头函数的特点
    1. 可以省略 () 不写
      => 当你只有一个形参的时候, 可以不写小括号
    2. 可以省略 {} 不写
      => 当你的函数体只有一句话的时候, 可以省略 {}
      => 并且会把这一句话的结果当做 返回值
    3. 箭头函数内没有 this                           //注意下   !!!!!!!!!!!!!!
      => 箭头函数内没有自己的 this
      => 箭头函数内的 this 就是外部作用域的 this
    4. 箭头函数没有 arguments
      => 箭头函数内没有 arguments 这个实参的集合
    5. 箭头函数不能被改变 this 指向
      => call / apply / bind 都不能改变 箭头函数的 this 指向
    6. 箭头函数不能被当做构造函数使用
      => 箭头函数不能和 new 关键字连用
      
例:
箭头函数的定义
var f1 = function () { console.log('函数表达式') }
var f2 = () => { console.log('箭头函数') }

特点1:
var f1 = () => { console.log('hello world') }
f1()
var f2 = a => { console.log('hello world', a) }  //一个形参可去()
f2(100)
var f3 = (a, b) => { console.log('hello world', a, b) }  //两个形参不可去()
f3(10, 20)

特点2:
var f1 = (a, b) => { return a + b }
console.log(f1(10, 20))
var f2 = (a, b) => a + b               //当你的函数体只有一句话的时候, 可以省略 {}  
console.log(f2(100, 200))

特点3:
var obj = {
  f1: function () { console.log(this) },
  f2: () => console.log(this)
}
obj.f1()                  // this => obj
// 按说 f2 内的 this => obj
// 因为 f2 是一个箭头函数
// 所以 f2 内没有 this
// f2 内的 this 就是 f2 函数外部作用域的 this
// 因为 f2 的外部作用域 window, f2 内的 this 就是 window
obj.f2()

特点4:
var fn = () => console.log(arguments)
fn()

特点5:
var fn = () => console.log(this)
fn()
fn.call({ name: 'Jack' })

2.This指向

箭头函数最重要的目的是解决this指向问题

this 指向
    + 指向: 指引用地址的方向
    + 表达: this 到底是什么
    + 需要结合上下文, 决定不同位置的 this 指向的内容不一样

this 是一个关键字(熟读并背诵全文, 手抄)
    + 是一个使用在作用域内的关键字
      => 要么用在全局
        -> 因为在全局使用 this 的时候
        -> this 指向 window
      => 要么用在函数内
    + 函数内的 this            (this只看函数调用   哪个函数里的this就看哪个函数)
      => 重点: 不管函数定义在哪, 不管函数怎么定义, 只看函数如何被调用(箭头函数除外)
      => 普通调用
        -> 函数名()
        -> this 指向 window
      => 对象调用
        -> 对象名.函数名()
        -> this 指向 对象(点前面是谁就是谁)
      => 定时器调用
        -> setTimeout(函数, 数字)
        -> setInterval(函数, 数字)
        -> this 指向 window
      => 事件处理函数
        -> 事件源.on事件类型 = 函数
        -> 事件源.addEventListener(事件类型, 函数)
        -> this 指向 事件源
      => 未完待续 ...

2.1 This指向补充

This指向在js中是非常丰富的 还有两三个没讲
 1、全局中this指向 window
 2、命名函数或者匿名函数执行时 this指向window或者undefined
 3、命名函数或者匿名函数在任何其他作用域中执行,this指向window或者undefined
 4、对象中方法中的this指向当前对象,对象中属性中的this指向对象外上下文环境中的this
 5、事件函数中this指向侦听事件的对象,谁侦听事件this就是谁
 6、箭头函数中this指向箭头函数外上下文环境中的this指向
 7、正常的回调函数(除事件触发的回调函数外)this全部指向window或者undefined
 8、如果回调函数使用arguments的方式调用执行,被回调函数中this指向回调它的函数中arguments对象
 
例:
4.对象中方法中的this指向当前对象,对象中属性中的this指向对象外上下文环境中的this
    var b = -1;
    var o1 = {
        b: 100,
        init: function () {
            console.log(this);   //对象是o1 
            var b = 0;
            var o = {
                a: this.b,
                b: 2,
                c: function () {
                    console.log(this);  //对象是o
                }
            }

            o.c();
            console.log(o);
        }
    }
    o1.init();
 
5.普通函数中指向事件侦听的对象
     document.addEventListener("click",function(e){
      // this-->document  
     this.clickHandler(e);  //但是document下面是没有clickhandler的所以报错
            })

6、箭头函数中this指向箭头函数外上下文环境中的this指向
     // 箭头函数中this指向箭头函数外上下文环境中的this
     var fn=()=>{
          console.log(this);  //obj
       }
     fn();

7、正常的回调函数(除事件触发的回调函数外)this全部指向window或者undefined
    function fn(f){
        f();
    }
    function fn1(){
        console.log(this); //window|undefined
    }
    fn(fn1);

8.如果回调函数使用arguments的方式调用执行,被回调函数中this指向回调它的函数中arguments对象
    function fn(f){
        arguments[0]()
    }
    function fn1(){
        console.log(this);//指向fn中arguments
    }
    fn(fn1);

3.ES6解构赋值

将整体化整为零就叫做解构

ES6 的解构赋值
    + 目的: 快速从对象或者数组中获取成员
      => 解构数组(不常用)
      => 解构对象
      
      
1.解构数组(不常用)
    + 使用 [] 对数组进行解构
    + 语法: var [ 变量1, 变量2, ... ] = 数组
    + 意义: 按照索引, 把数组内的每一个数据依次赋值给 变量
    + 多维数组解构
      => 原始数组如何书写, 解构如何书写, 数据换成变量
      
例:   
解构数组  (数组里面的元素按位赋值给前面的变量)
var arr = [ 100, 200, 300 ]

1. 解构       ( []在左边叫解构 在右边叫数组 )
var [a, b, c] = arr
console.log(a, b, c)

2. 多维数组解构     (abcdefgi 一一对应)
var arr = [ 1, 2, [ 3, 4, [ 5, 6, [ 7, 8, [ 9 ] ] ] ] ]
      var [ a, b, [ c, d, [ e, f, [ g, h, [ i ] ] ] ] ] = arr
console.log(arr)
console.log(f)
console.log(i)

3. 数组的解构 + var 可以做交换变量
var a = 5
var b = 6
console.log(a, b)
var [ b, a ] = [ a, b ]
console.log(a, b)

4. 数组里面的元素按位赋值给前面的变量
var arr=[1,2,3,4];
var [a,b,c,d]=arr;
var [a,b,c]=arr;
var [a,b,c,d,e]=arr;//e=undefined

5. 如果数组中没有最后一项,e默认值为5,如果有最后一项,则赋值这个元素
var [a,b,c,d,e=5]=arr; 
arr=[1,2,3,4,10]  a=1 b=2 c=3 d=4 e=10
arr=[1,2,3,4]  a=1 b=2 c=3 d=4 e=5


2.解构对象
    + 解构对象使用 {}
    + 语法: var { key, key2, ... } = 对象
    + 意义: 按照你写 key 去对象内获取成员

  解构对象起一个别名
    + 语法: var { key: 别名 } = 对象

  解构多维对象
    + 原始对象如何书写, 解构如何书写, 删除掉值即可, 如果需要别名直接书写
    
例:
1.解构赋值
    function fn({a,b,c:{a:a1=1,b:b1=2}={}}={a:1,b:2,c:{a:3,b:4}}){
        console.log(a,b,a1,b1);//1,2,3,4
    }
    fn({a:1});
    
2.解构对象起一个别名
var obj={a:1,b:{a:2,c:{a:3}}};
 同名属性解构时可以使用:起别名
var {a:a1,b:{a:a2,c:{a:a3}}}=obj;

var obj={a:1,b:{a:2,c:{}}};
var {a:a1,b:{a:a2,c:{a:a3=4}}}=obj;
console.log(a1,a2,a3)

3.赋默认值
function fn(a=1){
  console.log(a);
     }

fn(3); //3
fn(); //1

4.Set和Map

Array  迭代器
连续按位存储的一组数据,紧密结构,删除,插入都会造成数组的结构发生改变,
因此效率较低,但是数组因为紧密性可以获取前后关系元素,可以排序,数组查找需要从头开始遍历,速度比对象慢。
数组中的元素是可以重复,数组只能按照下标存储

Object  不是迭代器
对象是按照key存储的值,key对应一个唯一的value,key不能重复,对象是一种松散结构
因此没有前后关系,也不能排序,没有顺序,松散结构添加删除速度非常快,查找元素的速度
也是非常快,对象中key不能重复,但是value可以相同,对象必须使用字符串或者symbol
作为key存储。对象没有长度


Set  类似于数组,集合  Set是松散结构,没有key只存储值,没有下标,不能重复,
每个元素唯一,有长度,set也不适用于排序,迭代器
WeakSet 弱类型Set


Map 类似于对象,HashMap,也是key-value键值对,用key来存储value,有长度
key可以是任何类型 map也不适用于排序,迭代器
WeakMap 弱类型Map

4.1 有关set:

var s=new Set([1,2,3,4,2]);
var o={a:1,b:2,c:3,d:4};
var s=new Set(Object.values(o));
console.log(s); //Set(4) {1, 2, 3, 4}


iterable 所有的迭代器都是可以放入
var s=new Set()

s.add(1); //添加
s.add(2);

s.clear(); //清空

s.delete(3); //删除元素

var bool=s.has(2); //has(value)判断是否是成员
console.log(bool) //true

console.log( s.size); //4   //没有length,使用size获取集合元素数量

遍历1
s.forEach((value)=>{
  console.log(value)
    })

遍历2
for(var value of s){
  console.log(value)
    }

4.2 有关map:

1.entries()               //对象转换为迭代器
2.fromEntries();          //将迭代器对象转换为对象

//map的使用方法和使用方式(记)
var m=new Map();          //创建map
console.dir(Object);
[["a",1],["b",2]]         //双重数组  数组就是迭代器

var o=Object.entries();            //对象转换为迭代器
var o=Object.entries({a:1,b:2});   //把对象转换成上面的双重数组
console.log(o)
    
for(var [key,value] of Object.entries({a:1,b:2})){    //这样将他转换为迭代器 然后就可以进行for of 进行遍历
console.log(key,value)
   }

Object.fromEntries([[key,value],[key,value]]);    //将迭代器对象转换为对象
var o=Object.fromEntries([["a",1],["b",2]]);
console.log(o)

var o={a:1,b:2,c:3};
var m=new Map(Object.entries(o));                //将对象转换为迭代器
console.log(m)

// 一个一个的加-对应的数据操作
var m=new Map();
m.set("a",1);
m.set("b",2);
m.set("c",3);
m.clear(); //清空
m.delete("b"); //删除key,就会对应删除数据  delete obj.a

var value=m.get("a"); //表示获取map中key是a的元素   obj["a"];

var bool=m.has("c"); //判断key是否存在
console.log(bool)

console.log(value);
console.log(m);
console.log(m.keys()); //获取到所以key组成的迭代器
console.log(m.values()); //获取所有value组成的迭代器
console.log(m.size); //map是有长度的,对象没有长度

//遍历1 forEach
m.forEach((value,key)=>{         
    console.log(key,value)
})

//遍历2 for of
for(var [key,value] of m){
    console.log(key,value)
    }

//可以独立遍历map中key或者value
for(var key of m.keys()){
    console.log(key)
    }

for(var value of m.values()){
    console.log(value)
    }
//转换成map的迭代器样式-一般来说不直接使用
for(var [key,value] of m.entries()){
    console.log(key,value)
    }

console.log(m.entries()) //map的迭代器样式-一般来说不直接使用

5.认识面向对象

认识面向对象
    + 面向对象是一个开发思想
    + 面向对象: 对面向过程的高度封装
    + 核心: 高内聚, 低耦合

  例子: 吃面条
    + 面向过程
      => 和面: 多少面粉多少水
      => 切面: 多宽多窄
      => 煮面: 多长时间
      => 拌面: 多少酱, 多少面
      => 吃面: 用哪吃
    + 面向对象
      => 找到一个面馆
      => 点一碗面, 点完以后就等着
      => 吃面
    + 换一个思路
      => 当我想吃面条的时候
      => 我要找到一个面馆, 如果有面馆直接用就好
      => 我自己开一个面馆(自己找厨师/...)
      => 点一碗面, 等着面端上来
      => 吃面

  例子: 实现轮播图
    + 面向过程
      => 获取元素(banner/imgBox/pointBox)
      => 准备变量(index/flag/timer)
      => 调用方法
        -> copyEle()
        -> setPoint()
        -> autoPlay()
    + 面向对象
      => 我们自己把所有的过程封装起来(Swiper)
      => 我们自己直接调用使用

  例子: 实现轮播图
    + 面向过程实现第一个
      => 获取元素(banner/imgBox/pointBox)
      => 准备变量(index/flag/timer)
      => 调用方法
        -> copyEle()
        -> setPoint()
        -> autoPlay()
    + 面向过程实现第二个
      => 获取元素(banner2/imgBox2/pointBox2)
      => 准备变量(index2/flag2/timer2)
      => 调用方法
        -> copyEle2()
        -> setPoint2()
        -> autoPlay2()
    + 面向对象实现第一个
      => banner1 = {
          banner: 第一个轮播图的整体范围
          imgBox: 自己的banner内查找承载图片的盒子
          pointBox: 自己的banner内查找承载焦点的盒子
          index: 表示索引
          timer: 定时器返回值
          flag: 开关
          copyEle: 函数(调用的是自己的 banner/ 自己的 imgBox/ 自己的 pointBox)
          setPoint: 函数
          autoPlay: 函数(操作自己的 timer/ 自己的 flag/ 自己的 index)
        }
    + 面向对象实现第二个
      => banner2 = {
          banner: 第二个轮播图的整体范围
          imgBox: 自己的banner内查找承载图片的盒子
          pointBox: 自己的banner内查找承载焦点的盒子
          index: 表示索引
          timer: 定时器返回值
          flag: 开关
          copyEle: 函数(调用的是自己的 banner/ 自己的 imgBox/ 自己的 pointBox)
          setPoint: 函数
          autoPlay: 函数(操作自己的 timer/ 自己的 flag/ 自己的 index)
        }

  总结面向对象学习任务
    => 找到一个能 批量创建对象 的 "机器"(自定义构造函数)
    => "机器" 要求
      -> 批量创建对象
      -> 创建的对象要有属性(非函数对象成员)有方法(函数对象成员)
      -> 创建出来的对象要合理
    => 使用 "机器" 创建对象