箭头函数 改变this指向

1.箭头函数

<div>我是div</div>
    <script>
      
        const oDiv = document.querySelector('div');

        // 普通函数
        oDiv.addEventListener('click' , function(){ 
             console.log('我是div标签')
         })

        // 箭头函数
         oDiv.addEventListener('click' , ()=>{ 
             console.log('我是div标签');
         })

        // 只有一个参数,可以不写(),直接定义一个参数
         oDiv.addEventListener('click' , e=>{ 
             console.log(e);
         })
 
        // 只有一行代码,不写{}
        oDiv.addEventListener('click' , e=>console.log(e) )
        //click { target: div, buttons: 0, clientX: 47, clientY: 20, layerX: 47, layerY: 20 } 
    </script>

2. 箭头函数中的this指向

箭头函数中的this指向
为什么要有箭头函数?
是为了配合面向对象和构造函数
在箭头函数中,this指向有特殊的意义,专门可以用来配合构造函数和面向对象编程思想

在箭头函数中,this指向,父级程序的this指向
如果父级程序有this指向,那么箭头函数指向的就是父级程序的this
如果父级程序没有this指向,那么指向的就是window

<body>
    <div>1234</div>
    <ul>
        <li>1</li>
        <li>2</li>
        <li>3</li>
        <li>4</li>
        <li>5</li>
    </ul>
    <script> 
        // 复习this指向 
        // 普通函数的this指向
        // 声明式,赋值式/匿名函数,对象中函数,绑定的事件处理函数
        // this都是指向的调用函数时,之前定义的内容

        // 1,声明式 --- 指向的是window
         function fun1(){ 
             console.log(this);	//Window 
         }
 		 fun1();

        // 2,匿名函数/赋值式 --- 指向的是window
         const fun2 = function(){ 
             console.log(this);	//Window 
         }
         fun2();

        // 3,定义在对象中的函数 --- 指向的是对象
         const obj = {  
             fun3 : function(){ 
                 console.log(this);	//Object { fun3: fun3() }
             }
         }
         obj.fun3();

        // 4,绑定的事件处理函数 --- 指向的是绑定事件处理函数的标签
        const oDiv = document.querySelector('div');
        oDiv.onclick = function(){ 
            console.log(this);	//<div>
        }

        oDiv.addEventListener('click' , function(){ 
            console.log(this);	//<div>
        })

        // 箭头函数的tihs指向
        // 与普通函数的this指向是有区别的
        // 箭头函数中,this的指向是父级程序的this指向
        // 当前的程序,箭头函数的父级程序,没有
        // this指向的就是window

        oDiv.addEventListener('click' , ()=>{ 
            console.log(this);	//window
        })

        // 对li进行操作
        const oLis = document.querySelectorAll('li');
        oLis.forEach(function(item,key){ 
             console.log(this);  // 输出的是forEach的函数的this指向
            // 箭头函数的this,是父级程序,forEach()的this,是window
            item.addEventListener('click' , ()=>{ 
                 console.log(key,this);//0--4 window
            })
        })
 
        // forEach()中 函数的this指向,就是window
         const arr = [1,2,3,4,5,6];
         arr.forEach(function(){ 
             console.log(this);	//window
         })

        const obj = { 
            // 普通函数,this指向对象
            fun1 : function(){ console.log(this)},
            // 箭头函数this指向是,父级程序
            // 父级程序是对象
            // 只有函数有this,obj对象没有this
            // 父级程序没有this,指向的是window
            fun2 : ()=>{ console.log(this)},
 
            // fun3是一个普通函数,this指向的是obj对象
            fun3 : function(){ 
                // fun4,是一个箭头函数,this指向的是父级程序的this指向
                // 父级程序是fun3,fun3的this是对象,fun4箭头函数的this也是对象
                const fun4 = ()=>{ console.log(this)};
                fun4();
            }
        }
        obj.fun1();	//Object { fun1: fun1(), fun2: fun2(), fun3: fun3() }
        obj.fun2();	//Window 
        obj.fun3();	//Object { fun1: fun1(), fun2: fun2(), fun3: fun3() }
   </script>

关于this的总结

  1. 普通的function函数
    声明式 — window
    赋值式 — window
    forEach循环 — window
    定时器,延时器 — window
    对象中的函数 — 对象本身
    事件绑定事件处理函数 — 绑定事件的标签
  2. 箭头函数的this指向
    父级程序的this指向
    如果父级程序有this指向(父级程序也是函数),this指向的就是父级程序的this指向
    如果父级程序没有this指向(数组,对象…),this指向的是window

