date1107this指向、箭头函数、解构赋值、展开运算符、Map和Set、模块化开发

75 阅读11分钟

date1107 this指向、箭头函数、解构赋值、展开运算符、Map和Set、模块化开发

今天所涉及到的知识点有点杂,也有点多,但是咱们应该平静心态,认真学习鸭。

一、this关键字

概念:每一个函数内部都有一个关键字this,this的值只和函数的调用有关,与函数书写无关。

  1. 特点
    • 一个普通函数的全局函数,在正常调用的情况下,this指向的是window;
fun1();
function fun1(){
    console.log(this);
}

运行结果:

01.png

  • 如果将函数放置到对象中,通过对象的语法去获取到并调用函数,那么this指向的是对象;

fun1();
function fun1(){
    console.log(this);
}

const obj = {
    name:'Jack',
    age:18,
    sex:'男',
    fun:fun1,
}
//通过对象取值的方式调用函数
obj.fun()

运行结果: 02.png

  • 如果将函数作为事件处理函数,那么触发的时候,内部的this指向了事件源;
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        div {
            width: 100px;
            height: 100px;
            background-color: pink;
        }
    </style>
</head>

<body>
    <div>我是div</div>
    <script>
    // 运行结果是this指向的是oDiv
    // 点击div标签 打印出div的标签
    fun1();
    function fun1(){
        console.log(this);
    }
    
    var oDiv = document.querySelector('div');
    oDiv.onclick = fun1;
</script>

运行结果: 03.png

  • 如果将函数作为定时器执行时的函数,那么触发的时候,内部的this指向了全部对象window。
    • 注意:将函数放在定时器中,this指向的是window,定时器中这种this指向方式,和直接写window没有任何区别,一般不会使用。
// 运行结果是this指向的是window
fn();
function fn(){
    console.log(this);
}

setTimeout( fn , 1000 );
setInterval(fn , 10000);

二、改变this指向

改变this指向有三种方式,分别是call,apply,bind三种方式来改变this指向,下面详细来说三种的语法和使用区别。

  1. call方法
  • 语法形式:函数名称.call(this指向 , 参数1 , 参数2 , 参数3 , ...);
  • 语法形式和bind差不多。
        // this指向obj
        const obj = {
            a:1,
            b:2,
            c:3,
        }

        function fun(x , y){
            console.log(this , x , y);
        }
        
        fun.call(obj , 300 , 400);
  1. apply方法
  • 语法形式:通过apply(this指向 , 参数1 , 参数2 , 参数3 , ...)修改this指向。
  • 参数需要用方括号给括起来。
        // 运行结果:obj
        const obj = {
            a:1,
            b:2,
            c:3,
        }

        function fun(x , y){
            console.log(this , x , y);
        }
        
        fun.apply(obj , [300 , 400 , 500]);
  1. bind方法
  • 语法形式:通过bind(this指向 , 参数1 , 参数2 , 参数3 , ...)修改this指向。
  • 必须赋值给一个变量返回,返回的是一个新函数。
        //运行结果:obj
        const obj = {
            a:1,
            b:2,
            c:3,
        }

        function fun(x , y){
            console.log(this , x , y);
        }
        
        const newFn = fun.bind(obj , [300 , 400 , 500]);
        console.log(newFn);

三、ES6

ES6其实就是JS发展过程中的某一个版本而已 那个版本的版本号叫做ES6

##微信

  • 在最初的时候 是不具有微信支付的
  • 随着版本的更新 在某一个版本推出了微信支付

##JS

  • 在最初的时候 是只有var 关键词可以声明变量
  • 随着版本的更新 在某一个版本推出了新的变量声明方式

##JS的更新

  • 在推出ES6的时候 这个版本推出的东西比较多
  • 所以后续程序员为了方便记忆 把ES6以后的版本 统称为ES6+

四、let与const

ES6 新增两种变量声明的方式:let和const。 之前我们学的ES5我们只能使用var声明变量,语法 和 var 一样

let 变量名 = 值;const 变量名 = 值

let/const 与var 的差异 1.let/const 声明的变量 不允许出现重复的变量,

使用var 声明变量的时候可以出现重复声明 后赋予的值会覆盖前面的值,let/const 不允许变量重复声明;

