전역 변수는 시스템 전체에 걸쳐 종속성이 있는 개체용으로 예약되어야 하며 해당 이름 지정은 모호성을 피하고 이름 지정 충돌 위험을 최소화해야 합니다. 실제로 이는 꼭 필요한 경우가 아니면 전역 개체를 생성하지 않아야 함을 의미합니다.
그런데 뭐, 이미 알고 계셨겠지만...
그래서 어떻게 하셨나요? 전통적인 접근 방식에서는 전역을 제거하는 가장 좋은 전략은 기본 모듈 및 하위 시스템의 실제 네임스페이스 역할을 하는 소수의 전역 개체를 만드는 것이라고 말합니다. 네임스페이스에 대한 여러 접근 방식을 살펴보고 James Edwards의 최근 기사를 기반으로 생각해낸 우아하고 안전하며 유연한 솔루션으로 마무리하겠습니다.
저는 静态命名空间
를 네임스페이스 태그가 실제로 하드 코딩된 솔루션을 가리키는 포괄적인 용어로 사용합니다. 예, 한 네임스페이스를 다른 네임스페이스에 재할당할 수 있지만 새 네임스페이스는 이전 네임스페이스와 동일한 개체를 참조합니다.
가장 기본적인 방법입니다. 이는 매우 장황한 내용이므로 이러한 네임스페이스의 이름을 바꾸려면 수행해야 할 작업이 있습니다. 하지만 안전하고 명확합니다.
var myApp = {} myApp.id = 0; myApp.next = function() { return myApp.id++; } myApp.reset = function() { myApp.id = 0; } window.console && console.log( myApp.next(), myApp.next(), myApp.reset(), myApp.next() ); //0, 1, undefined, 0
this
를 사용하여 형제 속성을 참조하면 향후 유지 관리가 더 쉬워질 수도 있지만 네임스페이스의 메서드가 재할당되는 것을 막을 수 있는 방법이 없기 때문에 이는 약간 위험합니다.
var myApp = {} myApp.id = 0; myApp.next = function() { return this.id++; } myApp.reset = function() { this.id = 0; } myApp.next(); //0 myApp.next(); //1 var getNextId = myApp.next; getNextId(); //NaN whoops!
이제 네임스페이스 이름을 한 번만 참조하면 되므로 나중에 이름을 변경하는 것이 더 간단합니다(네임스페이스를 반복적으로 참조하지 않았다고 가정). this
값이 "놀랍게" 될 수 있는 위험은 여전히 존재합니다. 그러나 객체 리터럴 구조에 정의된 객체가 재할당되지 않을 것이라고 가정하는 것이 더 안전합니다.
최근에는模块模式
사용하고 있습니다. 논리는 모듈의 공용 인터페이스를 나타내는 개체를 반환하는 메서드 래퍼(일반적으로 자체 호출)에 의해 전역 범위에서 격리됩니다. 이 메서드를 즉시 호출하고 결과를 네임스페이스 변수에 할당함으로써 이 명명된 변수에 모듈의 API를 잠급니다. 또한 반환 값에 포함되지 않은 모든 변수는 항상 비공개로 유지되며 해당 변수를 참조하는 공개 메서드에만 표시됩니다.
var myApp = { id: 0, next: function() { return this.id++; }, reset: function() { this.id = 0; } } window.console && console.log( myApp.next(), myApp.next(), myApp.reset(), myApp.next() ) //0, 1, undefined, 0
위의 객체 리터럴 예와 마찬가지로 네임스페이스 이름은 쉽게 변경할 수 있지만 추가적인 이점이 있습니다. 객체 리터럴은 클래스 4입니다. 이는 모두 속성 할당에 관한 것이며 논리를 지원할 여지가 없습니다. 게다가 모든 속성은 초기화되어야 하며, 속성 값은 객체 간에 쉽게 참조될 수 없습니다(따라서 예를 들어 내부 클로저 는 불가능합니다). 모듈 패턴에는 위의 제약 사항이 없으며 추가적인 개인 정보 보호 이점을 제공합니다.
이 섹션을 命名空间注入
이라고 부를 수도 있습니다. 네임스페이스는 메서드 래퍼 内部
를 직접 참조하는 프록시로 표시됩니다. 즉, 더 이상 네임스페이스에 할당된 반환 값을 래핑할 필요가 없습니다. 이는 네임스페이스 정의를 더욱 유연하게 만들고 독립적인 네임스페이스(또는 전역 컨텍스트)에 존재하는 모듈의 여러 독립적 인스턴스를 가질 수 있도록 합니다. 동적 네임스페이스는 직관적이고 읽기 쉽다는 추가 이점과 함께 모듈 패턴의 모든 기능을 지원합니다.
여기에서는 네임스페이스를 자체 호출 메서드에 매개변수로 전달합니다. id
변수는 context
에 할당되지 않았기 때문에 비공개입니다.
var myApp = (function() { var id= 0; return { next: function() { return id++; }, reset: function() { id = 0; } }; })(); window.console && console.log( myApp.next(), myApp.next(), myApp.reset(), myApp.next() ) //0, 1, undefined, 0
context
를 전역 개체로 설정할 수도 있습니다(한 단어만 변경하면 됩니다!). 이는 라이브러리 소유자에게 큰 자산입니다. 기능을 자체 호출 함수로 래핑하고 사용자가 글로벌인지 여부를 결정하도록 할 수 있습니다(John Resig는 JQuery를 작성할 때 이 이론을 초기에 채택한 사람이었습니다).
this
를 네임스페이스 프록시로 사용James Edwads의 최근 기사가 제 관심을 끌었습니다. "내가 가장 좋아하는 JavaScript 디자인 패턴"은 모듈 패턴에도 의존할 수 있다고 생각하는 많은 논평자들에 의해 분명히 오해되었습니다. 이 기사는 다양한 기술을 장려하지만(아마도 독자를 혼란스럽게 할 수 있음) 그 핵심에는 내가 수정하여 네임스페이스 도구로 제시한 약간의 천재성이 있습니다.
이 패턴의 장점은 단순히 언어가 설계된 방식대로 사용된다는 것입니다. 그 이상도 그 이하도, 기회주의도, 부정행위도 없습니다. 게다가 네임스페이스는 this
키워드(주어진 실행 컨텍스트 내에서 변경할 수 없음)를 통해 주입되므로 실수로 수정될 수 없습니다.
var myApp = {}; (function(context) { var id = 0; context.next = function() { return id++; }; context.reset = function() { id = 0; } })(myApp); window.console && console.log( myApp.next(), myApp.next(), myApp.reset(), myApp.next() ) //0, 1, undefined, 0
더 좋은 점은 apply
(및 call
) API가 컨텍스트와 매개변수로부터 자연스러운 분리를 제공하므로 모듈 생성자에게 추가 매개변수를 전달하는 것이 매우 깔끔합니다. 다음 예에서는 이를 설명하고 여러 네임스페이스와 독립적으로 모듈을 실행하는 방법을 보여줍니다.
var myApp = {}; (function(context) { var id = 0; context.next = function() { return id++; }; context.reset = function() { id = 0; } })(this); window.console && console.log( next(), next(), reset(), next() ) //0, 1, undefined, 0
물론 글로벌 ID 생성기가 필요하다면 아주 간단합니다...
nextIdMod(); window.console && console.log( next(), next(), reset(), next() ) //0, 1, undefined, 0
这个我们作为例子使用的 id 生成器工具并没有表现出这个模式的全部潜力。通过包裹一整个库和使用this
关键字作为命名空间的替身,我们使得用户在任何他们选择的上下文中运行这个库很轻松(包括全局上下文)。
//library code var protoQueryMooJo = function() { //everything } //user code var thirdParty = {}; protoQueryMooJo.apply(thirdParty);
我希望避免命名空间嵌套。它们很难追踪(对人和电脑都是)并且它们会让你的代码因为一些乱七八糟的东西变得很多。如 Peter Michaux 指出的,深度嵌套的命名空间可能是那些视图重新创建他们熟悉和热爱的长包链的老派 Java 开发者的遗产。
通过 .js 文件来固定一个单独的命名空间也是可以的(虽然只能通过命名空间注入或者直接分配每一个变量),不过你应该对依赖谨慎些。此外将命名空间绑定到文件上可以帮助读者更轻易弄清整个代码。
因为 JavaScript 并没有正式的命名空间结构,所以有很多自然形成的方法。这个调查只详细说明了其中的一部分,可能有更好的技术我没有发现。我很乐意知道它们。
以上就是JavaScript 中的命名空间详细介绍的内容,更多相关内容请关注PHP中文网(www.php.cn)!