闭包
- 只要这个函数调用后没执行完,该执行上下文会一直存在,不会被垃圾回收
- 闭包:解决外部变量无法访问内部变量,闭包涉及到的变量会一直存在。
- 如果多人引用,因为函数作用域的独立性,不会互相干扰
new Function
创建的函数,是全局执行上下文
function test() {
var i = 0;
return function () {
var j = 0;
++i, ++j;
console.log(i * j);
}
}
var f1 = test();
f2 = test();//独立
f1();//1
f1();//2 因为闭包,所以引用变量一直存在
f2();//1 函数作用域的独立性
防抖(频繁清空定时器)
频繁操作后,只获取最后
t.oninput = debounce(fn, 1000)
function debounce(fn, delay) {
let time;//闭包变量,一直存在
return function(){
//频繁操作,频繁清空计时器
clearTimeout(time);
time=setTimeout(() => {
//...执行代码
}, delay);
}
}
节流(开锁,关锁)
频繁操作,有规律的获取(开锁,关锁)
function throttle(fn,wait){
let time;
return ()=>{
if(!time){
timer = setTimeout(()=>{//关锁
//...执行代码
timer = null;//开锁
},delay);
}
}
}
function throttle(fn,wait){
let old=0;
return ()=>{
let now=new Date().valueOf();
if(now-old>wait){
//...执行代码
old=now;
}
}
}
递归
-
递归必须有一个跳出条件
-
每一层递归如果需要进行累计操作,需要return一个值,不然就会undefined
-
函数作用域:
- 会保存当前函数内的信息
- 每个函数都是独立的
-
可以使用尾递归进行优化
-
递归其实是个回溯的过程,从返回的位置往回执行
当一个函数进行嵌套调用时
- 当前函数被暂停
- 将当前函数的执行上下文依次入栈
尾递归优化:将每次的结果携带
//优化前
function dg(n){
if(n===1)return 1;
return n*dg(n-1)
}
dg(5)
//优化后 O(1)
function dg(n,total){
if(n===1)return total;
return dg(n-1,n*total) //将结果携带
}
dg(5,1)
this
-
this是动态的,谁调用this就指向谁
-
多层调用取决于最近的
-
没有明确调用者,则为全局调用
-
-
箭头函数,this指向外层的this(静态指向)
-
立即执行函数,this指向全局
修改this
let obj1={
name:'obj1_name',
print:function(){
return()=>console.log(this.name)
}
}
let obj2={name:'obj2_name'}
obj1.print()() //obj1_name
obj1.print().call(obj2) //obj1_name
obj1.print.call(obj2)() //obj2_name
- 没有参数时,this指向全局
- call性能更好
.call(this,参数); //性能更好
.apply(this,[参数]);
.bind(this,参数)(); //bind会返回新函数
箭头函数
- 箭头函数不能使用arguments、super和new.target,但可以使用rest参数访问参数列表
arguments
是类数组,可迭代对象
- 箭头函数没有prototype属性,不能用作构造函数
- 箭头函数的this指向其所在作用域(this是静态的)
- 普通函数可以使用call修改this。但箭头函数不行(因为他根本没有自己的this
展开运算符
rest参数
-
用于接受函数参数,只能放在末尾,并返回一个数组(arguments是类数组)
function fn(a,...args){ console.log(a,args);//1 [2, 3, 4, 5] } fn(1,2,3,4,5)
-
也可以用于解构赋值
let [a,...args]=[1,2,3,4,5] console.log(a,args);//1 [2, 3, 4, 5]
spread语法
- 将数组 | 字符串 | 对象在语法层面展开
- 是浅拷贝
- 字符串:展开为字符串数组
- 函数调用传参
fn(...arr)
数组
- 展开数组
[...arr]
- 数组合并
[...arr,...arr1]
- 将类数组传为数组
[...arguments]
对象
-
展开对象
{...obj}
-
具有iterator接口的对象也可以展开
var m = new Map(); m.set(1,1) m.set(2,2) var arr = [...m] // [[1,1],[2,2]]
-
对象合并
{...obj,...obj1}
-
属性覆盖
{...obj,"name":"bob"}
解构赋值
- 将属性 | 值从对象 | 数组中取出,赋值给其他变量。
- 解构接收的变量必须声明
- 可以嵌套解构,只要格式对应就行
数组
- 解构:
var [one, two, three] = [1,2,3];
- 设置默认值:
var [a=5, b=7] = [1];
- 交换变量值:
[a, b] = [b, a];
- 忽略值:
var [a, , b] = f()
- 使用
rest
参数:var [a, ...b] = [1, 2, 3]
- 使用正则解构
对象
- 解构:
var {a, b} = {a: 1, b: 2}
- 起别名:
var {a: A, b: B} = {a: 1, b: 2}
- 默认值:
var {a = 10, b = 20} = {a: 1};
高阶函数
满足以下一种情况:
- 函数接受的参数还是函数
- 函数返回的还是函数(闭包)
比如:setTImeout,Promise
函数柯里化
- 通过函数调用继续返回函数
- 将多个参数变成单个参数
function(a,b,c){}
//柯里化
function(a){
return function(b){
return function(c){
return a+b+c
}
}
}
工厂函数
调用该函数,内部会实例化对象并返回