前端学习从入门到高级全程记录之32(JavaScript高级4)

本文深入探讨JavaScript中的高阶函数概念,包括call、apply、bind的使用及区别,函数作为参数和返回值的应用,以及闭包的原理和实际案例,如缓存数据和实现点赞功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

学习目标

本期接上期继续学习JavaScript高级。

8.高阶函数(接上一期)

8.8 call、apply、bind

上期了解了函数 this 指向的不同场景之后,我们知道有些情况下我们为了使用某种特定环境的 this 引用,

这时候时候我们就需要采用一些特殊手段来处理了,例如我们经常在定时器外部备份 this 引用,然后在定时器函数内部使用外部 this 的引用。

然而实际上对于这种做法我们的 JavaScript 为我们专门提供了一些函数方法用来帮我们更优雅的处理函数内部 this 指向问题。

这就是接下来我们要学习的 call、apply、bind 三个函数方法。

call

call() 方法调用一个函数, 其具有一个指定的 this 值和分别地提供的参数(参数的列表)。

注意:该方法的作用和 apply() 方法类似,只有一个区别,就是 call() 方法接受的是若干个参数的列表,而 apply() 方法接受的是一个包含多个参数的数组。

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

参数:

  • thisArg
    • 在 fun 函数运行时指定的 this 值
    • 如果指定了 null 或者 undefined 则内部 this 指向 window
  • arg1, arg2, …
    • 指定的参数列表
apply

apply() 方法调用一个函数, 其具有一个指定的 this 值,以及作为一个数组(或类似数组的对象)提供的参数。

注意:该方法的作用和 call() 方法类似,只有一个区别,就是 call() 方法接受的是若干个参数的列表,而 apply() 方法接受的是一个包含多个参数的数组。

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

参数:

  • thisArg
  • argsArray

apply() 与 call() 非常相似,不同之处在于提供参数的方式。

apply() 使用参数数组而不是一组参数列表。例如:

fun.apply(this, ['eat', 'bananas'])

例子:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>title</title>
  <script>

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

//    function f1(x,y) {
//      console.log("结果是:"+(x+y)+this);
//      return "10000";
//    }
//    f1(10,20);//函数的调用


    //console.log("========");
    //此时的f1实际上是当成对象来使用的,对象可以调用方法
    //apply和call方法也是函数的调用的方式
    //f1.apply();
    //f1.call();
    //console.log("==========");
    //f1.apply(null);
    //f1.call(null);

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

    //f1.apply(null,[100,200]);
    //f1.call(null,100,200);

    //apply和call都可以让函数或者方法来调用,传入参数和函数自己调用的写法不一样,但是效果是一样的

//    var result1=f1.apply(null,[10,20]);
//    var result2=f1.call(null,10,20);
//    console.log(result1);
//    console.log(result2);





//    function f1(x,y) {
//      console.log("这个函数是window对象的一个方法:"+(x+y)+this.sex);
//    }
//    window.f1(10,20);
//    //obj是一个对象
//    var obj={
//      age:10,
//      sex:"男"
//    };
//
//    window.f1.apply(obj,[10,20]);
//    window.f1.call(obj,10,20);
//    console.dir(obj);


    //apply和call可以改变this的指向


    function Person(age,sex) {
      this.age=age;
      this.sex=sex;
    }
    //通过原型添加方法
    Person.prototype.sayHi=function (x,y) {
      console.log("您好啊:"+this.sex);
      return 1000;
    };
    var per=new Person(10,"男");
    per.sayHi();

    console.log("==============");
    function Student(name,sex) {
      this.name=name;
      this.sex=sex;
    }
    var stu=new Student("小明","人妖");
    var r1=per.sayHi.apply(stu,[10,20]);
    var r2=per.sayHi.call(stu,10,20);

    console.log(r1);
    console.log(r2);
  </script>
</head>
<body>


</body>
</html>
总结apply和call
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>title</title>
  <script>

    //apply和call都可以改变this的指向
    //函数的调用,改变this的指向
    //    function f1(x,y) {
    //      console.log((x+y)+":===>"+this);
    //      return "这是函数的返回值";
    //    }
    //    //apply和call调用
    //    var r1=f1.apply(null,[1,2]);//此时f1中的this是window
    //    console.log(r1);
    //    var r2=f1.call(null,1,2);//此时f1中的this是window
    //    console.log(r2);
    //    console.log("=============>");
    //    //改变this的指向
    //    var obj={
    //      sex:"男"
    //    };
    //    //本来f1函数是window对象的,但是传入obj之后,f1函数此时就是obj对象的
    //    var r3=f1.apply(obj,[1,2]);//此时f1中的this是obj
    //    console.log(r3);
    //    var r4=f1.call(obj,1,2);//此时f1中的this是obj
    //    console.log(r4);


    //方法改变this的指向