3.改变this指向

重点:箭头函数,不能改变this指向,只有普通function函数,能改变this指向

改变this指向的方法

1. call()方法

语法: 函数.call(参数1,其他参数…可以是多个或者没有 )
作用: 调用并且执行函数,同时,将函数的this指向,定义为指定的内容(参数1)
参数1,是改变的this的指向
其他参数,是原始函数的实参,原始函数有几个形参,此时就要对应的输入几个实参,没有形参,就没有实参

2. apply()方法

语法: 函数.apply(参数1,参数2) 只有两个参数
参数1:改变的this的指向内容
参数2:原始函数的实参,必须是一个数组的形式,将实参定义成数组的单元
其他用法和作用于 .call是相同的

总结: call方法与apply方法,作用,效果,都是完全一致的
只是对于原始函数的参数赋值方法,不同
call方法是通过其他多个参数来实现
apply方法是通过一个数组参数,来实现
两个方法没有本质的区别,爱用哪个用那个

3. bind()方法

语法: const 变量 = 函数.bind(参数1);
不是立即执行函数
生成一个新的函数,这个新的函数是改变this指向之后的新的函数
参数1,定义的要改变的的this指向
其他参数,一般不定义,是使用函数原有的形参

总结:

call apply 都是立即执行函数
参数1,都是改变的this指向
其他参数,是原始函数的形参(可以有,也可以没有)
bind 不是立即执行函数,是生成一个新的函数
参数1,是改变的this指向
就使用原始函数的形参

        const obj1 = { 
            name:'张三',
            age:18,
            sex:'男',
        }

        const obj2 = { 
            name:'李四',
            fun2 : function(){ 
                console.log(this);
            }
        }
        // 对象中的函数,this指向的是这个对象,obj2
        obj2.fun2();	//Object { name: "李四", fun2: fun2() }
        // 改变this指向,指向的是obj1这个对象
        // 代用,并且执行fun2这个函数,同时将fun2的this指向,从原始的obj2,改变为obj1
         obj2.fun2.call(obj1);	//Object { name: "张三", age: 18, sex: "男" }

        // 带有参数的函数,this指向的改变

        // 定义的带有参数的普通函数
        function fun3(name,age,sex){ 
            console.log(name,age,sex,this);
        }
        // 执行时,输出实参,此时this指向是window
        fun3('张三',18,'男');	//张三 18 男 window

        // 改变this指向 , call方法
fun3.call(obj1,'李四',20,'女');	//李四 20 女 Object { name: "张三", age: 18, sex: "男" }

        // 改变this指向 , apply方法
fun3.apply(obj1 , [ '王五' , 20 , '不知道' ])	//王五 20 不知道 Object { name: "张三", age: 18, sex: "男" }

        // bind方法,不是立即执行函数,而是定义生成一个新的函数
        // 新生成的函数,this指向是参数1
        // 新生成的函数,形参是原始函数fun3的形参
        const fun4 = fun3.bind(obj1);

fun4('王二麻子' , 100 , '不详');	//王二麻子 100 不详 Object { name: "张三", age: 18, sex: "男" }

4. 立即执行函数

立即执行函数
在定义函数的同时,立即执行这个函数
语法:
( 封装的函数 ) ( )
! 封装的函数 ( )
~ 封装的函数 ( )
这三种语法没有区别,爱用哪个用那个
立即执行定义的函数,不是真正的在定义声明函数
立即执行之后,无法再次被正常的调用
具体使用方法,要到闭包的时候使用

        // 定义函数
        function fun(){ console.log(123)}
        // 调用函数
        fun(); 
        // 立即执行,在定义的同时,立即执行函数
        ( function fun1(){ console.log(123)} )()
        // 立即执行函数,并没有真正的定义真个函数
        // 没有办法正常的再次调用这个函数
        // fun1();

        !function fun1(){ console.log(123)}()
        ~function fun1(){ console.log(123)}()

5. 解构数组语法

