ES6语法核心基础之函数进阶总结

ES6语法核心基础之函数进阶总结,第1张

目录

1.函数的定义方式

2.函数的调用方式以及this指向

3.改变函数中的this指向

4.严格模式

5.高阶函数

6.闭包

7.递归

8.拷贝


1.函数的定义方式

(1)自定义函数(命名函数)   

    function name(params) {}

(2)函数表达式(匿名函数)

  var fun=function name(params) { }

(3)利用new Function('参数1',"参数2”,函数体)(了解,因为其效率不高)

这种方式其实就是构造函数,Function里面参数必须都是字符串格式

 var f=new Function ('a','b','console.log(a+b)') 
        f(1,2);//3

所有的函数都是Function的实例对象,函数也属于对象

2.函数的调用方式以及this指向

(1)普通函数 this指向window

(2)对象方法 this指向的对象是对象

(3)构造函数 this指向实例对象 原型对象里面的this指向的也是实例对象

 (4)绑定事件函数  this指向函数的调用者 btn这个按钮对象

(5)定时器函数  this指向window

 (6)立即执行函数 this指向window

// 函数的调用方式
        // (1)普通函数 this指向window
        function fn() {
            console.log('普通函数的this'+this);
        }
        fn()  
        fn.call()
        //  (2)对象方法 this指向的对象是o
       var o={
           sayHi:function(){
            console.log('对象方法的this'+this);
           }
       }
       o.sayHi();
         //  (3)构造函数  this指向实例对象 原型对象里面的this指向的也是实例对象
         function Star(){}
         Star.prototype.sing=function(){}
         var ldh=new Star();
        //  (4)绑定事件函数  this指向函数的调用者 btn这个按钮对象
        btn.onclick=function(){}//点击按钮就可以调用这个函数
        //(5)定时器函数  this指向window
        setInterval(function(){},1000)
        // (6)立即执行函数 this指向window
        (function () {
            console.log('立即执行函数的this'+this);
        })()
        // 立即执行函数是自动调用
3.改变函数中的this指向

(1)call()方法

这个方法可以调用对象,简单的理解为调用函数的方式,但是他可以改变函数的this指向

语法:fun.call(thisArg,arg1,arg2,……)

作用一:调用函数,改变函数内部的this指向

作用二:call的主要作用可以实现继承

  // 1.call()
        var o={
            name:'hello'
        }
        function fn(a,b) {
            console.log(this);
            console.log(a+b);
        }
        fn.call(o,1,2)
        // 作用一:调用函数,改变函数内部的this指向
        // 作用二:call的主要作用可以实现继承
        function Father(name,age,sex){
            this.name=name
            this.age=age
            this.sex=sex
        }
        function Son(name,age,sex) {
            // call后面可以指定参数,第一个是指定this所指向的函数,后面是所传入的参数
        /*在调用父构造函数的同时,把父构造函数中的this指向子构造函数中的this,这样子构造函数就可 
          以使用父构造函数中的this*/
            Father.call(this,name,age,sex)
        }
        var son=new Son('张三',18,'男')
        console.log(son);

(2).apply方法

这个方法可以调用一个函数。可以理解为调用函数的方式,它可以改变函数的this指向

语法:fun.apply(thisAry,[argsArray])

thisAry:在fun函数运行是指定的this值

argsArray:传递的值,必需包含在数组里面  

返回值是函数的返回值,因为他就是调用函数

作用:

1.调用函数,第二个可以改变函数内部的this指向,它的第二个参数必须是数组(伪数组)

2.apply的主要应用 比如说可以利用apply借助于数学内置对象求最大值

var o={
            name:'hello'
        };
        function fn(arr){
            console.log(this);//name
            console.log(arr);//'pink'
           
        }
        // 此处的参数2必须为数组
        fn.apply(o,['pink'])
        // 3.apply的主要应用 比如说可以利用apply借助于数学内置对象求最大值
        // Math.max()
        var arr=[12,33,55,3,6,88]
        /*
        下面这个代码在执行的时候调用的是Math.max方法,我们不需要改变this指向,所以第一个参数为null,
        参数二是数组,数组会把数据传递给前面的方法
        但是在js语法规范中,参数一写null可能会不合适,所以说就直接写自己
        */ 
        // var max=Math.max.apply(null,arr)
        var max=Math.max.apply(Math,arr)
        console.log(max);//88

(3)bind方法

如果有的函数我们不需要立即调用,但是又想改变这个函数内部的this指向,此时使用bind,因为call和apply都是会立即调用的。与此同时使用bind可以减少声明的次数,节约内存空间。

该方法不会调用函数,但是能改变函数内部的this指向

语法:fun.bind(thisAry,arg1,arg2)

参数:

thisAry:在fun函数运行是指定的this值

arg1,arg2传递的其他参数

返回值由指定的个this值和初始化参数改造的原函数拷贝

  var o={
            name:'hello'
        }
        function fn(a,b) {
            console.log(this);
            console.log(a+b);
        }
        // 此时bind只是绑定,并没有调用,所以说f需要接收
        // bind改变了this的指向,指向o
        var f=fn.bind(o,1,2);
        // 此时的返回值是原函数改变this之后所产生的新函数,也就是f
        f()

案例

 

但是如果有多个按钮的话,bind作用会更明显

   
    
    
   
三种方法的区别联系
调用函数参数应用场景
call()立即调用任意常用作继承
apply()立即调用数组形式与数组有关,比如借助数学对象实现数组最大值最小值
bind()不会立即调用任意不调用函数,但是想改变this指向,比如改变定时器内部的this指向
4.严格模式

js除了提供正常模式之外,还提供了严格模式,ES5的严格模式是采用具有限制性js变体的一种方式,即在严格的条件下运行js代码。严格模式消除了代码运行的一些不安全之处,保证代码运行安全,提高编译器效率,增加运行速度。严格模式在IE10版本以上才会被支持,就浏览器中容易被忽略

分类:严格模式可以运用到整个脚本或者是个别函数中,所以在使用的时候,可以将严格模式分为为脚本开启严格模式和为函数开启严格模式

(1)为脚本开启严格模式:需要在所有语句之前放一个特定语句 “use strict”(或者‘use strict’)

有的script标签基本是严格模式,有的是正常模式,这样不利于合并文件,所以可以将整个脚本文件放在一个立即执行的匿名函数中,这样独立创建一个作用域而不影响其他的script脚本 

 

 (2)为函数开启严格模式

  

 开启严格模式之后

this的变化

(1)变量名必需先声明再使用

(2)不能随意删除已经声明好的变量

(3)严格模式下全局作用域函数中的this是undefined

(4)严格模式下如果构造函数不加new调用,this会报错

(5)定时器里面的this指向还是window

(6)事件.对象还是指向调用者

函数的变化

(1)严格模式下函数的参数不能重名

(2)函数声明必须在顶层

更多严格模式参考JavaScript 严格模式(use strict) | 菜鸟教程

5.高阶函数

高阶函数是对其它函数进行 *** 作的函数,它接收函数作为参数或者将函数作为返回值输出

 // 高阶函数-函数可以作为参数传递
        function fn(a,b,callback){
            console.log(a+b);
            callback&&callback()
        }
        // 整个过程先执行fn传入参数的函数,再执行回调函数
        fn(1,2,function(){
            console.log('我是最后调用的函数');
            
        })
6.闭包

(1)闭包:指有权访问另一个函数作用域中变量的函数。简单的理解就是一个作用域可以访问另外一个函数内部的局部变量

(2)闭包的产生:被访问的变量所在的函数就是闭包函数

// 闭包的产生:fun这个函数作用域访问了另外一个函数fn里面的局部变量num
        // 被访问的变量所在的函数就是闭包函数,此时fn为闭包函数
        function fn(){
            var num=10;
            function fun() {
                console.log(num);
            }
            fun()
        }
        fn()

(3)闭包的作用:延伸了变量的作用范围

下面这个fn执行之后返回函数fun,将fun赋值给f,f先执行var  然后进入到fun函数中,最后输出。只有当所有的函数执行完毕之后num才会被销毁。return在这当中起了一个非常重要的作用,下面这个就相当于子函数可以使用父函数的的变量。return也是闭包中实现的一个原理

  // fn外面的作用域可以访问fn内部的局部变量
        function fn(){
            var num=10;
            /* function fun() {
                console.log(num);
            }
           return fun; */
           return function fun() {
                console.log(num);
            }
        }
        var f=fn();
        f()//10
        // 上面这一步就相当于下列写法
        /* var f=  function fun() {
                console.log(num);
            } */

(4)闭包应用

// 闭包应用-点击li输出当前li的索引号
        // 1.利用动态添加属性的方式
        var lis=document.querySelector('.nav').querySelectorAll('li')
        for (let i = 0; i < lis.length; i++) {
            lis[i].index=i
            lis[i].onclick=function(){
                // console.log(i);   
               console.log(this.index);
           };  
        }
        // 2.利用闭包的方式得到当前小li的索引号
         for(var i=0;i
// 闭包应用-计算打车价格
        // 打车起步价13(3公里内),之后每多一公里增加5块钱,用户输入公里数就可以计算打车价格
        // 如果有拥堵情况,总价格多收取10块钱拥堵费
        // function fn(){}
        // fn()
       var car=(function(){
             var start=13//起步价
             var total=0//总价
             return{
                 //正常的总价
                 price:function(n){
                  if(n<=3){
                    total=start
                  }else{
                    total=start+(n-3)*5
                  }
                  return total;
                 },
                 //拥堵之后的费用
                 yd:function(flag){
                   return flag?total+10:total
                 } 
             }
         })()
         console.log(car.price(5));//23
         console.log(car.yd(true));//33
         console.log(car.price(1));//13
         console.log(car.yd(false));//23
7.递归

如果一个函数在内部可以去调用其本身,那么这个函数就是递归函数。

简单理解:函数内部自己调用自己,这个函数就是递归函数

递归函数的作用和循环效果一样,由于递归很容易发生‘栈溢出’错误,所以必须要加退出条件return

 // 递归函数:函数内部自己调用自己,这个函数就是递归函数
        var num=1
        function fn(){
            console.log('我要打印六句话');
            if(num==6){
                return;//递归里面必须加退出条件
            }
            num++
          fn()
         
        }
        fn()

利用递归求阶乘1*2*3*4*....n

  // 利用递归求1~n的阶乘 1*2*3*4....n
        function fn(n) {
            if(n==1){
                return 1
            }
            return n*fn(n-1)
        }
       console.log(fn(3)); //6
    //    详细思路 加入用户输入的是3,每次调用fn保留前面的n
    // return 3*fn(2)
    // return 3*(2*fn(1))
    // return 3*(2*1)
    // return 3*(2)
    // return 6

 利用递归函数求斐波那契数列(兔子数列)1 1 2 3 5 8....

// 利用递归函数求斐波那契数列(兔子数列)1 1 2 3 5 8....
        // 用户输入一个数字n就可以求i出这个数字对应的兔子序列值
        // 只需要知道用户输入的第n项的前面两项(n-1)(n-2)就可以计算出n对应的序列值
        function fn(n) {
            if (n===1||n===2) {
                return 1;
            }
            return fn(n-1)+fn(n-2)
        }
        console.log(fn(6));//8

利用递归遍历数据 

遍历外层数据使用第一个if,遍历第二层数据符合条件的来到第二层,然后再一次调用getID,返回之后再一次执行第一个if

 var data=[{
            id:1,
            name:'家电',
            goods:[{
                id:11,
                gname:'冰箱',
                goods:[{
                    id:111,
                    gname:'hair'
                },
                {
                    id:112,
                    gname:'美的'
                }
            ]
            },{
                id:12,
                gname:'洗衣机'
            }]
        },{
            id:2,
            name:'服饰'
        }]
        // 我们想要输入id号,就可以返回的相应的数据对象
        //1.利用forEach去遍历里面的每一个对象
        function getID(json,id){
            var o={}
           json.forEach(function(item){
            //    console.log(item);//2个数组元素
               if(item.id==id){
                // console.log(item)
                o=item
                // 2.想要得到最里面的数据 11 12可以利用递归函数
                // 里面应该有goods数组并且数组不是空的
               }else if(item.goods&&item.goods.length>0){
                  o= getID(item.goods,id)
               }
           });
           return o;
        }
       console.log(getID(data,1)) 
       console.log(getID(data,2)) 
       console.log(getID(data,11)) 
       console.log(getID(data,22)) 
       console.log(getID(data,111)) 
8.拷贝

(1)浅拷贝

浅拷贝只是拷贝一层,更深层次的对象级别的只拷贝引用(地址)

ES6中新增的语法:Obj.assign(target,..source) 可以用于浅拷贝

参数一:指的是拷贝之后的对象

参数二:被拷贝者,

  // 浅拷贝只是拷贝一层,对于深层次的对象级别的只拷贝引用
        var obj={
            isd:1,
            name:'tony',
            msg:{
                age:18
            }
        }
        var o={};
        /* 
        //方法一
        for(var k in obj){
            //k 是属性名  obj[k]属性值
            o[k]=obj[k]//o[k]相当于o.k   
        }
        console.log(o);
        // 拷贝之后的o与原来的obj指向的是同一个地址
        // 浅拷贝把更深层次对象的地址拷贝给了o,当修改了age时,原来obj里面的age也会被修改。
        o.msg.age=20
        console.log(obj); */
        
        //方法二
        // 在ES6中可以利用Obj.assign(target,..source) 拷贝
        Object.assign(o,obj);

(2)深拷贝

深拷贝拷贝多层,每一级别的数据都会拷贝。深拷贝会新开辟一个容纳数据的空间,也就是复制原来的空间,然后在新空间上修改数据的时候就不会影响原来空间里面的数据。

深拷贝也利用了递归原理

  // 浅拷贝只是拷贝一层,对于深层次的对象级别的只拷贝引用
        var obj={
            isd:1,
            name:'tony',
            msg:{
                age:18
            },
            color:['pink','red']
        }
        var o={};
    // 封装函数
    function deepCopy(newobj,oldobj) {
        for (var k in obj){
        // 要判断属性值的数据类型 
        // 判断数据类型要将数组放在对象前面,因为数组也是对象,如果放在后面就会判断不准确
        // 1.获取属性值 oldobj[k]
        var item=oldobj[k]
        // 2.判断这个值是否为数组
        if(item instanceof Array){
            newobj[k]=[]//这就相当于这个数组为o.color=[]
            // 这个函数就是把值给属性,item是值,newobj[i]为属性
            deepCopy(newobj[k],item)
        }else if(item instanceof Object){
            // 3.判断这个值是否为对象
            newobj[k]={}
            deepCopy(newobj[k],item)
        }else{
           // 4.属于简单数据类型
           newobj[k]=item
        }
        }
    }
    deepCopy(o,obj)
    console.log(o);

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1296945.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-10
下一篇 2022-06-10

发表评论

登录后才能评论

评论列表(0条)