2.let/const 声明的变量没有变量提升

也就是不可以提前调用,var声明的变量可以提前调用,打印出的是undefined。

3.let/const声明的变量会受限于所有的{} ,

var关键字声明的局部变量 可以在外部使用 正常打印出值,也就是使用let/const声明的变量是块级作用域 在函数内定义的局部变量不可以在函数外部使用 如果在函数外部使用会报错。

let/const的差异:

1.let声明的叫做变量(后续可以修改内部的值), 2.const声明的变量叫做常量(后就不能修改内部的值)

// 是否可以提前调用
        // var打印undefined let/const报错
        console.log(a);
        console.log(b);
        var a = 1 ;
        var b = 2 ; 
        let a = 1 ;
        let b = 2 ;

        // 局部变量是否可以在函数外部使用
        function fun(){
            var a = 1 ;
            var b = 2 ;
        }
        fun();

        // 是否可以重复定义变量
        // var可以重复定义变量  let/const不可以重复定义变量
        var a = 11 ;
        var a = 22 ;
        let b = 11 ;
        let b = 22 ;
        console.log(a);
        console.log(b);

五、随堂练习

第一种情况:面试题: 对象obj打印的是什么。

        // 打印出:{name: 'Jacks'}
        const obj = { name:'Jack' };
        obj.name = 'Jacks';
        console.log(obj);

第二种情况:面试题: 对象obj打印的是什么。

        // 第二种情况:
        // 打印结果:直接报错
        // const声明的值重新修改的是其中的内存地址 但是const的内存地址不可以被改变
        const obj = { name:'Jack' };
        obj = { name:'Jacks' };
        console.log(obj);

第三种情况:面试题: 对象obj打印的是什么。

        // 第三种情况:
        // 打印结果:{name: 'Jacks'}
        // var声明的变量后面声明的值会覆盖前面声明的值
        var obj = { name:'Jack' };
        obj.name = 'Jacks';
        console.log(obj);

第四种情况:面试题: 对象obj打印的是什么。

        // 面试题二
        // 第一种情况:
        // 打印结果:1s过后5次循环的值为5
        // 前面的几次循环的值都被最终的值给覆盖了 最后var被赋予的值为第五次循环的5
        // var声明的i是一个全局变量
        for(var i = 0 ; i < 5 ; i++){
            setTimeout(function(){
                console.log(i);
            } , 1000)
        }

第五种情况:面试题: 对象obj打印的是什么。

        // 第二种情况:
        // 打印结果:1s过后0 1 2 3 4
        // let声明的值不可以给覆盖 并且在循环5次过后 打印出的值就是5次循环的值
        // let声明的i是一个块级作用域
        for(let i = 0 ; i < 5 ; i++){
            setTimeout(function(){
                console.log(i);
            } , 1000)
        }

六、箭头函数

  1. 概念:箭头函数就是对ES5普通函数写法上的一个优化。
  2. 语法形式:普通写法:(书写形参) => (书写函数调用时执行的代码)
  3. 箭头函数优化:箭头函数如果只有一个形参的时候 可以不写前面小括号

下面就是各种箭头函数的源代码,每一种都很重要,要认真看哦,运行结果可以自己复制代码到编译器运行。

        // 普通函数
        const fun1 = function fun1() {
            console.log(111);
        }
        fun1();


        // 箭头函数
        // 将普通函数转化为箭头函数
        const fun2 = () => {
            console.log(222);
        }
        fun2();


        // 箭头函数的优化
        // 函数体只有一行代码的时候可以不写{}
        const fun3 = () => console.log(333);
        fun3();


        // 只有一个形参时 可以不写前面的小括号
        const fun4 = a => console.log(444);
        fun4();



        // 计算累加和
        const fun5 = function(a , b){
            console.log(a+b);
        }
        fun5(100 , 200);
        const fun6 = (a, b) => a + b;
        console.log(fun6(100, 200));

七、解构赋值

  1. 概念:是ES6新增的获取数组和对象中的每一项值的方法,快速从数组或对象中取出成员的一种语法。
  2. 两种:数组的结构赋值和对象的解构赋值。