//    function Person(age) {
//      this.age = age;
//    }
//    Person.prototype.sayHi = function (x, y) {
//      console.log((x + y) + ":====>" + this.age);//是实例对象
//    };
//
//    function Student(age) {
//      this.age = age;
//    }
//    var per = new Person(10);//实例对象
//    var stu = new Student(100);//实例对象
//    //sayHi方法是per实例对象的
//    per.sayHi.apply(stu, [10, 20]);
//    per.sayHi.call(stu, 10, 20);


    //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也是对象
    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中


    function Person() {
      this.sayHi=function () {
        console.log("您好");
      };
    }
    Person.prototype.eat=function () {
      console.log("吃");
    };

    var per=new Person();
    per.sayHi();
    per.eat();
    console.dir(per);
    //实例对象调用方法,方法要么在实例对象中存在,要么在原型对象中存在

  </script>
</head>
<body>


</body>
</html>
bind方法

bind() 函数会创建一个新函数(称为绑定函数),新函数与被调函数(绑定函数的目标函数)具有相同的函数体(在 ECMAScript 5 规范中内置的call属性)。

当目标函数被调用时 this 值绑定到 bind() 的第一个参数,该参数不能被重写。绑定函数被调用时,bind() 也接受预设的参数提供给原函数。

一个绑定函数也能使用new操作符创建对象:这种行为就像把原函数当成构造器。提供的 this 值被忽略,同时调用时的参数被提供给模拟函数。

语法:

fun.bind(thisArg[, arg1[, arg2[, ...]]])

参数:

  • thisArg
    • 当绑定函数被调用时,该参数会作为原函数运行时的 this 指向。当使用new 操作符调用绑定函数时,该参数无效。
  • arg1, arg2, …
    • 当绑定函数被调用时,这些参数将置于实参之前传递给被绑定的方法。

返回值:

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

示例1:

this.x = 9; 
var module = {
  x: 81,
  getX: function() { return this.x; }
};

module.getX(); // 返回 81

var retrieveX = module.getX;
retrieveX(); // 返回 9, 在这种情况下,"this"指向全局作用域

// 创建一个新函数,将"this"绑定到module对象
// 新手可能会被全局的x变量和module里的属性x所迷惑
var boundGetX = retrieveX.bind(module);
boundGetX(); // 返回 81

示例2:

function LateBloomer() {
  this.petalCount = Math.ceil(Math.random() * 12) + 1;
}

// Declare bloom after a delay of 1 second
LateBloomer.prototype.bloom = function() {
  window.setTimeout(this.declare.bind(this), 1000);
};

LateBloomer.prototype.declare = function() {
  console.log('I am a beautiful flower with ' +
    this.petalCount + ' petals!');
};

var flower = new LateBloomer();
flower.bloom();  // 一秒钟后, 调用'declare'方法
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>title</title>
  <script>

    function f1(x, y) {
      console.log((x + y) + ":=====>" + this.age);
    }


    //复制了一份的时候,把参数传入到了f1函数中,x===>10,y===>20,null就是this,默认就是window
    //bind方法是复制的意思,参数可以在复制的时候传进去,也可以在复制之后调用的时候传入进去
    //apply和call是调用的时候改变this指向
    //bind方法,是赋值一份的时候,改变了this的指向


    //    var ff=f1.bind(null);
    //    ff(10,20);


//    function Person() {
//      this.age = 1000;
//    }
//    Person.prototype.eat = function () {
//      console.log("这个是吃");
//    };
//    var per = new Person();
//
//    var ff = f1.bind(per, 10, 20);
//    ff();




    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();
    //bind是用来复制一份
    //使用的语法:
    /*
    * 函数名字.bind(对象,参数1,参数2,...);---->返回值是复制之后的这个函数
    * 方法名字.bind(对象,参数1,参数2,...);---->返回值是复制之后的这个方法
    *
    * */

  </script>
</head>
<body>


</body>
</html>
bind的应用
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>title</title>
  <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>
</head>
<body>


</body>
</html>
总结
  • call 和 apply 特性一样
    • 都是用来调用函数,而且是立即调用
    • 但是可以在调用函数的同时,通过第一个参数指定函数内部 this 的指向
    • call 调用的时候,参数必须以参数列表的形式进行传递,也就是以逗号分隔的方式依次传递即可
    • apply 调用的时候,参数必须是一个数组,然后在执行的时候,会将数组内部的元素一个一个拿出来,与形参一一对应进行传递
    • 如果第一个参数指定了 null 或者 undefined 则内部 this 指向 window
  • bind
    • 可以用来指定内部 this 的指向,然后生成一个改变了 this 指向的新的函数
    • 它和 call、apply 最大的区别是:bind 不会调用
    • bind 支持传递参数,它的传参方式比较特殊,一共有两个位置可以传递
        1. 在 bind 的同时,以参数列表的形式进行传递
        1. 在调用的时候,以参数列表的形式进行传递
      • 那到底以谁 bind 的时候传递的参数为准呢还是以调用的时候传递的参数为准
      • 两者合并:bind 的时候传递的参数和调用的时候传递的参数会合并到一起,传递到函数内部

