JavaScript学习记录十七

apply和call方法的使用

    //apply和call的使用
    //作用:可以改变this的指向

    //apply和call方法中如果没有传入参数,或者是传入的是null,那么调用该方法的函数对象中的this就是默认的window

    *JavaScript中存在继承,通过调用apply或call传过去的第一个参数来动态指定方法中的 this .

    function f1(x,y) {
      console.log("结果是:"+(x+y)+this);
      return "10000";
    }
    f1.apply();
    f1.call();

    f1.apply(null);
    f1.call(null);

apply和call都可以让函数或者方法来调用,传入参数和函数自己调用的写法不一样,但是效果是一样的
    f1.apply(null,[100,200]);
    f1.call(null,100,200);

apply和call的使用方法
    /*
    * apply的使用语法
    * 函数名字.apply(对象,[参数1,参数2,...]);
    * 方法名字.apply(对象,[参数1,参数2,...]);
    * call的使用语法
    * 函数名字.call(对象,参数1,参数2,...);
    * 方法名字.call(对象,参数1,参数2,...);
    *
    * 作用:改变this的指向
    * 不同的地方:参数传递的方式是不一样的

    * 只要是想使用别的对象的方法,并且希望这个方法是当前对象的,那么就可以使用apply或者是call的方法改变this的指向

        function f1() {
            console.log(this+":====>调用了");
        }
        f1是函数,f1也是对象,因为f1中有 __proto__和prototype
        console.dir(f1);
        对象调用方法,说明,该对象中有这个方法
        f1.apply();
        f1.call();
        console.log(f1.__proto__==Function.prototype);
        所有的函数都是Function的实例对象
        console.log(Function.prototype);//ƒ () { [native code] }
        console.dir(Function);
        apply和call方法实际上并不在函数这个实例对象中,而是在Function的prototype中
bind是用来复制一份
//使用的语法:
/*理解:将改变this后的函数状态复制了一份。函数调用之后内部this使用的是指定后的
* 函数名字.bind(对象,参数1,参数2,...);---->返回值是复制之后的这个函数
* 方法名字.bind(对象,参数1,参数2,...);---->返回值是复制之后的这个方法
    function Person(age) {
      this.age=age;
    }
    Person.prototype.play=function () {
      console.log(this+"====>"+this.age);
    };

    function Student(age) {
      this.age=age;
    }
    var per=new Person(10);
    var stu=new Student(20);
    //复制了一份
    var ff=per.play.bind(stu);
    ff();  [object Object]====>20

bind方法的使用

  <script>
    通过对象,调用方法,产生随机数
    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();
  </script>

函数中的几个成员

    //函数中有一个name属性----->函数的名字,name属性是只读的,不能修改
    //函数中有一个arguments属性--->实参的个数
    //函数中有一个length属性---->函数定义的时候形参的个数
    //函数中有一个caller属性---->调用(f1函数在f2函数中调用的,所以,此时调用者就是f2)

    function f1(x,y) {
      console.log(f1.name);
      console.log(f1.arguments.length);
      console.log(f1.length);
      console.log(f1.caller);//调用者
    }

函数还可以通过参数传递来实现调用,在函数体中执行函数

           function f1(fn) {
             setInterval(function () {
               console.log("定时器开始");
               fn();
               console.log("定时器结束");
             },1000);
           }

           f1(function () {
             console.log("好困啊,好累啊,就是想睡觉");
           });

函数作为返回值

           可以参考java中设置toString方法进行理解
           var num=10;
           console.log(typeof num);  number
           var obj={};
           console.log(obj instanceof Object);  true
           更改this为obj,直接打印obj的使用会显示其数据类型
           Object.prototype.toString.call(obj);
            console.log(obj)  {}

            获取数据类型,修改this指向具体类型数据,通过toString方法进行打印
           console.log(Object.prototype.toString.call([]));  [object Array]
           console.log(Object.prototype.toString.call(new Date()));  [object Date]

           函数作为返回值的使用
        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

函数作为参数练习,有点像java中的重写equals方法

    *sort方法会从零号位置进行遍历和比较,如果返回值大于零,则进行交换。

    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;
      }
    });
    console.log(arr);

    var arr1=["acdef","abcd","bcedf","bced"];
    arr1.sort(function (a,b) {
      if(a>b){
        return 1;
      }else if(a==b){
        return 0;
      }else{
        return -1;
      }
    });
    console.log(arr1);

案例:函数作为参数

    function File(name, size, time) {
      this.name = name;//电影名字
      this.size = size;//电影大小
      this.time = time;//电影的上映时间
    }
    var f1 = new File("jack.avi", "400M", "1997-12-12");
    var f2 = new File("tom.avi", "200M", "2017-12-12");
    var f3 = new File("xiaosu.avi", "800M", "2010-12-12");
    var arr = [f1, f2, f3];

    function fn(attr) {
      //函数作为返回值
      return function getSort(obj1, obj2) {
        if (obj1[attr] > obj2[attr]) {
          return 1;
        } else if (obj1[attr] == obj2[attr]) {
          return 0;
        } else {
          return -1;
        }
      }
    }

    var ff = fn("name");
    //函数作为参数
    arr.sort(ff);
    for (var i = 0; i < arr.length; i++) {
      console.log(arr[i].name + "====>" + arr[i].size + "===>" + arr[i].time);
    }

作用域和作用域链和预解析

    //变量---->局部变量和全局变量,
    //作用域:就是变量的使用范围
    //局部作用域和全局作用域
    //js中没有块级作用域---一对括号中定义的变量,这个变量可以在大括号外面使用
    //函数中定义的变量是局部变量

        if(true){
            var num=10;
        }
        console.log(num)    10
        function fn() {
            var num2=20;
        }
        console.log(num2);  报异常 num2 is not defined

    作用域链:变量的使用,从里向外,层层的搜索,搜索到了就可以直接使用了层层搜索,搜索到0级作用域的时候,如果还是没有找到这个变量,结果就是报错

    *如果里层没有对应的变量,它会一层一层想外查找

        var num=10;
        function f() {
            var num=20;
            function f1() {
                var num=30;
                console.log(num);
            }
            f1();
        }
        f();

    //预解析:就是在浏览器解析代码之前,把变量的  声明  和  函数的声明  提前(提升)到该作用域的最上面

        console.log(num);
        var num=10;   undefined 声明提前了,但是没有初始化
        f();   函数执行了,预解析函数提前了
        function f() {
            console.log('函数执行了')
        }
        console.log(f1); undefined 函数的声明提前了
        var f1=function() {
            console.log('声明提前了')
        }

闭包
    * 闭包的概念:函数A中,有一个函数B,函数B中可以访问函数A中定义的变量或者是数据,此时形成了闭包(这句话暂时不严谨)
    * 闭包的模式:函数模式的闭包,对象模式的闭包
    * 闭包的作用:缓存数据,延长作用域链
    * 闭包的优点和缺点:缓存数据

        函数模式的闭包:在一个函数中有一个函数
           function f1() {
             var num=10;
             //函数的声明
             function f2() {
               console.log(num);  10
             }
             //函数调用
             f2();
           }
           f1();

        对象模式的闭包:函数中有一个对象
           function f3() {
             var num=10;
             var obj={
               age:num
             };
             console.log(obj.age);//10
           }
           f3();

闭包小练习

        function f() {
            var num=10;
            return function(){
                num++;
                return num;
            }
        }
        var fn=f();
        console.log(fn()); 11
        console.log(fn()); 12
        console.log(fn()); 13

总结:如果想要缓存数据,就把这个数据放在外层的函数和里层的函数的中间位置

    //闭包的作用:缓存数据.优点也是缺陷,没有及时的释放

    //局部变量是在函数中,函数使用结束后,局部变量就会被自动的释放
    //闭包后,里面的局部变量的使用作用域链就会被延长

    function showRandom() {
      var num=parseInt(Math.random()*10+1);
      console.log(num);
    }

    showRandom();
    showRandom();
    showRandom();

实现了缓存功能的闭包,多次调用打印的数字都一样
    function f1() {
      var num=parseInt(Math.random()*10+1);
      return function () {
        console.log(num);
      }
    }

    var ff=f1();

    ff();
    ff();
    ff();

案例:点赞小案例

  <style>
    ul {
      list-style-type: none;
    }

    li {
      float: left;
      margin-left: 10px;
    }

    img {
      width: 200px;
      height: 180px;
    }

    input {
      margin-left: 30%;
    }
  </style>
  <script>
    //$永远都是24k纯帅的十八岁的杨哥$
  </script>
</head>
<body>
<ul>
  <li><img src="images/ly.jpg" alt=""><br/><input type="button" value="赞(1)"></li>
  ...若干个...
</ul>
<script>

  //获取所有的按钮
  //根据标签名字获取元素
  function my$(tagName) {
    return document.getElementsByTagName(tagName);
  }
  //闭包缓存数据
  function getValue() {
    var value=2;
    return function () {
      //每一次点击的时候,都应该改变当前点击按钮的value值
      this.value="赞("+(value++)+")";
    }
  }
  //获取所有的按钮
  var btnObjs=my$("input");
  //循环遍历每个按钮,注册点击事件
  for(var i=0;i<btnObjs.length;i++){
    //注册事件
    btnObjs[i].onclick=getValue();
  }

       沙箱:环境,黑盒,在一个虚拟的环境中模拟真实世界,做实验,实验结果和真实世界的结果是一样,但是不会影响真实世界

    var num=10;
    (function () {
        var num=20;
        console.log(num+10);  30
    })();

沙箱小案例

    (function () {
        document.getElementById('btn').onclick=function () {
            console.log('按钮被点击了')
        }
    })();
    (function () {
        var str='我是中国人';
        console.log(str.substr(2))   中国人
    })();

沙箱小案例

<div>这是div</div>
<div>这是div</div>
<p>这是p</p>
<p>这是p</p>
<script>
  var getTag = 10;
  var dvObjs = 20;
  var pObjs = 30;
  (function () {
    //根据标签名字获取元素
    function getTag(tagName) {
      return document.getElementsByTagName(tagName)
    }
    //获取所有的div
    var dvObjs = getTag("div");
    for (var i = 0; i < dvObjs.length; i++) {
      dvObjs[i].style.border = "2px solid pink";
    }
    //获取所有的p
    var pObjs = getTag("p");
    for (var i = 0; i < pObjs.length; i++) {
      pObjs[i].style.border = "2px solid pink";
    }
  }());
  console.log(getTag);  10
  console.log(dvObjs);  20
  console.log(pObjs);   20

递归:函数中调用函数自己,此时就是递归,递归一定要有结束的条件

        function f(n) {
            if(n==1){
                return 1;
            }
            return n+f(n-1);
        }
        console.log(f(10));

猜你喜欢

转载自blog.csdn.net/qq_34117624/article/details/82909242
今日推荐