closure在每次面试中都在伤害我。终于我了解了closure。但是我的问题是,以下这些摘要之间有什么区别?我们应该在哪种情况下使用闭包?
function add(x) {
return function(y) {
return function(z) {
return x + y + z;
}
};
}
console.log(add(1)(2)(3))
简单可以代替闭合,我们可以将三个参数传递给单个方法。
function add(x,y,z) {
return x + y + z;
}
console.log(add(1,2,3))
那我为什么要使用闭包?
答案 0 :(得分:1)
此特定示例显示了启用partial application的咖喱函数。对于单个函数调用而言,它似乎没有用,但它还允许您编写
background-image
当然,如果没有使用function add(x) { return function(y) { return x + y; }; }
const add2 = add(2);
console.log(add2(1)); // 3
console.log(add2(40)); // 42
函数,您可能会使用
add
但这是不必要的冗长。
当然,这只强调了一个封闭的用例,有many many more。
答案 1 :(得分:1)
在此示例中,输出没有实际差异。但是,让我们变得更简单:
function add(a) {
return function(b) {
return a+b;
}
}
console.log(add(1)(2));
function add(a, b) {
return a+b;
}
console.log(add(1, 2));
为简单起见,该函数采用两个参数。一次,您必须在调用时同时传递它们,另一次,您必须一次传递它们。让我们看看这可能有用:
function add(a) {
return function(b) {
return a+b;
}
}
let numbers = [1, 2, 3, 4, 5, 6];
//lets add the same number to all members of the array:
const numberToAdd = 5;
//traditionally
const newArray = []; //make a new array
for (let num of numbers) { //define a loop
newArray.push(num + numberToAdd); //populate the array
}
console.log(newArray);
//functional
const mappedArray = numbers.map(num => num + numberToAdd); //using .map to handle everything
console.log(mappedArray);
//using the function we have
const betterMappedArray = numbers.map(add(numberToAdd));
console.log(betterMappedArray);
因此,通过.map
进行的函数方法更短,更容易,但是可以通过传递函数来进一步改进。在没有add
函数的情况下,您仍然要传递一个函数,而您每次要定义一个新的加法函数 ,您只想向数组中添加一些东西。如果要添加可变数量,则没有add
的情况下,您必须创建两个新功能,这些功能基本上都可以完成相同的事情
function add(a) {
return function(b) {
return a+b;
}
}
let numbers = [1, 2, 3, 4, 5, 6];
console.log("using .map() with new functions");
console.log(
numbers
.map(num => num + 5)
.map(num => num + 10)
);
console.log("using .map() with add()");
console.log(
numbers
.map(add(5))
.map(add(10))
);
如您所见,将所有功能并排放置似乎很浪费。即使将签名设为add(a, b)
,因此它需要两个参数,这意味着您将不得不调用numbers.map(num => add(num, 5))
,但这并不能改善任何情况。
请记住,add
非常简单-您的函数可能更复杂。仍然,通过简单的示例,让我们重新编写示例以显示它如何有用:
function add(a) {
return function(b) {
return a+b;
}
}
const shoppingCart = [
{name: "item1", price: 1},
{name: "item2", price: 2},
{name: "item3", price: 3},
{name: "item4", price: 4},
{name: "item5", price: 5},
{name: "item6", price: 6},
];
const applyHandlingTax = add(5);
const applyShippingTax = add(10);
const numbers = shoppingCart.map(item => item.price); //extract prices from the shopping cart
const finalPrices = numbers
.map(applyHandlingTax)
.map(applyShippingTax);
console.log(finalPrices);
这是一个简单的示例,带有夸张的数字,但是它只是用来说明我们在这里可以做些什么。这在功能上与前面的代码段相同,但是正如您所看到的,我们现在有了业务逻辑,几乎没有任何更改。
applyHandlingTax
定义为添加5
。我们还定义了applyShippingTax
来添加10
。.map
将它们直接应用到我们拥有的结果集上,从而减少了我们必须编写的代码量。 numbers.map(applyHandlingTax).map(applyShippingTax)
正在对每个数字征收运费和手续费。作为开发人员,很明显,您要添加运费和手续费。 add
可以正常工作,那么从定义上看也会起作用-无需测试applyShippingTax
。实际上,没有什么要测试的-函数的主体没有,我们没有为它编写任何逻辑,我们只为函数使用结果。add
并从商品中提取价格。即使这样,也可以像使用add
一样轻松地提取后者,因此我们可以将其应用于 any 种结果集
function extract(name) {
return function(item) {
return item[name];
}
}
const shoppingCart = [
{name: "item1", price: 1},
{name: "item2", price: 2},
{name: "item3", price: 3},
{name: "item4", price: 4},
{name: "item5", price: 5},
{name: "item6", price: 6},
];
const people = [
{name: "Alice", drives: "Audi"},
{name: "Bob", drives: "BMW"},
{name: "Carol", drives: "Citroen"},
{name: "David", drives: "Dodge"},
{name: "Esther", drives: "EDAG"},
{name: "Fred", drives: "Ford"},
];
const prices = shoppingCart.map(extract('price'));
console.log(prices);
const names = people.map(extract('name'));
const cars = people.map(extract('drives'));
console.log(names);
console.log(cars);
即使有一个非常简单的add
示例,我们也可以做得很远。 add
的编写方式称为currying-该函数返回一次另一个函数,而不是一次获取 X 个参数直到满意为止,需要 X-1 。
与其他功能配合使用的功能-要么产生它们(像add
一样),要么消耗它们,或者两者都称为higher-order functions。如果我们使用这些数据并持续地使用它们,则会进入functional programming的领域。不需要使用完全功能的样式来获取这些好处-正如我们在add
中所看到的那样,即使我们正在应用业务规则,您也可以编写一个简单的应用程序而无需使用大量代码。
答案 2 :(得分:0)
'add(1)(2)(3)'和'add(1,2,3)'具有相同的结果。但是前者我可以做很多事情。 让我举一个例子。
function add(x) {
return function(y) {
return function(z) {
return x + y + z;
}
};
}
const WELCOME_POINT = 10;
const VIP_POINT = 20;
function myPointCaculator(currentPoint, predicate) {
if(typeof predicate === 'number')
return currentPoint + predicate;
else if(typeof predicate === 'function') {
return currentPoint + predicate(WELCOME_POINT);
} else {
return currentPoint;
}
}
const eventPoint = add(WELCOME_POINT)(VIP_POINT);
myPointCaculator(WELCOME_POINT, eventPoint);
答案 3 :(得分:0)
这是一个非常综合且几乎没有用的示例。简而言之,您需要闭包,因为Javascript使用了大量基于回调的代码,并且您希望在这些回调中保留对前一个作用域的可访问性:
function foo(bar) {
setTimeout(function () {
alert(bar);
});
}
这里的关闭机制允许alert(bar)
仍然可以访问bar
,即使foo
已经完成执行并且其所有变量都应该超出范围。这就是 closure 的意思,它关闭作用域并保持可用状态。