|
1.函数进阶
- 函数的定义和使用
- 函数声明方式function关键字(命名函数)
- 函数表达式(匿名函数)
- new Function()
- Function里面的参数必须都是字符串格式
- 第三种方式执行效率低,也不方便书写,因此较少使用
- 所有函数都是Function的实例(对象)
- 函数也属于对象
1 <!DOCTYPE html>
2 <html>
3 <head>
4 <meta charset="utf-8">
5 <title></title>
6 </head>
7 <body>
8 <script type="text/javascript">
9 //函数的定义方式
10 //1.自定义函数
11 function fn(){};
12 //2.函数表达式
13 var fun = function(){};
14 //3.利用new Function('参数1','参数2','函数体');
15 var f = new Function('a','b','console.log(a+b)');
16 f(1,2);
17 //4.所有的函数都是Function的实例对象
18 </script>
19 </body>
20 </html>
1 <!DOCTYPE html>
2 <html>
3 <head>
4 <meta charset="utf-8">
5 <title></title>
6 </head>
7 <body>
8 <script type="text/javascript">
9 //函数的调用方式
10
11 //1.普通函数
12 function fn(){
13 console.log("普通函数");
14 }
15 // fn();
16 // fn.call();
17 //2.对象的方法
18 var obj = {
19 sayHi: function(){
20 console.log("Hi");
21 }
22 }
23 obj.sayHi();
24 //3.构造函数
25 function Star(){};
26 new Star();
27 //4.绑定时间的函数
28 // btn.onclick = function(){};
29 //点击按钮就可以调用这个函数
30 //5.定时器函数
31 setInterval(function(){},1000);
32 //这个函数是定时器自动每秒钟调用一次
33 //6.立即执行函数
34 (function(){console.log("怎么也飞不出,花花的世界~~~")})()
35 //立即执行函数是自动调用
36 </script>
37 </body>
38 </html>
| 调用方式 |
this指向 |
| 普通函数调用 |
window |
| 构造函数调用 |
实例对象,原型对象里面的方法也指向实例对象 |
| 对象方法调用 |
该方法所属对象 |
| 事件绑定调用 |
绑定事件对象 |
| 定时器函数 |
window |
| 立即执行函数 |
window |
1 <!DOCTYPE html>
2 <html>
3 <head>
4 <meta charset="utf-8">
5 <title></title>
6 </head>
7 <body>
8 <script type="text/javascript">
9 //函数的调用方式
10 //函数的不同决定了this的指向不同
11 //1.普通函数 this指向window
12 function fn(){
13 console.log("普通函数"+this);
14 }
15 // fn();
16 // fn.call();
17 //2.对象的方法 this指向对象
18 var obj = {
19 sayHi: function(){
20 console.log("Hi"+this);
21 }
22 }
23 // obj.sayHi();
24 //3.构造函数 this指向的是实例对象,原型对象里面的this指向的也是实例对象
25 function Star(){};
26 new Star();
27 //4.绑定时间的函数 this指向函数的调用者btn
28 // btn.onclick = function(){};
29 //点击按钮就可以调用这个函数
30 //5.定时器函数 this指向window
31 setInterval(function(){},1000);
32 //这个函数是定时器自动每秒钟调用一次
33 //6.立即执行函数this指向window
34 (function(){console.log("怎么也飞不出,花花的世界~~~")})()
35 //立即执行函数是自动调用
36 </script>
37 </body>
38 </html>
JavaScript为我们提供了一些函数方法帮助我们改变函数内部this指向问题,常用的有bind()、call()、apply()三种方法
call方法调用一个对象,简单理解为调用函数的方式,但是它可以改变函数的this指向
-
- apply()方法
- fun.apply(thisArg,[argsArray])
- thisArg:在fun函数运行时指定的this值
- argsArray:传递的值,必须包含在数组里面
- 返回值值就是函数的返回值,因为它必须是调用函数
bind()方法:不会调用函数
- fun.bind(thisArg,arg1,arg2,…)
- thisArg:在fun函数运行时指定this的值
- arg1、arg2:传递其他参数
- 返回由指定的this值和初始化参数改造的原函数拷贝
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<script type="text/javascript">
//改变函数内this指向,js提供了三种方式call()、apply()、bind()
//1.call()
var o = {
name: 'bbh'
};
function fn(arr,num){
console.log(this);
console.log(arr+num)
}
// fn.call(o);
//call第一个可以调用函数,第二个可以改变函数内部的this指向
//call的主要作用可以实现继承
//2.apply()应用运用的意思
// fn.apply(o,['bbh','56']);
//(1)也是调用函数,第二个可以改变函数内部的this指向
//(2)但是他的参数必须是数组、伪数组
//(3)apply的主要应用比如我们可以利用apply借助于数学内置对象找最大值
//3.bind()绑定捆绑的意思
var res = fn.bind(o);
//(1)不会调用原来的函数 可以改变原来函数内部this指向
//(2)返回的是原函数改变this之后产生的新函数
console.log(res);
</script>
</body>
</html>
1 <!DOCTYPE html>
2 <html>
3 <head>
4 <meta charset="utf-8">
5 <title></title>
6 </head>
7 <body>
8 <button>点击</button>
9 <script type="text/javascript">
10 //1.如果有的函数我们不需要立即调用,但是又想改变函数内部的this指向
11 //2.我们有一个按钮当我们点击了之后就禁用这个按钮,3秒之后启动
12 var btn = document.querySelector("button");
13 btn.onclick = function(){
14 this.disabled = true;
15 setTimeout(function(){
16 this.disabled = false;
17 //这个this指向的btn
18 }.bind(this),3000)
19 }
20 </script>
21 </body>
22 </html>
- call、apply、bind总结
- 相同点
- 区别点
- call和apply会调用函数,并且改变函数内部this指向
- call和apply传递的参数不一样,call传递参数arg1,arg2,…形式,apply必须数组形式[arg]
- bind不会调用函数,可以改变函数内部this指向
- 主要应用场景
- call经常做继承
- apply经常跟数组有关系,比如借助数学对象实现数组最大值和最小值
- bind不调用函数,但是还想改变this指向,比如改变定时器里的this指向
2.严格模式
JavaScript除了提供正常模式外,还提供了严格模式(strict mode)。即在严格的条件下运行JS代码
- 严格模式
- 消除了JavaScript语法的一些不合理,不严谨之处,减少了一些怪异行为
- 消除代码运行的一些不安全之处,保证代码运行的安全
- 提高编译器效率,增加运行速度
- 禁用了在ECMAScript的未来版本中可能会使用的一些语法,例如一些保留字:class
- 开启严格模式:严格模式可以应用到整个脚本或个别函数中。我们价格严格模式分为脚本开启严格模式和函数开启严格模式
- 脚本开启严格模式
- 为整个脚本文件开启严格模式,需要在所有语句之前放一个特定语句"use strict"
- 函数开启严格模式
- 需要把"use strict"声明放在函数题所有语句之前
1 <!DOCTYPE html>
2 <html>
3 <head>
4 <meta charset="utf-8">
5 <title></title>
6 </head>
7 <body>
8 <!-- 为整个脚本(script标签)开启严格模式 -->
9 <script type="text/javascript">
10 'use strict';
11 //下面的js代码会按照严格模式执行代码
12 </script>
13 <script type="text/javascript">
14 (function(){
15 'use strict';
16 })()
17 </script>
18 <!-- 为某个函数开启严格模式 -->
19 <script type="text/javascript">
20 function fn(){
21 //此时只是给函数fn开启严格模式
22 'use strict';
23 }
24 function fun(){
25 //里面还是按照普通模式执行
26 }
27 </script>
28 </body>
29 </html>
- 严格模式中的变化
- 变量规定
- 严格模式中,变量都必须先用var声明,然后再使用
- 严禁删除已经声明的变量
1 <!DOCTYPE html>
2 <html>
3 <head>
4 <meta charset="utf-8">
5 <title></title>
6 </head>
7 <body>
8 <!-- 为整个脚本(script标签)开启严格模式 -->
9 <script type="text/javascript">
10 'use strict';
11 //下面的js代码会按照严格模式执行代码
12 //1.变量名必须先声明再使用
13 // num = 1;
14 // console.log(num);// num is not defined
15 //2.我们不能随意删除已经声明好的变量
16 // var num = 10;
17 // delete num;//Delete of an unqualified identifier in strict mode
18
19 </script>
20
21 </body>
22 </html
-
- 严格模式下this指向问题
- 严格模式下全局作用域中的函数this指向的是undefined
- 严格模式下,如果构造函数不加new调用,this就会报错
- 函数变化
- 函数不能有重名的参数
- 函数必须声明在顶层,不允许在非函数代码块内声明函数
3.高阶函数
高阶函数是对其他函数进行操作的函数,它接收函数作为参数或将函数作为返回值输出
1 <!DOCTYPE html>
2 <html>
3 <head>
4 <meta charset="utf-8">
5 <title></title>
6 </head>
7 <body>
8 <script type="text/javascript">
9 //高阶函数-函数可以作为参数传递
10 function fn(a,b,callback){
11 console.log(a+b);
12 callback&&callback();
13 }
14 fn(1,2,function(){
15 console.log("success");
16 });
17 </script>
18 </body>
19 </html>
闭包指有权访问另一个函数作用域中的变量的函数
1 <!DOCTYPE html>
2 <html>
3 <head>
4 <meta charset="utf-8">
5 <title></title>
6 </head>
7 <body>
8 <script type="text/javascript">
9 //闭包(closure)指有权访问另一个函数作用域中变量的函数
10 //闭包:我们fun这个函数作用域 访问了另外一个函数fn里面的局部变量
11 //我们fn 外面的作用域可以访问fn,内部的额局部变量
12 //闭包的主要作用,延伸了变量的作用范围
13 function fn(){
14 var num = 10;
15 function fun(){
16 console.log(num);
17 }
18 return fun;
19 }
20 var f = fn();
21 /*
22 类似于
23 f = function fun(){
24 console.log(num);
25 }
26 */
27 f();
28 </script>
29 </body>
30 </html>
1 <!DOCTYPE html>
2 <html>
3 <head>
4 <meta charset="utf-8">
5 <title></title>
6 </head>
7 <body>
8 <ul class="nav">
9 <li>榴莲</li>
10 <li>臭豆腐</li>
11 <li>鲱鱼罐头</li>
12 <li>大猪蹄子</li>
13 </ul>
14 <script type="text/javascript">
15 //闭包应用-点击li输出当前li的索引号
16 var lis = document.querySelectorAll(".nav li");
17 //1.利用动态添加属性的方式
18 // for(var i = 0 ; i < lis.length ; i++){
19 // lis.index = i;
20 // lis.onclick = function(){
21 // console.log(this.index);
22 // }
23 // }
24 //2.利用闭包的方式得到当前小li的索引号
25 for(var i = 0 ; i < lis.length ; i++){
26 //利用for循环创建了4个执行函数
27 (function(i){
28 lis.onclick = function(){
29 console.log(i);
30 }
31 })(i);
32 }
33 </script>
34 </body>
35 </html>
1 <!DOCTYPE html>
2 <html>
3 <head>
4 <meta charset="utf-8">
5 <title></title>
6 </head>
7 <body>
8 <ul class="nav">
9 <li>榴莲</li>
10 <li>臭豆腐</li>
11 <li>鲱鱼罐头</li>
12 <li>大猪蹄子</li>
13 </ul>
14 <script type="text/javascript">
15 //闭包应用-3秒钟之后,打印所有li元素的内容
16 var lis = document.querySelectorAll(".nav li");
17 for(var i = 0 ; i < lis.length ; i++){
18 (function(i){
19 setTimeout(function(){
20 console.log(lis.innerText);
21 },3000);
22 })(i)
23 }
24 </script>
25 </body>
26 </html>
1 <!DOCTYPE html>
2 <html>
3 <head>
4 <meta charset="utf-8">
5 <title></title>
6 </head>
7 <body>
8 <script type="text/javascript">
9 //闭包应用-计算打车价格
10 //打车起步价13(3公里内),之后每多一公里增加5块钱,用户输入公里数就可以计算打车价格
11 //如果有拥堵情况,总价格多收取10块钱拥堵费
12 var res = (function(){
13 var start = 13;//起步价
14 var total = 0;//总价
15 return {
16 price: function(n){//正常价格
17 if(n <= 3)
18 total = 13;
19 else{
20 total = (n-3)*5 + 13;
21 }
22 return total;
23 },
24 yongdu: function(flag){//拥堵价格
25 return flag ? total+10 : total;
26 }
27 }
28 })();
29 console.log(res.price(5));
30 console.log(res.yongdu(true));
31 </script>
32 </body>
33 </html>
- 闭包总结
- 闭包是一个函数(一个作用域可以访问另一个函数的作用域)
- 闭包的作用:延伸变量的作用范围
4.递归
如果一个函数可以在内部调用其本身,这个函数就是递归函数
1 <!DOCTYPE html>
2 <html>
3 <head>
4 <meta charset="utf-8">
5 <title></title>
6 </head>
7 <body>
8 <script type="text/javascript">
9 //递归函数:函数内部自己调用自己,这个函数就是递归函数
10 //由于递归很容易发生“栈溢出”错误,所以必须要加退出条件(return)
11 var num = 0;
12 function fn(){
13 console.log("bbh");
14 if(num == 5){
15 return;//递归函数里面必须添加退出条件
16 }
17 num++;
18 fn();
19 }
20 fn();
21 </script>
22 </body>
23 </html>
1 <!DOCTYPE html>
2 <html>
3 <head>
4 <meta charset="utf-8">
5 <title></title>
6 </head>
7 <body>
8 <script type="text/javascript">
9 //递归函数:函数内部自己调用自己,这个函数就是递归函数
10 //由于递归很容易发生“栈溢出”错误,所以必须要加退出条件(return)
11 function fn(n){
12 if(n == 1){
13 return 1;
14 }
15 return n*fn(n-1);
16 }
17 var res = fn(3);
18 console.log(res);
19 </script>
20 </body>
21 </html>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<script type="text/javascript">
//利用递归函数求斐波那契序列
//用户输入一个数字n,就可以求出这个数字对应的兔子序列值
function fn(n){
if(n == 1 || n == 2){
return 1;
}else{
return fn(n-1)+fn(n-2);
}
}
console.log(fn(8))
</script>
</body>
</html>
1 <!DOCTYPE html>
2 <html>
3 <head>
4 <meta charset="utf-8">
5 <title></title>
6 </head>
7 <body>
8 <script type="text/javascript">
9 //根据id返回数据对象
10 var data = [{
11 id: 1,
12 name: '家电',
13 goods: [{
14 id: 11,
15 gname: '冰箱'
16 }, {
17 id: 22,
18 gname: '洗衣机',
19 goods: [{
20 id: 2201,
21 gname: '滚筒洗衣机'
22 },
23 {
24 id: 2202,
25 gname: '壁挂洗衣机'
26 }
27 ]
28 }]
29 },
30 {
31 id: 2,
32 name: '服饰'
33 }
34 ]
35 //我们想要做输入id号,就可以返回数据对象
36 //1.利用foreach遍历里面的每一个对象
37 function getId(json, id) {
38 var res = {};
39 json.some(function(value) {
40 if (value.id == id) {
41 res = value;
42 return value.id == id;
43 } else if(value.goods && value.goods.length > 0){
44 res = getId(value.goods, id);
45 }
46 });
47 return res;
48 }
49 console.log(getId(data, 2202));
50 </script>
51 </body>
52 </html>
- 深拷贝和浅拷贝
- 浅拷贝知识拷贝一层,更深层次对象级别的只拷贝引用
- 深拷贝拷贝多层,每一级别的额数据都会拷贝
- 浅拷贝
1 <!DOCTYPE html>
2 <html>
3 <head>
4 <meta charset="utf-8">
5 <title></title>
6 </head>
7 <body>
8 <script type="text/javascript">
9 var obj = {
10 id: 1,
11 name: 'bbh',
12 msg: {
13 age:18
14 }
15 };
16 var o = {};
17 // for(var k in obj){
18 // o[k] = obj[k];
19 // }
20 // o.msg.age = 30;
21 // console.log(o);
22 // console.log(obj);
23 console.log("---------------------");
24 //ES6提供的浅拷贝语法糖
25 //注意:浅拷贝只拷贝一层,当拷贝的数据里还存在复杂类型数据时,
26 //只会拷贝其地址,对数据进行修改时会影响到原来的数据
27 Object.assign(o,obj);
28 o.msg.age = 30;
29 console.log(obj);
30 console.log(o);
31 </script>
32 </body>
33 </html>
1 <!DOCTYPE html>
2 <html>
3 <head>
4 <meta charset="utf-8">
5 <title></title>
6 </head>
7 <body>
8 <script type="text/javascript">
9 var obj = {
10 id: 1,
11 name: 'bbh',
12 msg: {
13 age:18
14 },
15 sing: function(){
16
17 }
18 };
19 var o = {};
20 function fn(obj,o){
21 for(k in obj){
22 //判断属性值属于哪种数据类型
23 //1.获取属性值 obj[k]
24 //2.判断这个值是否为数组
25 //3.判断是否为对象
26 if(obj[k] instanceof Array){
27 o[k] = [];
28 fn(obj[k],o[k]);
29 }else if(obj[k] instanceof Object){
30 o[k] = {};
31 fn(obj[k],o[k]);
32 }else{
33 o[k] = obj[k];
34 }
35 }
36 }
37 //深拷贝封装函数
38 fn(obj,o);
39 o.msg.age = 30;
40 console.log(o);
41 console.log(obj);
42 </script>
43 </body>
44 </html>
来源:https://www.cnblogs.com/Miraitowa-fan/p/16166971.html |