// 数组的解构赋值
        const arr = [100 , 200 , 300 , 400];
        // 通过ES5的方式获取每一项值
        let num1 = arr[0];
        let num2 = arr[1];
        let num3 = arr[2];
        let num4 = arr[3];
        console.log(num1 , num2 , num3 , num4);
        // 通过ES6的方式获取数组的每一项值(解构赋值)
        let[num11 , num22 , num33 , num44] = arr;
        console.log(num11 , num22 , num33 , num44);



        // 对象的解构赋值
        // 通过ES5的方式获取每一项值
        const obj = {
            a: 10,
            b: 20,
            c: 30,
        }
        console.log(obj.a , obj.b , obj.c);
        // 通过ES6的方式获取每一项值
        let{a , b , c} = obj;
        console.log(a , b , c);
        console.log(a  , b , c);

八、箭头函数与普通函数的区别

  1. 箭头函数内部没有this 所以他的this取决于书写的时候
  2. 箭头函数内部没有arguments对象,使用的时候尽量不用使用,只有普通函数可以使用 箭头函数内部没有arguments会报错
// 普通函数的this指向window
        function fun1() {console.log(this);}
        fun1();




        // 箭头函数
        // 函数的上一级是window 所以this指向window
        const fun2 = () => {console.log(this);}
        fun2();

        // 普通函数的this指向obj
        const obj = {
            name:'Jack',
            sex:'男',
            age:18,
            city:fun1,
        }
        obj.city();


         // 箭头函数美没有this指向
         const obj2 = {
            name:'Jack',
            sex:'男',
            age:18,
            city:fun2,
        }
        obj.city();

九、展开运算符

  1. 语法形式:...数组(对象);
  2. 作用:展开数组或者对象,相当于把数组两次包裹的中括号去掉。
// 对象的展开运算符
        const obj = {
            a:10,
            b:20,
            c:30,
        }
        // 使用key键名来获取值
        console.log(obj.a , obj.b , obj.c);
        // 不支持这样的写法
        // console.log(...obj);
        // 可以这样写
        const obj1 = {
            ...obj,
            d:40,
            f:50,
        }
        console.log(obj1);




        // 数组的展开运算符
        const arr = [100 , 200 , 300 , 400 , 500];
        const arr1 = [...arr , 600 , 700];
        console.log(...arr);
        console.log(...arr1);



        // 函数的展开运算符
        function fun1(a , b , c , d , e){
            console.log(a , b , c , d , e);
        } 
        fun1(...arr);

十、Map和Set

map和set数据结构

1.set方法
  1. 概念:ES6新推出的两种数据结构,set类似与数组的一种数据结构,内部按照索引排序(但是不能通过索引取值)。

  2. 语法形式:var 变量 = new set([参数1 , 参数2 , 参数3 , ...]);

  3. 特点:

    • 天生不支持重复数据 所以可以利用set来数组去重。
    • set中的size类似于数组中的length。
  4. set的增删查改

    • 新增数据:set数据结构.add(数值);
    • 查询数据:set数据结构.has(数据); 返回布尔值 找到返回true 找不到返回false
    • 删除数据:set数据结构.delete(数据);
    • 清空数据:set数据结构.clear();
  5. 循环遍历set数据结构

    • 语法形式:set数据结构.forEach(item , key , origin){}
        // 设定一个set
        const s = new Set([100 , 200 , 300 , 400 , 500 , 600]);
        console.log(s);

        // set的长度
        console.log(s.size);

        // 打印出其中的值  这样打印输出的是undefined
        // console.log(s[0]);
        // console.log(s[1]);
        // console.log(s[2]);
        // console.log(s[3]);
        // console.log(s[4]);
        // console.log(s[5]);


        // 判断set中是否有这个数据
        console.log(s.has(100));
        console.log(s.has(10000));



        // 向set中新增数据
        // 一次只能新增一个
        // s.add(1000);
        // s.add(1000 , 20000);
        console.log(s);


        // 向set中删除数据
        s.delete(1000);
        console.log(s);


        // set数据清空
        // s.clear();
        // console.log(s);



        // 循环遍历set
        // set中没有键名key 所以key打印出来和item数值一样
        s.forEach(function(item , key , origin){
            console.log(item , key , origin);
        })




        // 利用set对数组去重
        const arr = [1 , 2 , 1 , 2 , 3 , 6 , 2 , 6 , 4 , 8 , 10 , 5];
        console.log([...new Set(arr)]);