8.9 函数的其他成员

  • arguments
    • 实参集合
  • caller
    • 函数的调用者
  • length
    • 形参的个数
  • name
    • 函数的名称
function fn(x, y, z) {
  console.log(fn.length) // => 形参的个数
  console.log(arguments) // 伪数组实参参数集合
  console.log(arguments.callee === fn) // 函数本身
  console.log(fn.caller) // 函数的调用者
  console.log(fn.name) // => 函数的名字
}

function f() {
  fn(10, 20, 30)
}

f()
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>title</title>
  <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);//调用者
    }
//    f1.name="f5";
//    f1(10,20,30,40);
//    console.dir(f1);


    function f2() {
      console.log("f2函数的代码");
      f1(1,2);
    }
    f2();
  </script>
</head>
<body>


</body>
</html>

8.10 高阶函数之函数作为参数使用

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>title</title>
  <script>


//    function f1(fn) {
//      console.log("f1的函数");
//      fn();//此时fn当成是一个函数来使用的
//    }
//    //fn是参数,最后作为函数使用了,函数是可以作为参数使用
//    //传入匿名函数
//    f1(function () {
//      console.log("我是匿名函数");
//    });
//    //命名函数
//    function f2() {
//      console.log("f2的函数");
//    }
//    f1(f2);
//    //函数作为参数的时候,如果是命名函数,那么只传入命名函数的名字,没有括号



//    function f1(fn) {
//      setInterval(function () {
//        console.log("定时器开始");
//        fn();
//        console.log("定时器结束");
//      },1000);
//    }
//
//    f1(function () {
//      console.log("好困啊,好累啊,就是想睡觉");
//    });

  </script>
</head>
<body>


</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>title</title>
  <script>

    //    var arr = [1, 100, 20, 200, 40, 50, 120, 10];
    //    //排序
    //    arr.sort();
    //    console.log(arr);

    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);









  </script>
</head>
<body>


</body>
</html>

8.11 高阶函数之函数作为返回值使用

function genFun (type) {
  return function (obj) {
    return Object.prototype.toString.call(obj) === type
  }
}

var isArray = genFun('[object Array]')
var isObject = genFun('[object Object]')

console.log(isArray([])) // => true
console.log(isArray({})) // => true

扩展案例:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>title</title>
  <script>

    //排序,每个文件都有名字,大小,时间,都可以按照某个属性的值进行排序

    //三部电影,电影有名字,大小,上映时间
    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);
    }

  </script>
</head>
<body>


</body>
</html>

9.闭包

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

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>title</title>
  <script>

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

//    while(true){
//      var num=10;
//      break;
//    }
//    console.log(num);
//
//    {
//      var num2=100;
//    }
//    console.log(num2);
//
//    if(true){
//      var num3=1000;
//    }
//    console.log(num3);

//    function f1() {
//      //局部变量
//      var num=10;
//    }
//    console.log(num);


    作用域链:变量的使用,从里向外,层层的搜索,搜索到了就可以直接使用了
    层层搜索,搜索到0级作用域的时候,如果还是没有找到这个变量,结果就是报错
   var num=10; //作用域链 级别:0
   var num2=20;
   var str = "abc"
   function f1() {
     var num2=20;
     function f2() {
       var num3=30;
       console.log(num);
     }
     f2();
   }
   f1();


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

    //变量的提升
    console.log(num);
    var num=100;

    //函数的声明被提前了
    f1();
    function f1() {
      console.log("这个函数,执行了");
    }

    
    f2();
    var f2=function () {
      console.log("小杨好帅哦");
    };

  </script>
</head>
<body>


</body>
</html>

9.2 闭包的概念

闭包就是能够读取其他函数内部变量的函数,

由于在 Javascript 语言中,只有函数内部的子函数才能读取局部变量,

因此可以把闭包简单理解成 “定义在一个函数内部的函数”。

所以,在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。

闭包的用途:

  • 可以在函数外部读取函数内部成员
  • 让函数内成员始终存活在内存中

解释:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>title</title>
  <script>
    //闭包
    /*
    * 闭包的概念:函数A中,有一个函数B,函数B中可以访问函数A中定义的变量或者是数据,此时形成了闭包(这句话暂时不严谨)
    * 闭包的模式:函数模式的闭包,对象模式的闭包
    * 闭包的作用:缓存数据,延长作用域链
    * 闭包的优点和缺点:缓存数据
    *
    * 闭包的应用
    *
    *
    * */


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

    //对象模式的闭包:函数中有一个对象

