函数
1. 函数的声明
1.1 Function 构造函数
除了使用 function
关键字和 函数表达式对函数声明外,Function
构造函数也可以声明函数。
const monty = new Function('m','m','return m*n');
// 上述声明 等同于
function monty(m,n){
return m*m;
}
// 也可以写成
const monty = function(m,n){
return m*m;
}
除此之外,Function
构造函数还有其他用法。我们可以看出,当我们在使用 Function
构造函数声明函数的时候,传入的是字符串,那么我们就可以用这一特性对字符串进行操作。
列:给定一个可序列化的对象 obj
,请不使用遍历或递归输出 a.b.c 的值。
const obj = {
a:{
b:{
c:'Monty'
}
}
};
const getCValue = function(path){
return new Function(`return ${JSON.stringify(obj)}.${path}`)()
}
const cValue = getCValue('a.b.c');
console.log(cValue); // Monty
由此看出,有点像 eval
方法,Function
构造函数也可以处理可被其接受的字符串。
当然了,Function
构造函数 肯定还有其他的用途,这里先不做介绍了,待以后有需要再进行补充。
2. 函数的其他知识点
2.1 闭包
闭包是Javascript语言的一个重要特色,很多高级应用都要依靠它来实现。
理解闭包的前提是理解 JavaScript 变量的作用域。
JavaScript 有两种作用域:
- 全局作用域
- 函数作用域
函数内部可以直接读取全局变量,但是函数外部是无法读取函数内部声明的变量。
let p1 = 'Monty'
function func(){
console.log(p1);
}
func(); // Monty
function func2(){
let p2 = 'Monty';
}
console.log(p2); //Uncaught ReferenceError: p2 is not defined
如上所述 func2
方法,如果我们需要获得 p2
这个变量,需要怎么办呢?
既然直接无法获取,那么我们可以变通一下,在 func2
方法中再声明一个方法不就可以获取到了嘛。
function func2(){
let p2 = 'Monty';
return function func3(){
return p2;
}
}
const p2Value = func2()();
console.log(p2Value); // Monty
简直完美有没有!这时候我们就可以说 :
func3
方法是func2
方法的闭包。
那什么是闭包呢?其实我们可以简单的理解为:
闭包就是定义在一个函数内部的函数
闭包还有一个特点,就是他可以保存运行状态。让我们来看下面的例子
function func4() {
let p3 = 'Monty';
return function func5(p4) {
return p3 += p4;
}
}
const f4Closure = func4();
f4Closure(' Ma'); // Monty Ma
f4Closure(' is me.'); // Monty Ma is me.
除此之外,我们还可以用它封装对象的私有属性和私有方法。
function Person(name) {
let _age;
function setAge(n) {
_age = n;
}
function getAge() {
return _age;
}
return {
name: name,
getAge: getAge,
setAge: setAge
};
}
var p1 = Person('Monty');
p1.setAge(25);
p1.getAge() // 25
由此可见,我们可以得出闭包的用途:
- 读取函数内部的变量
- 保存函数内部变量在内存中
- 封装对象的私有属性或私有方法
我们思考一下,外层函数每次运行都会生成一个新的闭包,而这个闭包又会保存其外层函数的内部变量,如果我们多次调用生成新的闭包,势必会造成大量的内存消耗,很可能会导致网页性能问题。所以闭包虽好,但是使用的时候请不要滥用。