2.map方法
  1. 概念:ES6推出的一种数据结构,和set一样,也不支持重复数据,类似于对象的一种数据结构,但是map的key可以是任意类型的值。

  2. 语法形式:var m = new Map([[key , value] , [key , value] , ...]);

    • 输出形式是以箭头函数的形式输出,eg:key => value;
  3. 在实际开发中 我们使用map 的场景想要将对象的key用于字符串之外的数据形式;

  4. map数据结构的增删查改

    • 新增数据:map数据结构.set(key , item); 向当前数据结构中新增数据
    • 获取数据:map数据结构.get(key); 获取指定的key对应的value
    • 查询数据:map数据结构.has(key); 查询数据结构中是否存在当前key 返回布尔值 有就返回true 无就返回false
    • 删除数据:map数据结构.delete(key); 删除当前数据结构对应的key
    • 清空数据:map数据结构.clear(); 清空当前数据结构
  5. 循环遍历map数据结构:

    • 语法形式:map数据结构.forEach(item , key , origin){}
        // map语法
        // 普通对象获取数值
        const obj = {
            a:10,
            b:20,
            c:30,
        }
        console.log(obj);
        console.log(obj.a);
        console.log(obj['a']);

        // map数据结构创建单个
        const m = new Map([['a' , 100] , ['b' , 200]]);
        console.log(m);

        // map数据结构创建多个
        const arr1 = [1 , 2 , 3];
        const arr2 = [4 , 5 , 6];
        const m1 = new Map([[['c' , 300]] , [arr1 , arr2] , ['arr1' , [11 , 21 , 31]] , ['arr2' , [22 , 23 , 24]]]);
        console.log(m1);

        // set增加map数据数值
        m.set('name' , ['q' , 'w' , 'e' , 'r']);
        console.log(m);


        // get获取map数据数值
        console.log(m.get('name'));


        // has查看map中是否有 返回布尔值
        console.log(m.has(100));
        console.log(m.has('a'));


        // delete删除map数值
        m.delete('a');
        console.log(m);


        // clear清空map数值
        console.log(m1);
        m1.clear();
        console.log(m1);


        console.log('');



        // 循环遍历map
        console.log(m);
        m.forEach(function(item , key , origin){
            console.log(item , key , origin);
        })

十一、对象语法的简写

这一块没有什么理论的知识,所以直接上了代码。

        /*
            对象语法的简写
        */

        // 对象的简写
        const obj = {
            name: name,
            sex:'男',
            age:18,
        }
        console.log(obj);

        const obj1 = {
            name,
            sex:'男',
            age:18,
        }
        console.log(obj1);




        // 向对象中添加函数
        const obj3 = {
            name:'Jack',
            sex:'男',
            age:18,
            fun1:function fun1(){
                console.log(111);
            }
        }
        console.log(obj3);

        
        const obj4 = {
            name:'Jack',
            sex:'男',
            age:18,
            fun1:function fun1(){
                console.log(111);
            },
            fun2(){
                console.log(222);
            },
        }
        console.log(obj4);

十二、模块化开发

概念:就是将功能拆分开 每一个功能写道一个JS文件中 (整理出来 积木 一个个的模块)

后续根据实际需求 将不同的JS文件拼接到一起 (按照图纸 将每一个积木拼接一个完整的小汽车或者小房子)

主要是把一些核心的功能拆分出来封装成一个模块 不要分得太细 分得太细维护和操作的时候会很麻烦

将多个逻辑分别写到多个JS文件中 每一个文件都只能使用当前文件内的变量 每一个文件 就是一个独立的作用域(文件作用域)

  1. ES6使用模块化开发的前提:

    • 页面必须使用服务器 以服务器的形式打开
    • script标签行内必须配置type="module" eg:
  2. 如果想要拼接的话 需要导入别的文件到自己的文件内

  3. 前提:导入的文件 必须有导出的内容

  4. 导出:向外部暴露一些内容 可以是变量 可以是函数

  5. 导入:引入别的文件向外部暴露出的那些内容