>  기사  >  웹 프론트엔드  >  앞에서 뒤로 폐쇄

앞에서 뒤로 폐쇄

PHPz
PHPz원래의
2023-09-02 16:09:031157검색

JavaScript에서 클로저는 종종 신비한 예술로 간주됩니다. 일단 마스터하고 나면 정말 놀라운 JavaScript를 작성할 수 있습니다. 이 기사에서는 JavaScript 클로저의 마법에 대해 간략하게 소개합니다.


폐쇄란 무엇인가요?

JavaScript의 주요 사실 중 하나는 모든 것이 객체라는 것입니다. 물론 여기에는 기능도 포함됩니다.

클로저는 함수의 변수가 해결되는 관련 범위를 가진 함수 객체일 뿐입니다.

클로저라는 이름은 내용이 닫혀 있는 방식에서 유래되었습니다. 다음 JavaScript 코드를 고려해보세요:

으아악

좋아하는 콘솔을 켜고 그 나쁜 소년을 실행하면 "이 피자는 모두 페퍼로니지만...햄을 세 조각에 얹어주세요."라는 효과에 대한 맛있는 메시지를 받게 됩니다. 클로저를 마스터하는 데 필수적인 JavaScript입니다.

클로저는 함수 객체입니다

위 코드에는 몇 개의 함수 객체가 있습니까? 음... 우리는 pizzaParty 函数,并且嵌套在该函数中的是 innerFunction。数学并不总是我的强项,但在我的书中 1 + 1 = 2 . 각 함수 개체에는 각 함수의 scope 내에서 해결되는 고유한 변수 세트가 있습니다.

클로저에는 자체 범위가 있습니다

클로저는 범위에 대한 견고한 기초 없이는 완전히 이해될 수 없습니다. JavaScript의 범위 지정 메커니즘을 사용하면 각 함수에 고유한 topping 변수가 있을 수 있습니다. 이 변수가 없으면 페퍼로니가 너무 많거나 햄이 너무 적거나 * 헐떡거릴*... 피자 파티에서 멸치가 나올 수 있습니다. 이 아이디어를 더 잘 설명하기 위해 간단한 예를 사용해 보겠습니다.

앞에서 뒤로 폐쇄

함수는 함수가 정의될 ​​때 적용되는 범위를 사용하여 실행됩니다. 함수가 호출될 때 유효한 범위와는 아무 관련이 없습니다.

변수 도우미는

외부에서 작업합니다.

녹색 화살표는 외부에서 내부로의 접근성을 나타냅니다. 함수 외부 범위에 정의된 변수는 함수 내에서 액세스할 수 있습니다.

pizzaParty 함수에서 pizzaParty 函数中省略 topping 变量,那么我们会收到类似“This Pizza is all about the anchovi”的消息,但由于 pizzaParty 在其自己的范围内有一个 topping 변수를 생략하면 "This Pizza is all about the anchovi"와 같은 메시지가 표시되지만 pizzaParty는 자체 범위에 있으므로 내부에는

변수가 있습니다. 그 짭짤한 바보들은 우리 피자 파티 근처에 절대 오지 않습니다.

innerFunction 内部访问 numSlices 参数,因为它是在上面的范围中定义的 - 在本例中是 pizzaParty 마찬가지로 범위는

입니다.

가변 접근성은 내부에서 작동하지 않습니다

빨간색 화살표는 함수 범위 내의 변수가 해당 함수 외부에서 액세스될 수 없음을 나타냅니다. 이는 변수가 다음 조건 중 하나를 충족하는 경우에만 발생합니다.
  1. var은(는)
  2. 키워드를 사용하고 있습니다.
  3. 변수는 함수 또는 외부 함수의 매개변수입니다.
  4. 이 변수는 중첩된 함수입니다.

var 关键字将导致 JavaScript 在外部函数中设置最接近的命名变量,一直到全局范围。因此,使用我们的示例,无法从 pizzaParty 访问 innerFunction 中的火腿 topping,并且无法在 anchovi 所在的全局范围内访问 pizzaParty 中的意大利辣香肠 topping 변수를 설정할 때