//    function f3() {
//      var num=10;
//      var obj={
//        age:num
//      };
//      console.log(obj.age);//10
//    }
//    f3();



//    function f1() {
//      var num=10;
//      return function () {
//        console.log(num);
//        return num;
//      }
//    }
//
//   var ff= f1();
//   var result= ff();
//    console.log(result);


//    function f2() {
//      var num=100;
//      return {
//        age:num
//      }
//    }
//
//   var obj= f2();
//    console.log(obj.age);

  </script>
</head>
<body>


</body>
</html>

练习:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>title</title>
  <script>


    //普通的函数
    function f1() {
      var num = 10;
      num++;
      return num;
    }
    console.log(f1());//11
    console.log(f1());//11
    console.log(f1());//11

    //函数模式的闭包
    function f2() {
      var num = 10;
      return function () {
        num++;
        return num;
      }
    }
    var ff = f2();
    console.log(ff());//11
    console.log(ff());//12
    console.log(ff());//13
    //把num的值缓存了。
  </script>
</head>
<body>


</body>
</html>

9.3 闭包案例产生相同的随机数

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>title</title>
  <script>

    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();

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

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

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

  </script>
</head>
<body>


</body>
</html>

9.4 闭包案例实现点赞

所需图片:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>对自己狠点</title>
	<style>
		ul {
			list-style-type: none;
		}

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

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

		input {
			margin-left: 30%;
		}
	</style>
</head>
<body>
<ul>
	<li><img src="images/ly.jpg" alt=""><br/><input type="button" value="赞(1)"></li>
	<li><img src="images/lyml.jpg" alt=""><br/><input type="button" value="赞(1)"></li>
	<li><img src="images/fj.jpg" alt=""><br/><input type="button" value="赞(1)"></li>
	<li><img src="images/bd.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();
	}
</script>
</body>
</html>

10.沙箱

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>title</title>
  <script>
    //沙箱:环境,黑盒,在一个虚拟的环境中模拟真实世界,做实验,实验结果和真实世界的结果是一样,但是不会影响真实世界



//    var num=10;
//    console.log(num+10);

//    //沙箱---小环境
//    (function () {
//      var num=10;
//      console.log(num);
//    })();
//
//    //沙箱---小环境
//    (function () {
//      var num=20;
//      console.log(num+10);
//    }());



//    var num=100;
//    (function () {
//      var num=10;
//      console.log(num);//10
//    }());
//
//
//    console.log(num);//100结果互不影响

  </script>
</head>
<body>


</body>
</html>

10.1 沙箱小案例

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>title</title>
  <script>


    (function () {
      var str="小白喜欢小黑";
      str=str.substr(2);
      console.log(str);
    }());


    //沙箱
    (function () {
      var str="小明喜欢小红";
      str=str.substr(2);
      console.log(str);
    }());



  </script>
</head>
<body>
<input type="button" value="按钮" id="btn"/>
<script>
  //点击按钮,弹出对话框
  (function () {
    document.getElementById("btn").onclick=function () {
      console.log("按钮被点击了");
    };
  }());

</script>

</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>title</title>

</head>
<body>
<div>这是div</div>
<div>这是div</div>
<div>这是div</div>
<p>这是p</p>
<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);
  console.log(dvObjs);
  console.log(pObjs);
</script>
</body>
</html>

11.函数递归

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>title</title>
  <script>
    //递归:函数中调用函数自己,此时就是递归,递归一定要有结束的条件
    //

    var i = 0;
    function f1() {
      i++;
      if (i < 5) {
        f1();
      }
      console.log("从前有个山,山里有个庙,庙里有个和尚给小和尚讲故事:");

    }

    f1();
  </script>
</head>
<body>


</body>
</html>

递归求和:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>title</title>
  <script>
    //求n个数字的和,5 计算1+2+3+4+5
//    var sum=0;
//    for(var i=1;i<=5;i++){
//      sum+=i;
//    }
//    console.log(sum);


    //递归实现:求n个数字的和   n=5--->  5+4+3+2+1

    //函数的声明
//    function getSum(x) {
//      if(x==1){
//        return 1;
//      }
//      return x+getSum(x-1);
//    }
//    //函数的调用
//    console.log(getSum(5));

    /*
    *
    * 执行过程:
    * 代码执行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 ---1+2+3
    //523
    function getEverySum(x) {
      if(x<10){
        return x;
      }
      //获取的是这个数字的个位数
      return x%10+getEverySum(parseInt(x/10));
    }
   console.log(getEverySum(1364));//5

    //递归案例:求斐波那契数列

    function getFib(x) {
      if(x==1||x==2){
        return 1
      }
      return getFib(x-1)+getFib(x-2);
    }
    console.log(getFib(12));
  </script>
</head>
<body>


</body>
</html>

总结

本期学习到此结束

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值