• 14 apply 和 call 方法_bind方法_高阶函数_作用域相关_闭包_递归


    复习及今日计划:

    复习:

    今日计划:

    改变函数中this的指向:

    apply 和call 方法的使用:

    下面通过 apply 和 call 改变this 的指向。

    将要改变的对象 放在第一个参数位置,就可以使得函数对象中的this 变为该对象。

    apply 和 call 的区别:

    如果函数对象中有参数,apply 是以一个数组传入的。

    而call 是以不定参数(...)传入的。

     1 <!DOCTYPE html>
     2 <html lang="en">
     3 <head>
     4     <meta charset="UTF-8">
     5     <title>title</title>
     6     <script>
     7         //改变函数对象 中this 的指向 
     8         function f1(name, age) {
     9             console.log("Name:"+name+ " Age :"+age+" 此时的this "+ this);
    10         }
    11         f1("tom",18);
    12         var obj = {
    13             sex:"男"
    14         };
    15         //使用apply /call 调用f1 函数
    16         //f1 是个对象
    17         // f1.apply(null,["tom",18]); //和 f1("tom",18); 没区别
    18         // f1.call(null,"tom",18); //和 f1("tom",18); 没区别
    19         
    20         f1.apply(obj,["tom",18]);  //此时 f1中的this 就变为 了 obj 
    21         f1.call(obj,"tom",18);  //此时 f1中的this 就变为 了 obj 
    22         
    23     </script>
    24 </head>
    25 <body>
    26 
    27 
    28 </body>
    29 </html>
    通过apply() 或call() 来改变函数对象中this 的指向!

    对于方法也是如此,和函数完全一致。

    总结

    使用时机:

    我们想使用一个函数,但是希望它里面的this 是我们想用的对象。就可以使用它了!将我们想用的对象传入即可。

    补充:

    上述两个方法实际是在函数 的 构造函数(Function的 原型中。

    bind() 方法的使用:

    使用时机:

    和apply()/call() 一样。

    我们想使用一个函数,但是希望它里面的this 是我们想用的对象。就可以使用它了!将我们想用的对象传入即可。

    只不过一个是直接调用 该函数,而.bind() 将函数中的this替换为我们想用的对象之后,会返回一个该函数对象

    bind() 的应用:

     1 <!DOCTYPE html>
     2 <html lang="en">
     3 <head>
     4     <meta charset="UTF-8">
     5     <title>title</title>
     6     <script>
     7         //函数对象 中this 的指向
     8         function ShowRandom() {
     9             //1-10 的随机数
    10             this.num = parseInt(Math.random()*10 +1);
    11         }
    12         //添加原型方法  --- show1, show2  方法
    13         ShowRandom.prototype.show1 = function () {
    14             setInterval(function () {
    15                 this.show2();
    16             }.bind(this),100);  //原本function(){} 匿名函数中的this 指向是 window ,但是通过bind 复制 产生了一个新的函数,而且里面的this变为了我们想要的this(实例对象)
    17         };
    18         //上述代码也可如下:(推荐使用!) 注意bind() 的返回值 是个函数
    19         /*
    20         ShowRandom.prototype.show1 = function () {
    21             // setInterval(this.show2,100); //这肯定是不可以。因为此时this 是window .  
    22             //我们想在想用 this.show2这个函数,而且想让它里面的this为 实例对象this 
    23             //如下即可。
    24             setInterval(this.show2.bind(this),100);
    25         };
    26          */
    27         
    28         ShowRandom.prototype.show2 = function () {
    29             console.log(this.num);
    30         };
    31 
    32         var showRandom = new ShowRandom();
    33         showRandom.show1();
    34 
    35 
    36 
    37 
    38     </script>
    39 </head>
    40 <body>
    41 
    42 
    43 </body>
    44 </html>
    View Code

    函数中的几个成员变量:

    高阶函数:

    函数作为参数:

     1 <!DOCTYPE html>
     2 <html lang="en">
     3 <head>
     4     <meta charset="UTF-8">
     5     <title>title</title>
     6     <script>
     7         //定时器
     8         function Wrapper(fn){
     9             setInterval(function () {
    10                 console.log("这里是定时器!");
    11                 fn();
    12             },1000);  //1s 执行一次 指定的函数 。
    13         }
    14         Wrapper(function () {
    15             console.log("Hello World!");
    16         });
    17     </script>
    18 </head>
    19 <body>
    20 
    21 
    22 </body>
    23 </html>
    1s执行一次函数。(定时器内执行 我们传入的参数)

    上面用到了包装。

    函数作为返回值:

    略。。。

    如何获取一个数据的数据类型:

    三种方式!!!

    我们之前 想要知道一个数据的数据类型:

    有以下两种方式:

    1,通过typeof 获取

    2,通过instanceof 来判断  

    下面看第三种:使用.call      借用   Object的一个方法: Object.prototype.toString() 方法。

     1 <!DOCTYPE html>
     2 <html lang="en">
     3 <head>
     4     <meta charset="UTF-8">
     5     <title>title</title>
     6     <script>
     7         //
     8         var ret =  Object.prototype.toString(); //[object Object] 此时.toString()中的this是Object的实例对象。所以它的类型是Object
     9         console.log(ret);
    10 
    11         var arr = [1,2,3];
    12         //现在 ,我们想用下 Object.prototype.toString()的方法,希望它里面的this不是Object的实例对象,而是我们arr对象。
    13         //于是尝试如下:
    14         var ret2 = Object.prototype.toString.call(arr);
    15         console.log(ret2);   //[object Array]  于是,我们就可以知道,只要是用Object.prototype.toString()的方法,并且将这个方法中的this改为相应的对象,就可以得到这个对象的类型。
    16 
    17         //再例如:
    18         var str = "Hello World";
    19         console.log(Object.prototype.toString.call(str));  //[object String]
    20 
    21         
    22 
    23     </script>
    24 </head>
    25 <body>
    26 
    27 
    28 </body>
    29 </html>
    View Code

    只要将toString()中的this改为相应的对象,就能得到 该对象的数据类型了。

    注:该方法的返回值是个string !    即返回的结果 “ [object String] ” 是string类型的。

    排序:

    可以通过给它传入一个 函数 来解决。(即函数做为参数 )

     1 <!DOCTYPE html>
     2 <html lang="en">
     3 <head>
     4     <meta charset="UTF-8">
     5     <title>title</title>
     6     <script>
     7         var arr = [1,3,7,5,2,1,45,2,0,1];
     8         arr.sort(function (a, b) {
     9             if(a>b)
    10                 return 1;
    11             else if(a ==b)
    12                 return 0;
    13             else
    14                 return -1;
    15         });
    16         console.log(arr); 
    17 
    18 
    19     </script>
    20 </head>
    21 <body>
    22 
    23 
    24 </body>
    25 </html>
    此时排序就稳定了!

    可是上面是数字间的排序,如果变为字符串呢?

    字符串之所以可以比较是因为 ASCII 值。

    可是如果是对象,对象之间是不能直接进行比较的。我可以通过对象的某个属性排序。

    案例:排序 + 函数作为返回值 的应用:

    现在有三个人,我们分别按照他们的姓名,年龄,身高进行排序。

     1 <!DOCTYPE html>
     2 <html lang="en">
     3 <head>
     4     <meta charset="UTF-8">
     5     <title>title</title>
     6     <script>
     7 
     8         //现在有 三个人
     9         function Person(name, age, height) {
    10             this.name = name;
    11             this.age = age;
    12             this.height = height;
    13         }
    14         var p1 = new Person("eom",18,160);
    15         var p2 = new Person("tgon",48,150);
    16         var p3 = new Person("alex",28,175);
    17 
    18         var arr = [p1,p2,p3];
    19 
    20         // 遍历输出
    21         function printArr() {
    22             for (var i =0;i<arr.length;i++){
    23                 console.log("Name: "+arr[i].name+" Age: "+arr[i].age+" Height: "+arr[i].height);
    24             }
    25         }
    26         printArr();
    27 
    28         //1,现在按照 "人的名字" 进行排序输出
    29         console.log("------------------");
    30         arr.sort(function (obj1,obj2) {
    31             if(obj1.name > obj2.name)
    32                 return 1;
    33             else if(obj1.name == obj2.name)
    34                 return 0;
    35             else
    36                 return -1;
    37         });
    38         printArr();
    39 
    40 
    41         //2,现在按照 "人的年龄" 进行排序输出
    42         console.log("------------------");
    43         arr.sort(function (obj1,obj2) {
    44             if(obj1.age > obj2.age)
    45                 return 1;
    46             else if(obj1.age == obj2.age)
    47                 return 0;
    48             else
    49                 return -1;
    50         });
    51         printArr();
    52 
    53         //3,现在按照 "人的身高" 进行排序输出
    54         console.log("------------------");
    55         arr.sort(function (obj1,obj2) {
    56             if(obj1.height > obj2.height)
    57                 return 1;
    58             else if(obj1.height == obj2.height)
    59                 return 0;
    60             else
    61                 return -1;
    62         });
    63         printArr();
    64 
    65     </script>
    66 </head>
    67 <body>
    68 
    69 
    70 </body>
    71 </html>
    View Code

    但是,上述代码的冗余性太高了。

    下面利用  函数作为返回值来解决。

     1 <!DOCTYPE html>
     2 <html lang="en">
     3 <head>
     4     <meta charset="UTF-8">
     5     <title>title</title>
     6     <script>
     7 
     8         //现在有 三个人
     9         function Person(name, age, height) {
    10             this.name = name;
    11             this.age = age;
    12             this.height = height;
    13         }
    14         var p1 = new Person("eom",18,160);
    15         var p2 = new Person("tgon",48,150);
    16         var p3 = new Person("alex",28,175);
    17 
    18         var arr = [p1,p2,p3];
    19 
    20         // 遍历输出
    21         function printArr() {
    22             for (var i =0;i<arr.length;i++){
    23                 console.log("Name: "+arr[i].name+" Age: "+arr[i].age+" Height: "+arr[i].height);
    24             }
    25         }
    26         printArr();
    27 
    28         //1,现在按照 "人的名字" 进行排序输出
    29         console.log("------------------");
    30         function solution(attr){
    31             return function (obj1,obj2) {
    32                 if(obj1[attr] > obj2[attr])
    33                     return 1;
    34                 else if(obj1[attr] == obj2[attr])
    35                     return 0;
    36                 else
    37                     return -1;
    38             }
    39         }
    40         arr.sort(solution("name"));
    41         printArr();
    42 
    43         //2,现在按照 "人的年龄" 进行排序输出
    44         console.log("------------------");
    45         arr.sort(solution("age"));  
    46         printArr();
    47 
    48         //3,现在按照 "人的身高" 进行排序输出
    49         console.log("------------------");
    50         arr.sort(solution("height"));
    51         printArr();
    52     </script>
    53 </head>
    54 <body>
    55 
    56 
    57 </body>
    58 </html>
    View Code

    可见,输出没变,代码少了很多。

    作用域_作用域链_预解析:

    作用域:

     

    所以,下面代码是可以输出的。

     1 <!DOCTYPE html>
     2 <html lang="en">
     3 <head>
     4     <meta charset="UTF-8">
     5     <title>title</title>
     6     <script>
     7         while (true){
     8             var num = 0;
     9             break;
    10         }
    11         console.log(num);  //输出是 0  
    12 
    13     </script>
    14 </head>
    15 <body>
    16 
    17 
    18 </body>
    19 </html>
    View Code

    但是,在函数内部的 是不能输出的。(函数内 是局部作用域!)如下代码:

     1 <!DOCTYPE html>
     2 <html lang="en">
     3 <head>
     4     <meta charset="UTF-8">
     5     <title>title</title>
     6     <script>
     7         function f(){
     8             var num = 0;
     9         }
    10         console.log(num);  //输出是 报错 num is not defined!
    11 
    12     </script>
    13 </head>
    14 <body>
    15 
    16 
    17 </body>
    18 </html>
    View Code

    作用域链:

    预解析:

     1 <!DOCTYPE html>
     2 <html lang="en">
     3 <head>
     4     <meta charset="UTF-8">
     5     <title>title</title>
     6     <script>
     7         // 1变量声明 的提升
     8         console.log(num); //此时的输出为 undefined  !
     9         var num = 100;
    10 
    11         // 2函数声明 的提升
    12         func();
    13         function func() {
    14             console.log("我是个函数");
    15         }
    16 
    17         func1(); //此时,就没有 函数声明 的提升  而是变量的声明提前。 func1是 undefined!   func1不是个函数    
    18         var func1 = function () {
    19             console.log("我也是函数");
    20         }
    21     </script>
    22 </head>
    23 <body>
    24 
    25 
    26 </body>
    27 </html>
    View Code

    闭包:

     1 <!DOCTYPE html>
     2 <html lang="en">
     3 <head>
     4     <meta charset="UTF-8">
     5     <title>title</title>
     6     <script>
     7         // 1,函数模式的闭包 :在一个函数中有一个函数 ,内层函数可以访问外层函数作用域中的变量 。
     8         function f1() {
     9             var num = 0;
    10             function f2() {
    11                 console.log(num);
    12             }
    13             f2();
    14         }
    15         f1();
    16 
    17         // 2,对象模式的闭包 :在一个函数中有个对象。对象可以访问外层函数作用域中的变量 。
    18         function f3() {
    19             var num = 10;
    20             var obj = {
    21                 age:num
    22             };
    23             console.log(obj.age);
    24         }
    25         f3();
    26 
    27 
    28 
    29 
    30     </script>
    31 </head>
    32 <body>
    33 
    34 
    35 </body>
    36 </html>
    闭包的两种模式!
     1 <!DOCTYPE html>
     2 <html lang="en">
     3 <head>
     4     <meta charset="UTF-8">
     5     <title>title</title>
     6     <script>
     7         // 1,函数模式 闭包
     8         function f1() {
     9             var num =10;
    10             return function () {
    11                 console.log("Hello World");
    12                 return num;
    13             }
    14         }
    15 
    16         var ret1 = f1();
    17         var ret2 = ret1();
    18         console.log(ret2);
    19 
    20         // 2 对象模式闭包
    21         function f2() {
    22             var num = 20;
    23             return {
    24                 age:num
    25             }
    26         }
    27         var obj = f2();
    28         console.log(obj.age);
    29         
    30 
    31 
    32 
    33 
    34 
    35 
    36 
    37     </script>
    38 </head>
    39 <body>
    40 
    41 
    42 </body>
    43 </html>
    这两种也和上面一样是闭包。

    之所以,闭包,就是将数据封存起来,起到了缓存的目的。

    闭包小案例:

     1 <!DOCTYPE html>
     2 <html lang="en">
     3 <head>
     4     <meta charset="UTF-8">
     5     <title>title</title>
     6     <script>
     7         // 1
     8         function f1() {
     9             var num = 10;
    10             num ++;
    11             return num;
    12         }
    13         console.log(f1()); //11
    14         console.log(f1()); //11
    15         console.log(f1()); //11
    16 
    17         // 2
    18         function f2() {
    19             var num = 10;
    20             return function () {
    21                 num ++;
    22                 return num;
    23             }
    24         }
    25         var ret = f2();
    26         console.log(ret()); //11
    27         console.log(ret()); //12
    28         console.log(ret()); //13  //原因是 ret 对象中 缓存的num 每次都不会再重新赋值 10 啦!
    29 
    30 
    31     </script>
    32 </head>
    33 <body>
    34 
    35 
    36 </body>
    37 </html>
    闭包的小案例!

    可以看出,闭包有缓存的功能。

    以后需要缓存一个变量的话,可以在闭包中返回!

    如下:

    通过闭包产生相同的随机数:

     1 <!DOCTYPE html>
     2 <html lang="en">
     3 <head>
     4     <meta charset="UTF-8">
     5     <title>title</title>
     6     <script>
     7         // 1
     8         function showRandom() {
     9             var num = parseInt(Math.random()*10 + 1);
    10             return num;
    11         }
    12         console.log(showRandom());
    13         console.log(showRandom());
    14         console.log(showRandom()); //随机数产生代码,执行了三次。
    15 
    16         // 2那么如何产生三个相同的 随机数值呢?
    17         function showRandom2() {
    18             var num = parseInt(Math.random()*10 +1);
    19             return function () {
    20                 return num;
    21             }
    22         }
    23         var ret =  showRandom2(); 
    24         console.log(ret());
    25         console.log(ret());
    26         console.log(ret()); //虽然调用了 三次,其实真正产生随机数只是执行了一次。
    27 
    28 
    29 
    30 
    31 
    32     </script>
    33 </head>
    34 <body>
    35 
    36 
    37 </body>
    38 </html>
    产生多个相同的随机数。

    闭包分析:

    闭包的优点缓存了数据。

    闭包的缺点:导致不能及时的释放变量的内存空间。

    闭包案例:

     1 <!DOCTYPE html>
     2 <html lang="en">
     3 <head>
     4     <meta charset="UTF-8">
     5     <title>title</title>
     6     <style>
     7         ul{
     8             list-style-type: none;
     9         }
    10         li{
    11             float: left;
    12             margin-left: 10px;
    13         }
    14         img{
    15             width: 200px;
    16             /*height: 180px;*/
    17         }
    18         input {
    19             margin-left: 30%;
    20         }
    21 
    22     </style>
    23 </head>
    24 <body>
    25     <ul>
    26         <li><img src="images/slidepic1.jpg" alt=""><br><input type="button" value="赞(1)"></li>
    27         <li><img src="images/slidepic2.jpg" alt=""><br><input type="button" value="赞(1)"></li>
    28         <li><img src="images/slidepic3.jpg" alt=""><br><input type="button" value="赞(1)"></li>
    29         <li><img src="images/slidepic4.jpg" alt=""><br><input type="button" value="赞(1)"></li>
    30     </ul>
    31     <script>
    32         //获取所有的按钮  通过 tagName
    33         function getByTagName(tagName) {
    34             return document.getElementsByTagName(tagName);
    35         }
    36         /* 1
    37         var btnObjs = getByTagName("input");
    38         for (var i =0;i<btnObjs.length;i++ ){
    39             btnObjs[i].onclick = function () {
    40                 var num = parseInt(this.value.slice(2)); //[2,)
    41                 this.value = "赞("+(++num)+")";
    42             };
    43         }
    44 
    45          */
    46 
    47 
    48         //2 使用闭包完成上述功能,   闭包缓冲数据。多次使用!          推荐使用  
    49         function getValue() {
    50             var num = 1;
    51             return function () {
    52                 this.value = "赞("+(++num)+")";
    53             }
    54         }
    55         //
    56         var btnObjs = getByTagName("input");
    57         for (var i =0;i<btnObjs.length;i++ ){
    58             btnObjs[i].onclick = getValue();
    59         }
    60 
    61 
    62     </script>
    63 
    64 
    65 
    66 
    67 </body>
    68 </html>
    点赞案例!

    沙箱:

    利用自调用函数来 形成 沙箱。

    沙箱小案例:

    以后的代码可以直接都放到沙箱中,这样 代码之间就很少会有冲突了。

    例如:

     1 <!DOCTYPE html>
     2 <html lang="en">
     3 <head>
     4     <meta charset="UTF-8">
     5     <title>title</title>
     6 </head>
     7 <body>
     8     <input type="button" value="点我" id="btn">
     9     <script>
    10         //点击按钮  弹出对话框
    11         (function(){
    12             document.getElementById("btn").onclick = function () {
    13                 alert("我出来了");
    14             }
    15         })();
    16     </script>
    17 </body>
    18 </html>
    View Code

    递归:

    递归案例:求1-n的和:

     1 <!DOCTYPE html>
     2 <html lang="en">
     3 <head>
     4     <meta charset="UTF-8">
     5     <title>title</title>
     6 </head>
     7 <body>
     8     <script>
     9 
    10         function getSum(n) {
    11             if( n == 1){
    12                 return 1;
    13             }
    14             return n + getSum(n-1);
    15         }
    16         var res = getSum(100);
    17         console.log(res); //5050
    18 
    19     </script>
    20 </body>
    21 </html>
    递归求和!

    递归案例:求一个数字各个位数上的和:

     1 <!DOCTYPE html>
     2 <html lang="en">
     3 <head>
     4     <meta charset="UTF-8">
     5     <title>title</title>
     6 </head>
     7 <body>
     8     <script>
     9 
    10         function getSum(n) {
    11             // if(Math.floor(n /10) == 0){
    12             if(n < 10){ //也可以这样,都一样。
    13                 return n;
    14             }
    15             return n %10 + getSum(Math.floor(n/10));
    16         }
    17         console.log(getSum(73636)); //25
    18 
    19     </script>
    20 </body>
    21 </html>
    View Code

    递归案例:求斐波那契数列 的第n项的值:

     1 <!DOCTYPE html>
     2 <html lang="en">
     3 <head>
     4     <meta charset="UTF-8">
     5     <title>title</title>
     6 </head>
     7 <body>
     8     <script>
     9 
    10         function getFib(n) {
    11             if(n == 1 || n ==2){
    12                 return 1;
    13             }
    14             return getFib(n-1) + getFib(n-2);
    15         }
    16         console.log(getFib(10));  //第十项的值为:55  
    17         // 1 1 2 3 5 8 13 21 34 55 !
    18         
    19     </script>
    20 </body>
    21 </html>
    View Code
  • 相关阅读:
    Cnic.SafeNativeMethods
    KnockOut文档--模板绑定
    luoguP1120 小木棍 [数据加强版]
    luoguP1951 收费站_NOI导刊2009提高(2)
    luoguP1821 [USACO07FEB]银牛派对Silver Cow Party
    luoguP2991 [USACO10OPEN]水滑梯Water Slides
    luoguP4198 楼房重建
    (数位dp)吉利数字 区间k大
    数字游戏
    Amount of Degrees
  • 原文地址:https://www.cnblogs.com/zach0812/p/11923572.html
Copyright © 2020-2023  润新知