키워드를 생략하면 JavaScript가 전역 범위까지 외부 함수에서 가장 가까운 명명된 변수를 설정하게 됩니다. 따라서 이 예를 사용하면 innerFunction의 ham

pizzaParty에서 액세스할 수 없으며 anchovi가 위치한 전역 범위의 pizzaParty에서 액세스할 수 없습니다. 페퍼로니

.

JavaScript는 어휘 범위를 사용합니다

어휘 범위는 함수가 정의될 ​​때 적용되었던 변수 범위를 사용하여 함수가 실행된다는 것을 의미합니다. 함수가 호출될 때 유효한 범위와는 아무 관련이 없습니다. 이 사실은 클로저의 힘을 활용하는 데 중요합니다.

이제 클로저가 무엇인지, 클로저의 범위가 무엇을 의미하는지 이해했으므로 몇 가지 고전적인 사용 사례를 살펴보겠습니다.

개인정보 보호를 위해 클로저를 사용하세요

클로저는 코드를 대중에게 숨기는

방법입니다. 클로저를 사용하면 외부 세계와 격리된 비공개 멤버를 쉽게 가질 수 있습니다.

으아악

클로저를 사용하면 외부 세계와 격리된 전용 멤버를 쉽게 가질 수 있습니다.

window),这样我们就可以“导出”一个公共函数,但隐藏其他所有函数。因为函数 myPrivateMultiplyFunction 그것을 분석해 봅시다. 우리의 최상위 함수 객체는 익명 함수입니다:

으아악

우리는 이 익명 함수를 즉시 호출합니다. 중첩된 함수인 전역 컨텍스트(myPrivateMultiplyFunction)를 전달하며 이는 클로저 범위 내에서만 존재하므로 이 범위 내 어디에서나 사용할 수 있습니다.

JavaScript는 곱셈 함수 내에서 사용할 수 있도록 비공개 함수에 대한 참조를 유지하지만 클로저 외부에서는 액세스할 수 없습니다 🎜 . 이것을 시도해 봅시다: 🎜
multiply(2,6) // => 12
myPrivateMultiplyFunction(2,6) // => ReferenceError: myPrivateMultiplyFunction is not defined

闭包允许我们定义一个供私人使用的函数,同时仍然允许我们控制世界其他地方所看到的内容。闭包还能做什么?


使用闭包进行元编程

在生成代码时,闭包非常方便。厌倦了记住键盘事件的所有那些烦人的键代码?一种常见的技术是使用键映射:

var KeyMap = {
	"Enter":13,
	"Shift":16,
	"Tab":9,
	"LeftArrow":37
};

然后,在键盘事件中,我们要检查是否按下了某个键:

var txtInput = document.getElementById('myTextInput');
txtInput.onkeypress = function(e) {
	var code = e.keyCode || e.which //usual fare for getting the pressed key
	if (code === KeyMap.Enter) {
	    console.log(txtInput.value);
	}
}

捕捉瞬间

上面的例子并不是最糟糕的,但是我们可以使用元编程和闭包来做出更好的解决方案。使用我们现有的 KeyMap 对象,我们可以生成一些有用的函数:

for (var key in KeyMap) {

	//access object with array accessor to set "dyanamic" function name
	KeyMap["is" + key] = (function(compare) {
		return function(ev) {
			var code = ev.keyCode || ev.which;
			return code === compare;
		}
	})(KeyMap[key]);

}

闭包非常强大,因为它们可以捕获定义它们的函数的局部变量和参数绑定。

此循环为 KeyMap 中的每个键生成一个 is 函数,并且我们的 txtInput.onkeypress 函数变得更具可读性:

var txtInput = document.getElementById('myTextInput');
txtInput.onkeypress = function(e) {
	if(KeyMap.isEnter(e)) {
		console.log(txtInput.value);
	}
}

魔法从这里开始:

