递归
在函数内部直接或者间接的调用自己就是递归
递归的要素
- 自己调用自己
- 要有结束条件
化归思想
化繁为简,化难为易的过程,化是转化,归是归结。
练习:
- 求前n项和
- 求n!
- 求n的m次方(求幂)
- 斐波那契数列
递归获取后代元素
1 | function getChildren(ele){ |
作用域
什么是作用域?
变量的作用范围就是作用域
什么是词法作用域?(词法作用域又叫静态作用域)
代码在写好的时候,根据代码的书写结构,就可以确定变量的作用范围,这种作用域,就是词法作用域
什么是块级作用域?
使用代码块限定的作用域就是块级作用域,js中没有块级作用域
作用域链
函数可以创建作用域,函数中又可以声明函数,这样就形成了作用域套作用域的连式结构,称作作用域链
变量的搜索原则
- 现在使用变量的作用域中进行查找,如果找到了就直接使用
- 如果没有找到,就去上级作用域链中进行查找,如果找到了就直接使用
- 如果没有找到,就沿着作用域链一直向上查找,直到找到全局作用域
JS代码执行过程
- 预解析
- 执行
变量提升
在js代码预解析的阶段,会将所有的变量声明以及函数声明提升到其所在的作用域的最顶上,这就是变量提升(Hoisting)
变量提升的特殊情况
- 函数同名:都提升,后面的会覆盖前面的
- 函数与变量同名: 只提升函数,忽略变量声明
- 变量提升分作用域
- 变量提升分段(script标签)
- 条件式函数声明: 会被当做函数表达式处理,只提升函数名称,函数体不提升
- 形参的赋值是在变量提升过程之前
闭包
闭包的概念
可以访问独立数据的函数!
闭包要解决的问题
在函数外部无法访问函数内部声明的变量
闭包的基本模型
1 | function outer(){ |
闭包的原理
作用域,变量的访问规则,上级作用域中无法直接访问下级作用域中的变量,但是下级作用域可以直接访问上级作用域中变量
闭包的用途
- 保护变量,增加对于变量赋值的时候的校验逻辑
- 给函数新增一个私有的变量
for循环注册点击事件以及for循环setTimeout的问题
缓存
将数据进行临时的存储,以提升访问效率
常见的缓存
实现jQuery缓存
1 | function createCache(){ |
jQuery的缓存源码
1 | function createCache(){ |
沙箱
1 | (function(window){ |
传参的目的
- 利于代码压缩
- 实现逻辑隔离
沙箱的用途
- 框架
- 组件
- 插件
函数的调用模式
函数调用模式
1 | 函数名(); |
方法调用模式
1 | 对象.方法名(); |
构造函数调用模式
1 | new 函数名(); |
上下文调用模式
工厂模式和寄生模式创建对象(只是调用模式不同)
上下文调用模式
call
1 | 函数名.call(this要指向的对象, arg1..argN); |
apply
1 | 函数名.apply(this要指向的对象, 数组或者伪数组); |
注意事项
- 如果第一个参数为null或者Undefined,this指向window
- 如果第一个参数为值类型的数据,就会将该数据转换成对应的引用类型的数据,再讲this指向该引用类型数据
tip
一般情况下apply方法的传参特性会非常常用!!!
练习
- 转换伪数组
- 求数组最大值
forEach和map
forEach
1 | 数组.forEach(function(value, index, arr){}) |
map
1 | 数组.map(function(value, index, arr){}) |
map的返回值
将每次执行回调函数的返回值,组合成一个新的数组,作为map方法的返回值!
map的练习
- 将数组中的元素转成字符串
- 求最大值
- 生成随机数
Object.defineProperty
用来给对象添加属性的1
2
3
4Object.defineProperty(obj, propertyName, descriptor);
//obj 就是要给谁添加属性
//propertyName 要添加的属性名
//descriptor 属性的描述信息,也就是特性集合,是一个对象哦~
descriptor对象中的属性
- writable 默认为false,表示属性是否可写
- configurable 默认为false, 表示属性是否可以配置(删除)
- enumerable 默认为false, 表示属性是否可以被遍历(for-in)
- value 用来设置属性的值
- get和set方法,和writable一样都可以用来设置属性是否可以写
严格模式
如何开启严格模式
1 |
严格模式中的特点
- 声明变量必须使用var
- 对象的属性不能重名
- 函数的形参名不能重复
- 八进制常量不允许使用
- eval有自己的作用域
案例(歌曲管理,Tab栏切换)
事件兼容性处理
三种注册事件的方式
- onclick简单形式
- addEventListener(type, handler, useCapture)
- attachEvent(type, handler)
addEventListener和attachEvent的区别
- 回调函数中获取事件对象的方式不一样,addEventListener通过回调函数的参数获取,attachEvent通过window.event获取
- 回调函数中的this指向不一致,addEventListener中this指向当前dom对象,attachEvent中this指向window
兼容性处理的通用函数
1 | function registerEvent(ele, type, handler){ |