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
原文地址:https://www.cnblogs.com/zach0812/p/11923572.html