KeyMap["is" + key] = (function(compare){
	
})(KeyMap[key]); //invoke immediately and pass the current value at KeyMap[key]

当我们循环 KeyMap 中的键时,我们将该键引用的值传递给匿名外部函数并立即调用它。这将该值绑定到该函数的 compare 参数。

我们感兴趣的闭包是我们从匿名函数内部返回的闭包:

return function(ev) {
	var code = ev.keyCode || ev.which;
	return code === compare;
}

请记住,函数是在定义函数时的作用域内执行的。 compare 参数绑定到循环迭代期间到位的 KeyMap 值,因此我们的嵌套闭包能够捕获它。我们及时拍摄当时有效范围的快照。

我们创建的函数允许我们在每次想要检查关键代码时跳过设置 code 变量,现在我们可以使用方便、可读的函数。


使用闭包扩展语言

至此,应该相对容易看出闭包对于编写一流的 JavaScript 至关重要。让我们应用我们对闭包的了解来增强 JavaScript 的一种原生类型(惊呼!)。我们将重点放在函数对象上,让我们增强本机 Function 类型:

Function.prototype.cached = function() {
	var self = this, //"this" refers to the original function
		cache = {}; //our local, lexically scoped cache storage
	return function(args) {
		if(args in cache) return cache[args];
		return cache[args] = self(args);
	};
};

这个小宝石允许任何函数创建其自身的缓存版本。您可以看到该函数返回一个函数本身,因此可以像这样应用和使用此增强功能:

Math.sin = Math.sin.cached();
Math.sin(1) // => 0.8414709848078965
Math.sin(1) // => 0.8414709848078965 this time pulled from cache

注意发挥作用的结束技巧。我们有一个本地 cache 变量,该变量保持私有并与外界屏蔽。这将防止任何可能使我们的缓存失效的篡改。

返回的闭包可以访问外部函数的绑定,这意味着我们能够返回一个可以完全访问内部缓存以及原始函数的函数!这个小函数可以为性能带来奇迹。这个特定的扩展被设置为处理一个参数,但我很想看到您对多参数缓存函数的尝试。


野外关闭

作为额外的好处,让我们看一下闭包的一些实际用途。

jQuery

有时,著名的 jQuery $ 工厂不可用(例如 WordPress),而我们希望以通常的方式使用它。我们可以使用闭包来允许内部函数访问我们的 $ 参数绑定,而不是使用 jQuery.noConflict

(function($){
	$(document).ready(function(){
		//business as usual....
	});
})(jQuery);

骨干.js

在大型 Backbone.js 项目中,将应用程序模型设为私有,然后在主应用程序视图上公开一个公共 API 可能会更有利。使用闭包,您可以轻松实现此隐私。

(function(exports){

var Product = Backbone.Model.extend({
    urlRoot: '/products',
});

var ProductList = Backbone.Collection.extend({
    url: '/products',
    model: Product
});

var Products = new ProductList;

var ShoppingCartView = Backbone.View.extend({

    addProduct: function (product, opts) {
        return CartItems.create(product, opts);
    },

    removeProduct: function (product, opts) {
        Products.remove(product, opts);
    },

    getProduct: function (productId) {
        return Products.get(productId);
    },

    getProducts: function () {
        return Products.models;
    }
});

//export the main application view only
exports.ShoppingCart = new ShoppingCartView;

})(window);

结论

快速回顾一下我们所学到的知识:

  • 闭包只不过是一个具有作用域的函数对象。
  • 闭包因其“关闭”其内容的方式而得名。
  • 闭包在 JavaScript 的词法范围上带来了巨大的收益。
  • 闭包是 JavaScript 中实现隐私的方式。
  • 闭包能够捕获外部函数的局部变量和参数绑定。
  • JavaScript 可以通过一些闭包魔法进行强大的扩展。
  • 闭包可以与许多您喜爱的库一起使用,让它们变得更酷!

非常感谢您的阅读!随意问任何问题。现在让我们享受披萨派对吧!

위 내용은 앞에서 뒤로 폐쇄의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.