博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
JS进阶(三)(函数进阶,apply,闭包...等)
阅读量:7025 次
发布时间:2019-06-28

本文共 7074 字,大约阅读时间需要 23 分钟。

--------------记录自JS高级视频中的学习笔记包括了函数进阶,apply,call,bind方法的使用,闭包,递归,浅拷贝与深拷贝,沙箱.

函数进阶

  • 创建函数的两种方式:
    • 函数声明:
      function f1(){    console.log("函数声明");}f1();复制代码
      • 函数声明如果放在if-else语句中,在IE8中会出错(函数声明会被提升)
    • 函数表达式:
      var f2 = function(){    console.log("函数表达式");};f2(); 复制代码
      • 使用函数表达式更好
  • 函数中的this指向
    • 普通模式
      • 普通函数中的this---window
      • 定时器中的this---window
      • 构造函数中的this---实例对象
      • 对象.方法中的this---当前的实例对象
      • 原型方法中的this---实例对象
    • 严格模式: "use strict"
      • 普通函数中的this得在window.函数();调用的时候才是window,若函数();则为undefined
  • 函数的不同的调用方式
    • 普通函数:
      function f1(){}f1();复制代码
    • 构造函数---通过new来调用,创建对象
      function F1(){}var f = new F1();复制代码
    • 对象的方法
      function F1(){    this.f1 = function(){};}var f = new F1();f.f1(); 复制代码
  • 函数也是对象,对象不一定是函数
    • 对象中有__proto__原型,是对象
    • 函数中有prototype原型,是对象
    • 若一个东西里有prototype,又有__proto__,说明是函数也是对象;(Math对象中有__proto__但没有prototype)
    • 所有的函数实际上都是Function的构造函数创建出来的实例对象
  • 函数中的几个成员介绍
    • name属性: 函数的名字,name的属性是只读的,不能修改
    • arguments属性: 实参的个数
    • length属性: 函数定义的时候形参的个数
    • caller属性: 调用者(例如f1函数在f2函数中调用的,此时的调用者就是f2)
  • 函数可以作为参数使用
    • 函数作为参数的时候,如果是命名函数,那么只传入命名函数的名字,没有括号
    • 练习:
    var arr = [1, 100, 20, 200, 40, 50, 120, 10];    //排序---函数作为参数使用,匿名函数作为sort方法的参数使用,那么此时的匿名函数中有两个参数,    arr.sort(function (obj1,obj2) {      if(obj1>obj2){        return -1;      }else if(obj1==obj2){        return 0;      }else{        return 1;      }    });//从小到大排序复制代码
  • 判断数据类型
    • typeof: 返回一个字符串,表示未经计算的操作数的类型
    • 对象 instanceof Object: 返回布尔类型,判断对象是否为某个类型
    • Object.prototype.toString(): 返回Object的数据类型([object Object])
    • Object.prototype.toString().call(对象): 返回的是该对象的数据类型
    • 获取某个对象的类型是不是传入的类型
    //获取某个对象的类型是不是你传入的类型    //[10,20,30] 是不是"[object Array]"    //type---是变量----是参数----"[object Array]"    //obj---是变量-----是参数----[10,20,30];    //判断这个对象和传入的类型是不是同一个类型    function getFunc(type) {      return function (obj) {        return Object.prototype.toString.call(obj) === type;      }    }    var ff = getFunc("[object Array]");    var result = ff([10, 20, 30]);    console.log(result);//true    var ff1 = getFunc("[object Object]");    var dt = new Date();    var result1 = ff1(dt);    console.log(result1);//false复制代码

apply,call与bind的使用

apply,call
  • 作用: 都可以改变this的指向
    function f1(x,y){        console.log((x + y) + ":===>" + this);    }    //apply 和 call调用    f1.apply(null,[1,2]);//3:===>[object Window]    f1.call(null,1,2);//3:===>[object Window]    //改变this的指向    var obj = {        };    f1.apply(obj,[1,2]);//3:===>[object Object]    f1.call(obj,1,2);//3:===>[object Object]复制代码
  • apply的使用语法
    • 函数名字.apply(对象,[参数1,参数2,...]);
    • 方法名字.apply(对象,[参数1,参数2,...]);
  • call的使用语法
    • 函数名字.call(对象,参数1,参数2,...);
    • 方法名字.call(对象,参数1,参数2,...);
  • 不同的地方 : 参数传递的方式不一样
  • 只要是想使用别的对象的方法,并且希望这个方法是当前对象的,那么就可以使用apply或者是call的方法改变this的指向
  • apply和call方法实际上并不在函数这个实例对象中,而是在Function的prototype中
