作用域就是当前执行环境的上下文,它限制了变量、函数的有效范围。
在当前作用域下声明的变量、函数只能在当前作用域内以及它嵌套的子作用域内有效。这样避免变量和函数的命名冲突,还可以形成私有数据,从而保证数据不会被外部作用域篡改。
作用域分为全局作用域和局部作用域、块作用域。
全局全局作用域中定义的变量、函数,在任何地方都能访问,在JAVAScript代码中最外层定义的变量、函数,都是在全局作用域中的。
局部作用域可以访问全局作用域或者父级作用域中的变量和函数。
在JavaScript中,函数使用var声明的变量都具有提升机制,就是先引用后声明。
这是因为JavaScript编译器会提前检查代码中的函数和var声明的变量,然后把它们提升到当前作用域的顶部,这样保证代码的正常运行,但是变量的赋值没有被提升。该变量变成了undefined。
用let关键字定义的变量,不能在初始化之前访问的原因是,它的声明被放到了临时隔离区,临时隔离区会在执行块级作用域的第一行代码之前生效。在变量完成初始化之后,才被释放出来。
在变量完成初始化之前,是不能访问临时隔离区的变量。
换句话来说,临时隔离区就是存放变量初始化的过程。
函数式编程,是以函数为核心,每一个操作,通过对函数的组合和复用来形成复杂的业务逻辑。只需要调用一次函数,就完成所有的业务逻辑。
函数式编程中的闭包,指的是一种语法形式和变量查找机制,在一系列的函数嵌套中,所有内部函数都可以访问外部函数以及全局作用域中的变量和函数。
闭包有一个用处:定义私有变量,闭包外面是不能访问内部变量的,这对内部变量起到一个保护作用,调用者只能通过闭包暴露出来的函数或者是对象来对内部变量的修改。
高阶函数就是接收函数作为参数,最终返回一个函数,这样的函数就是高阶函数。
柯里化就是把一个接收多个参数的函数,转化为一系列接收一个参数的子函数。这个过程就是柯里化,比如:通过汇率计算一美元等于多少人民币。
首先我们定义一个函数,接收汇率和美元数量,然后返回计算的结果,代码如下:
function usToCny(amount,rate){
return amount * rate;
}
但是每次计算的时候,都需要传入汇率,我们可以通过柯里化的方式,来简化这个函数,代码如下
function converRate(rate){
return (amount)=> amount * rate;
}
// 普通调用
converRate(6.3)(100)
// 或者是
const uToC = converRate(6.24);
console.log(uToC(100))
方法很多,柯里化仅仅是其中的一种。
函数缓存,就对于比较耗时的函数而言,把已经执行过的函数的结果保存下来作为缓存,如果下次再次需要这个函数的执行结果,那就先判断缓存中是否含有该结果,如果有就不用执行该函数。
一般是把函数的参数列表当作缓存的key,如果第二次调用函数传递相同的参数,就会返回缓存中的结果。
函数缓存,有效提升了代=代码程序的性能,加快相应速度。一般用于变化很少、不依赖外部条件并且很耗时的操作。比如计算斐波那契数列。
这是没有设置缓存的代码:
function fib(n){
if(n<=1)return n;
return fib(n-1)+fib(n-2);
}
const start = new Date().getTime();
console.log(fib(10))
const end = new Date().getTime();
console.log("执行花费时间:",end - start);
在这个例子中,有几个值是计算多次的,这就造成不必要的性能消耗。这就体现了函数缓存的重要性了,我们可以将已经计算过的值保存起来,,在后面的计算中,判断是否有缓存,如果有那么就是直接使用。
上面的例子修改后:
function fib(n){
if(n<=1){return n}
if(fib[n]){return fib[n]}
fib[n] = fib(n-1) + fib(n-2);
return fib(n);
}