JavaScript的闭包及函数重载

JavaScript的闭包及函数重载

闭包的概念

什么是闭包

说到JavaScript的闭包,需要先说一说JavaScript的作用域。

JavaScript在ECMA6之前,作用域是只有全局作用域跟函数作用域的。(这里先不涉及let和const)

函数内部可以读取器外部作用域定义的变量,而外部作用域不能直接读取到函数中定义的变量。

eg:

var n = 0;
function f1() {
	console.log(n); // 0
}

f1();

function f2() {
	var a = 1;
}
console.lot(a); // throw error .... undefind
复制代码

上述例子中,函数f1在运行时可以访问到全局作用域定义的变量n。而全局作用域中无法访问到函数f2中定义的变量a。

那么还有一个例子:

var n = 0;
function f1() {
	console.log(n); // 0

	var a = 1;
	function f2() {
		console.log(n); // 0
		console.log(a); // 1
	}

	f2();
}

f1();
复制代码

上述例子中的,函数f1中定义了函数f2,f2能够访问到f1中定义的变量a以及全局作用域中定义的变量n。那么,这可以说明,更里层的函数能够访问到更外层的作用域中定义的变量。而更外层的代码,无法访问到更里层的函数作用域定义的变量。这是JavaScript链式作用域的作用。

那么,如果我们有需要在全局作用域中访问到函数作用域中定义的变量,那应该怎么做呢?

我们发现函数f2是能够访问到f1中定义的变量的。那么将他返回到全局作用域:

function f1() {
	var a = 1;
	
	return function f2() {
		console.log(a);
	}
}

var function2 = f1();
function2(); // 1
复制代码

那么,上述的函数f2,就是一个闭包。

闭包是用于读取其他函数内部变量的函数(取自@阮一峰老师的博客)

闭包的特性

1.闭包可以读取其他函数内部变量。

这个特性这里不再赘述

2.闭包会将函数内部的局部变量存储在内存中

如上一节最后一个例子,函数f2将变量a保存在内存中,然后在被调用时,就能够访问到了。

那么,利用这个特性,我们可以做一个类似于计数器的东西:

eg:

function counter() {
	var a = 1;
	
	return function f1() {
		return a++;
	}
}

var counter1 = f1();
counter1(); // 1
counter1(); // 2
counter1(); // 3
复制代码

这个特性也会导致一个问题,就是如果滥用闭包的话,内存消耗会比较多。

利用闭包来定义私有变量

利用闭包的特性,我们可以利用闭包做私有变量:

var ClassA = function () {
	var a = 0;
	this.getA = function() {
		return a;
	}
	this.setA = function(val) {
		a = val;
	}
}

var objectA = new ClassA();
console.log(objectA.getA()); // 0
objectA.setA(111);
console.log(objectA.getA()); // 111
objectA.a; // error
复制代码

这里的a变量只能被ClassA以及getA和setA访问到。

利用闭包做函数重载

最近学习到了一个在JavaScript中实现函数重载的方法,感觉比较有趣。

众所周知JavaScript的函数的参数是不固定的,所以没办法做函数重载。如果要实现类似于函数重载的方法,比较平常的做法是使用if-elseswitch来判断参数,然后根据传入的参数不同,输出不同的结果。

而最近学习了一个,利用闭包处理的比较干净一些的做法。

1.准备阶段先撸一下需要存放重载函数的类/对象

var object = {};
复制代码

2.定义需要重载的函数。

function sum0(val0) {
	return val0;
}

function sum1(val0, val1) {
	return val0 + val1;
}

function sum2(val0, val1, val2) {
	return val0 + val1 + val2;
}
复制代码

3.然后定义装载重载函数的函数(核心):

function addMethod(object, name, f) {
	// 1. 从object中获取名字为name的函数作为old备用
	var old = object[name];
    // 2. 将object[name]定义为一个新的函数
    object[name] = function() {
        // 3. f.length为函数定义时的参数个数
        // arguments.length为函数调用时的参数个数
        // 如果调用的函数的形参和实参一致,则直接调用。否则,调用old函数
        if (f.length === arguments.length) {  
            return f.apply(this, arguments);    
        } else if (typeof old === "function") {
            return old.apply(this, arguments);    
        }  
    };
}
复制代码

4.装载函数:

addMethod(object, "sum", sum0);
addMethod(object, "sum", sum1);
addMethod(object, "sum", sum2);

console.log(object.sum(1)); // 1
console.log(object.sum(1, 2)); // 3
console.log(object.sum(1, 2, 3)); // 5
复制代码

上述代码使用old存储上一次调用addMethod方法加入的函数。然后通过闭包存储在内存中。使得每次调用add函数时,出现参数不等的情况时能够调用到old,以查找到上一个add进来的函数。最终达到函数重载的目的。


参考:阮一峰老师的JavaScript教程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值