day19高级函数
1.回顾
2.闭包函数
2.1基础使用
2.2使用场景
-
扩大变量的作用域范围
// 1.扩大变量的作用域范围的时候 function fun1() { var b = "局部变量b"; function fun2() { return b; } return fun2; } var res = fun1(); var newB = res(); console.log(newB);//"局部变量b" newB = null;//手动释放
-
在for循环添加事件中,可以拿到正确的下标
/ 2.可以解决在for循环添加事件中不能得到正确下标 // 面试题1 var arr = []; for (var i = 0; i < 10; i++) { arr.push(function () { console.log(i) }) } // for的作用就是给arr追加函数 并没有执行函数 i最后一次的值是10 // [f,f,f,f,f,f,f,f,f] console.log(arr[4]);//funtion(){console.log(i)} arr[5]();//10 // 怎么修改 arr[5]() 输出5 利用闭包函数解决这个问题 var arr = []; for (var i = 0; i < 10; i++) { (function (i) {//形参 console.log(i);//0 1 2 3.....9 arr.push(function () { console.log(i);//0 1 2 3....9 }) })(i)//实参 下标i } console.log(arr[5]);//function(){console.log(5)} arr[5]();//5 // 面试题2 var li = document.getElementsByTagName("li"); for (var i = 0; i < 10; i++) { li[i].onclick = function () { console.log(i);//10 } } //i最后一次的值10 // 利用闭包函数 点击第几个li就输出对应下标 for (var i = 0; i < 10; i++) { (function (i) {//形参i // console.log(i);//0 1 2 3 4.....9 li[i].onclick = function () { console.log(i);//0 1 2 3 4 5....9 } })(i)//for循环中的i }
-
模拟私有变量
// 3.模拟私有变量 // 构造函数 function Student() { // 私有变量必须通过函数返回出去 var name = "小张" function get() { return name; } return get; } var res = new Student();//调用构造函数 var res1 = res(); console.log(res1);//"小张"
3.递归函数
-
什么是递归:函数内部调用函数本身
-
递
-
函数自己调用自己
-
-
归
-
递归函数中的结束条件,一定要有结束条件,结束条件放在函数的最前面
-
-
==报错信息:Maximum call stack size exceeded栈溢出,是因为没有写结束条件==
<script> // 1.6! 6*5*4*3*2*1 /* 6! = 6*5! 5! = 5*4! 4! = 4*3! 3! = 3*2! 2! = 2*1! 1! = 1 n! = n*(n-1)! 结束条件 n=1 就结束了 注意:Maximum call stack size exceeded栈溢出,是因为没有写结束条件 */ // 阶乘函数 function jc(n) {//6 if (n == 1) return 1; return n * jc(n - 1) } var res = jc(10); console.log(res);
4.快速排序
-
快排思路
-
1.找数组中中间的值 splice(Math.floor( arr.length / 2),1)[0]
-
2.定义两个空数组 left right var left = [] var right = []
-
3.拿数组中的元素依次和中间值作比较 比中间值小的放入left数组 比中间值大的放入right数组
-
4.将left数组和中间值及right数组 组合成一个新的数组
-
==结束条件:当数组元素只有一个值或者空数组的时候就结束了 arr.length<=1==
-
function quick(arr) {//arr是比较的数组 // 归:结束条件 if (arr.length <= 1) return arr; // 1.找数组中中间的值 splice(Math.floor( arr.length / 2),1)[0] var middle = arr.splice(Math.floor(arr.length / 2), 1)[0]; console.log(middle); // 2.定义两个空数组 left right var left = []; var right = []; // 3.拿数组中的元素依次和中间值作比较 比中间值小的放入left数组 比中间值大的放入right数组 for (var i = 0; i < arr.length; i++) { if (arr[i] < middle) { left.push(arr[i]); } else { right.push(arr[i]); } } return quick(left).concat(middle, quick(right)) }
5.事件频繁触发
-
为了减少事件频繁发生的问题 我们可以使用防抖和节流解决
5.1防抖
-
防抖的原理:利用闭包函数,在事件处理函数中添加一个定时器,在定时器延迟一定的时候再执行代码,如果定时器没有走完又去触发该事件 从头开始计时(清除原先的定时器,从新定义一个)
var oDiv = document.getElementsByTagName("div")[0]; // 1.基础操作 oDiv.onmousemove = function () { oDiv.innerHTML++; } // 2.使用防抖减少事件执行的次数 var timer; oDiv.onmousemove = function () { //怎么去判断定时器有没有执行完 根据判断timer值 if (timer) { clearTimeout(timer); } timer = setTimeout(function () { oDiv.innerHTML++; }, 500) }
-
函数封装
// 3.防抖函数封装 function debounce(fun, wait) { var timer; function show() { //怎么去判断定时器有没有执行完 根据判断timer值 if (timer) { clearTimeout(timer); } timer = setTimeout(fun, wait) } return show; } oDiv.onmousemove = debounce(function () { oDiv.innerHTML++ }, 500)
5.2节流
-
节流的原理:利用闭包函数,在事件处理函数中添加一个定时器,延迟一定的时间执行代码。在定时器执行过程中 事件状态是禁止的 等定时器完成。事件状态解开
var oDiv = document.getElementsByTagName("div")[0]; // 1.基础操作 oDiv.onmousemove = show function show() { oDiv.innerHTML++; } // 2.节流减少事件触发的频率 oDiv.onmousemove = show; var timer;//初始值undefined function show() { // 怎么判断定时器有没有执行完 if (timer) return; timer = setTimeout(function () { oDiv.innerHTML++; timer = undefined; }, 500) }
-
函数封装
// 3.函数封装 function throttle(fun, wait) { var timer;//初始值undefined function show() { //怎么判断定时器有没有执行完 if (timer) return; timer = setTimeout(function () { fun();//要做的事情有很多很多 所以放入到一个函数中 timer = undefined; }, wait) } return show; } oDiv.onmousemove = throttle(function () { oDiv.innerHTML++ }, 500)
6.面向对象
编程思想有两种
-
面向过程:一步一步分析实现功能 注重的是过程
-
面向对象:不管滚成是啥样的,只看结果 注重是结果
有一天你想吃鱼香肉丝了,怎么办呢?你有两个选择 1、自己买材料,肉,鱼香肉丝调料,蒜苔,胡萝卜等等然后切菜切肉,开炒,盛到盘子里。注重过程 2、去饭店,张开嘴:老板!来一份鱼香肉丝! 注重结果 看出来区别了吗?这就是1是面向过程,2是面向对象。
-
面向对象核心:就是对象
-
面向对象的组成
-
方法:函数,一些具有行为的动作
-
属性:描述性的内容 静态的
-
-
特点
-
封装
-
继承
-
多态
-
6.1面向对象的创建
1.字面量创建
==缺点:只适用于单个对象的创建==
var obj = { // 属性 "name": "张三", "age": 20, // 方法 "work": function () { console.log("敲代码") } } // 缺点:只适用于单个对象的创建 var obj1 = { // 属性 "name": "赵四", "age": 30, // 方法 "work": function () { console.log("敲代码") } }
2.使用new 关键字创建
==缺点:代码冗余==
// 2.使用new关键字创建 var obj = new Object(); // 往空对象中添加属性和方法 // 属性 obj.name = "王五"; obj.age = 20; // 方法 obj.work = function () { console.log("敲代码") } console.log(obj);//{name: '王五', age: 20, work: ƒ} console.log(obj.name); obj.work(); // 缺点:代码冗余
3.工厂模式创建
==缺点:类识别不清==
// 3.工厂模式创建 这个函数就是用来创建人这个类(对象) function createObj(name, age) { //原材料 var obj = new Object(); // 加工 添加属性和方法 obj.name = name; obj.age = age; obj.work = function () { console.log("敲代码"); } // 出厂 return obj } // 创建一个人 var person1 = createObj("张三", 20); console.log(person1); // 创建一个人 var person2 = createObj("李四", 30); console.log(person2); // 缺点:类识别不清 var dog1 = createObj("大黄", 3); console.log(dog1);