JavaScript-18
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
调用方式 | 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>
- 改变函数内部this指向
JavaScript为我们提供了一些函数方法帮助我们改变函数内部this指向问题,常用的有bind()、call()、apply()三种方法
-
- call方法
call方法调用一个对象,简单理解为调用函数的方式,但是它可以改变函数的this指向
-
- apply()方法
- fun.apply(thisArg,[argsArray])
- thisArg:在fun函数运行时指定的this值
- argsArray:传递的值,必须包含在数组里面
- 返回值值就是函数的返回值,因为它必须是调用函数
bind()方法:不会调用函数
- fun.bind(thisArg,arg1,arg2,…)
- thisArg:在fun函数运行时指定this的值
- arg1、arg2:传递其他参数
- 返回由指定的this值和初始化参数改造的原函数拷贝
- apply()方法
<!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>
- bind方法应用
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总结
- 相同点
- 都可以改变函数内部的this指向
- 区别点
- 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就会报错
- 函数变化
- 函数不能有重名的参数
- 函数必须声明在顶层,不允许在非函数代码块内声明函数
- 严格模式下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[i].index = i; 20 // lis[i].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[i].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[i].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>
- 根据id返回数据对象
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>
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通