bind方法
  • bing方法是复制的意思,参数可以在复制的时候传进去,也可以在复制之后调用的时候传入进去
    function A(age){        this.age = age;    }    A.prototype.a = function(){        console.log(this + "===>" + this.age);    }    function B(age){        this.age = age;    }    var aObj = new A(10);    var bObj = new B(20);    //复制了一份    var c = aObj.a.bind(bObj);    c();//[object Object]===>20复制代码
    • 使用语法:
      • 函数名字.bind(对象,参数1,参数2,...)--->返回值是复制之后的这个函数
      • 方法名字.bind(对象,参数1,参数2,...)--->返回值是复制之后的这个方法
    • 应用实例
      function ShowRandom(){        //1-10的随机数        this.number = parseInt(Math.random()*10 + 1);    }    //添加原型方法    ShowRandom.prototype.show1 = function(){        //改变了定时器中的this的指向了,本来应该是window,现在为实例对象        window.setInterval(this.show2.bind(this),1000);    };    //添加原型方法    ShowRandom.prototype.show2 = function(){        //显示随机数--        console.log(this.number);    };    //实例对象    var sr = new ShowRandom();    //调用方法,输出随机数字    //调用这个方法一次,可以不停的产生随机数字    sr.show1();复制代码
作用域和作用域链及预解析
  • 变量--->局部变量和全局变量
    • 局部变量是在函数中,函数使用结束后,局部变量就会被自动的释放,闭包后,里面的局部变量的使用作用域链被自动的延长
  • 作用域:就是变量的作用范围--->局部作用域和全局作用域
    • js中没有块级作用域--一对括号中定义的变量,这个变量可以在大括号外面使用,函数中定义的变量是局部变量
  • 作用域链:变量的使用,从里向外,层层的搜索,搜索到了就可以直接使用了
    • 层层搜索,搜索到0级作用域的时候,如果还是没有找到这个变量,结果就是报错
  • 预解析:就是在浏览器解析代码之前,把变量的声明和函数的声明提前(提升)到该作用域的顶部(函数声明优先于变量声明)
闭包
  • 闭包的概念:函数A中,有一个函数B,函数B中可以访问函数A中定
    • 模式:函数模式的闭包,对象模式的闭包
    • 作用:缓存数据,延长作用域链
    • 优点和缺点:缓存数据(没有及时的释放 )
    • 应用:
      //函数模式的闭包    function f1(){        var num = 10;        //函数的声明        function f2(){            console.log(num);        }        //函数调用        f2();    }    f1();//10            //对象模式的闭包:函数中有一个对象    function f3(){        var num = 10;        var obj = {            age : num         }        console.log(obj.age);//10    }复制代码
    • 案例:产生三个相同的随机数
      function f1(){        var num = parseInt(Math.random()*10 + 1);        return function (){            console.log(num);        }    }        var ff = f1();    ff();//3(随机的)    ff();//3    ff();//3复制代码
    • 总结:如果想要缓存数据,就把这个数据放在外层的函数和里层的函数的中间位

沙箱

  • 沙箱: 环境,黑盒,在一个虚拟的环境中模拟真实世界,做实验,实验结果和真实世界的结果是一样的,但是不会影响真实世界
  • 沙箱--小环境
    (function (){        var num = 10;        console.log(num + 10);    }());复制代码
  • 小案例
    (function (){        var str = "小白喜欢小黑";        str = str.substr(2);        console.log(str);//喜欢小黑    }());        (function (){        var str = "小明喜欢小红";        str = str.substr(2);        console.log(str);//喜欢小红    }());复制代码
  • 总结:放在沙箱内(自调用函数)可以避免全局变量冲突,不会污染外部环境

递归

  • 递归: 函数中调用函数自己,此时就是递归,递归一定要有结束的条件,一般应用在遍历上,递归轻易不要用,效率很低
  • 案例: 求n个数字的累加和
    //递归实现:求n个数字的和    //函数的声明    function getSum(x){        if(x==1){            return 1;        }        return x + getSum(x - 1);     }    //函数的调用    console.log(getSum(5));//15    /*    *    * 执行过程:    * 代码执行getSum(5)--->进入函数,此时的x是5,执行的是5+getSum(4),此时代码等待    * 此时5+getSum(4),代码先不进行计算,先执行getSum(4),进入函数,执行的是4+getSum(3),等待, 先执行的是getSum(3),进入函数,执行3+getSum(2),等待,先执行getSum(2),进入函数,执行 2+getSum(1);等待, 先执行getSum(1),执行的是x==1的判断,return 1,所以,    * 此时getSum(1)的结果是1,开始向外走出去    * 2+getSum(1) 此时的结果是:2+1    * 执行:    * getSum(2)---->2+1    * 3+getSum(2) 此时的结果是3+2+1    * 4+getSum(3) 此时的结果是4+3+2+1    * 5+getSum(4) 此时的结果是5+4+3+2+1    *    * 结果:15    *    *    *    * */复制代码
  • 案例: 求一个数字各个位数上的数字的和: 123 --->6
    function getEverySum(x){        if(x<10){            return x;        }        //获取的是这个数的个位数        return x%10 + getEverySum(parseInt(x/10));    }    console.log(getEverySum(1364));//14复制代码
  • 案例: 求斐波那契数列(第三个数等于前两个数之和 第一第二个数为1)
    function getFib(x){        if(x==1 || x==2){            return 1;        }        return getFib(x-1) + getFib(x-2);    }    console.log(getFib(12));//144复制代码

浅拷贝和深拷贝

  • 浅拷贝: 拷贝结束复制,就相当于把一个对象中的所有的内容,复制一份给另一个对象,直接复制,或者说,就是把一个对象的地址给了另一个对象,他们指向相同,两个对象之间有共同的属性或者方法,都可以使用
    //作用:把一个对象的属性复制到另一个对象中,浅拷贝    //把a对象中的所有的属性复制到对象b中    function extend(a,b){        for(var key in a){            b[key] = a[key];        }    }复制代码
  • 深拷贝: 拷贝函数复制,深: 把一个对象中的所有属性或者方法,一个一个的找到,并且在另一个对象中开辟相应的空间,一个个的存储到另一个对象中
    //通过函数实现,把对象a中所有的数据深拷贝到对象b中    function extend(a,b){        for(var key in a){            //先获取a对象中每个属性的值            var item = a[key];            //判断这个值是不是数组            if(item instanceof Array){                //如果是数组,那么在b对象中添加一个新的属性,并且这个属性值也是数组                b[key] = [];                //调用这个方法,把a对象中的这个数组的属性值一个个的复制到b对象的这个数组属性中                extend(item,b[key]);            }else if(item instanceof Object){//判断在这个值是不是对象类型的           //如果是对象类型的,那么在b对象中添加一个属性,是一个空对象           b[key] = {};           //再次调用这个函数,把a对象中的属性对象的值一个一个复制到b对象的这个属性对象中           extend(item,b[key]);            }else{                //如果值是普通的数据,直接复制到b对象整过属性中                b[key] = item;            }        }    }复制代码

转载地址:http://knmxl.baihongyu.com/

你可能感兴趣的文章
使用PowerPivot建立简单的分析模型
查看>>
C# Java DES加密解密
查看>>
2011-09-21 16:53 VS2010、C#、Emgu CV配置 ; 在C#下使用OpenCV ; C#中使用OpenCV(Emgu CV);...
查看>>
mysql索引测试案例
查看>>
从topcoder赚钱的方法~
查看>>
会计电算化模拟试题9
查看>>
一名大学生在银行工作8年的职场感悟
查看>>
阻带窗函数[数字信号处理]使用窗函数设计FIR滤波器
查看>>
客户端生成nginx webdav配置
查看>>
接外包私活成功之道(一)-注重服务意识,挖掘深层需求
查看>>
GSM-串口和GPRS-网口通信
查看>>
技术人生:向前端人员学习
查看>>
【产品经理】产品经理的十大顶级错误
查看>>
“AIR SDK 0.0: AIR SDK location “...\devsdks\AIRSDK\Win” does not exist.”问题解决~
查看>>
识别Andriod APK签名证书类型
查看>>
获取CentOS软件源中的updates包
查看>>
git使用说明
查看>>
HTML5 Canvas实现黑客帝国文字掉落效果
查看>>
web 缓存
查看>>
【cocos2d-x 手游研发----怪物智能AI】
查看>>