数组的解构语法
就是数组的另一种使用调用方法
可以不通过 [ ]语法,不通过索引下标,来调用使用数组中的数据
用于将数组中的数据,一一对应的赋值给变量

        const arr = ['北京','上海','广州','重庆','天津'];
        // 之前使用数组的数据,必须通过[]语法和索引下标
        // let str1 = arr[0];
        // let str2 = arr[1];
        // let str3 = arr[2];
        // let str4 = arr[3];
        // let str5 = arr[4];

        // 将 arr 中的数据,调用出来,给 左侧内容进行一一对应的赋值
        let [str1,str2,str3,str4,str5] = arr;
        console.log(str1,str2,str3,str4,str5);

        // 结构多层的数组
        // 二维数组
        const arr2 = ['北京','上海',['a','b','c']];
        // s1对应北京,s2,对应上海,s3,对应['a','b','c']
        // let [s1,s2,s3] = arr2
        // 接续把 s3 对应的数组 ['a','b','c'] 解析
        // s1对应北京,s2对应上海,[]对应['a','b','c']
        // s3对应a s4对应b s5对应c
        let [s1,s2,[s3,s4,s5]] = arr2
        console.log(s1,s2,s3,s4,s5);

6. 对象的解构

对象的解构
之前对象数据的调用,通过.语法或者[]语法,配合属性来调用操作数据
现在可以使用解构语法来调用操作数据

        const obj = { 
            name:'张三',
            age:18,
            sex:'男',
            addr:'北京',
            phone:123456,
        }

        // 之前调用数据
        // let str1 = obj.name;
        // 解构语法
        // 将对象中,属性是name的属性值,调用,赋值给name变量名称
        // {}中定义的属性,一定是对象中具有的属性
        // 变量名称,就是name也就是属性名称
        // let {name} = obj;
        // console.log(name);

        // 解构语法之定义其他名称
        // 在对象obj中,找name属性,将对应的数值数据,赋值给变量别名userName
        // 通过userName来调用使用数据
        // 只能一次解构一个数据,不能一次性的做一一对应的赋值
        // let {phone:userName} = obj;
        // console.log(userName);

        // 多级对象的解构
        const obj2 = { 
            name1:{ 
                name2:'张三'
            }
        }

        // let {name1 : {name2}} = obj2;
        let { name1 : { name2:userName}} = obj2;
        console.log(userName); 
        // 只有name2解构对应张三,name1没有内容
        // console.log(name1); 
        // 如果只是 let {name1} = obj2
        // name1存储的是 对象 {name2:'张三'}

7. 展开运算符

展开运算符
…数组
将数组中的数据,展开来使用
在函数的实参中使用

        // 有多个形参
        function fun(num1,num2,num3,num4,num5){ 
            console.log(num1,num2,num3,num4,num5)
        }
        // 执行时就要输入多个实参
        fun(100,200,300,400,500);

        // 现在有一个数组,存储多个数据
        const arr = [1,2,3,4,5];
        fun(arr[0],arr[1],arr[2],arr[3],arr[4]);
        // 展开运算符,将数组中的数据展开使用
        // 将arr中的数据,展开,对形参进行一一对应的赋值
        // 通过数组,给多个形参赋值更简单
        fun(...arr);

8. 合并运算符

合并运算符

在函数的形参中使用
作用:将赋值的所有的实参,都是以数组的形式,存储在形参中

       // 只有一个形参,形参只能存储一个实参 
       function fun(arr){ 
           console.log(arr);
       }
       // 即时输入多个参数,只有一个形参,也只能存储第一个实参
       fun('a','b','c','d');

       // 合并运算符
       // 不管实参有几个,都以数组的形式,存储在形参中
       function fun1(...arr){ 
           console.log(arr);
           // 调用存储在形参arr中的实参,必须用过[]语法,索引下标
           // 或者 循环遍历 获取
       }
       // 输入的所有的实参,都会以数组的数据的形式,存储在形参arr中
       fun1('a','b','c','d','e',1,2,3,4,5);

       // 在 普通函数中,JavaScript定义了一个专门的变量,叫 arguments
       // 如果你没有定义形参,所有的实参都会以数组的形式存储在这个变量中
       // 作用于合并运算符相同
       // 但是 箭头函数中 没有 arguments 这个变量
       // 必须使用 ...形参 合并运算符的形式 来存储实参

       // 没有形参,JavaScript自动在arguments中,以数组的形式存储实参
       function fun3(){ 
           console.log(arguments);
       }

       fun3(1,2,3,4,5,6,7);
       // 箭头函数没有arguments,会报错
       // 只能使用 合并运算符 ...形参
       // const fun4 = ()=>{ 
       // console.log(arguments);
       // }

       // fun4(1,2,3,4,5);

       const fun5 = (...arr)=>{ 
           console.log(arr);
       }

       fun5(1,2,3,4,5);
    原文作者:珎珎啊
    原文地址: https://blog.csdn.net/qq_43363773/article/details/105420111
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