> 웹 프론트엔드 > JS 튜토리얼 > Javascript 모듈화 및 네임스페이스 관리_javascript 기술에 대한 문제점 설명

Javascript 모듈화 및 네임스페이스 관리_javascript 기술에 대한 문제점 설명

WBOY
풀어 주다: 2016-05-16 18:14:24
원래의
1013명이 탐색했습니다.

[모듈화에 대해, 모듈화가 필요한 이유]

먼저 모듈화가 필요한 이유에 대해 이야기해 보겠습니다. 사실 이는 여전히 코딩 아이디어 및 코드 관리의 편의성과 관련이 있습니다(모듈식 아이디어를 고려한 코더는 최소한 자신만의 명명 규칙 세트가 있어야 한다고 믿기 때문에 네임스페이스 오염 문제는 언급되지 않습니다. 규모의 프로젝트에서는 사이트에서 네임스페이스 오염 가능성이 매우 낮지만, 이 문제가 나중에 논의된다는 의미는 아닙니다.
사실 모듈식 아이디어는 우리 입에 있는 소위 "모듈"이 소위 "객체"보다 더 큰 개체일 수 있다는 점을 제외하면 여전히 객체 지향 아이디어와 동일합니다. 우리는 좋은 캡슐화를 통해 동일한 목적을 달성하는 데 전념하는 기능적 기능을 결합하고 좋은 재사용성을 보장합니다. 이러한 결합된 코드 조각의 아이디어를 객체 지향 아이디어라고 부를 수 있습니다. 이렇게 하면 사용 용이성, 다양성, 유지 관리성, 가독성, 변수 이름 오염 방지 등 많은 이점이 있습니다.
모듈화란 객체지향과 모듈지향에 불과합니다. 동일한 프로젝트(모듈)에 관련된 기능패키지를 유기적으로 결합하여 공통명을 통해 관리합니다. 대략적으로 모듈식 아이디어라고 할 수 있다. 따라서 객체지향에 비해 실제로는 객체지향보다 코드 아키텍처에서 모듈식 아이디어를 구현하는 것이 더 쉽다고 생각합니다.
C#과 달리 Java 및 기타 강력한 형식의 언어는 모듈성과 네임스페이스 메커니즘이 우수합니다. JavaScript는 모듈 생성 및 관리를 위한 언어 기능을 제공하지 않습니다. 이 때문에 우리가 js 코딩을 할 때 소위 네임스페이스를 사용하는 것은 약간 너무 캐주얼해 보일 것입니다(저도 포함해서). 예:

코드 복사 코드는 다음과 같습니다.

var Hongru = {} / / 네임스페이스

(function(){
Hongru.Class1 = 함수() {
//TODO
}
...
Hongru.Class2 = 함수() {
//할 일
}
})();

위와 같이 우리는 일반적으로 전역 변수나 전역 개체를 네임스페이스로 사용합니다. 너무 단순해서 그런 큰 책임을 맡기는 것이 다소 무심해 보일 수도 있습니다. 하지만 이것이 나쁘다고 말할 수 있을까? 아니, 오히려 이런 코딩 습관을 가진 학생들은 칭찬받아야 한다고 생각합니다. . .


그래서 우리가 어떤 프로젝트를 할 때나 소규모 웹사이트를 구축할 때, 실제로는 이 방법을 사용해 네임스페이스 작업을 하면 충분하며 기본적으로 큰 문제는 없습니다. 하지만 다시 본질로 돌아가서, 코드 깔끔함에 집착하거나 대규모 웹사이트를 구축하는 경우, 또는 처음부터 아주 우아한 태도와 논리로 코드 구조에 접근하는 경우입니다. 아마도 우리는 더 나은 네임스페이스 등록 및 관리 방법을 고려해야 할 것입니다.
이 측면에서 jQuery는 YUI, Mootool, EXT 등에 비해 약간 열등하지만(jq에도 자체 모듈식 메커니즘 세트가 있지만) 이것이 여전히 jQuery에 대한 우리의 사랑을 방해하지는 않습니다. 초점이 다릅니다. jq의 강점은 선택기에 있습니다. 그렇지 않으면 j-Query라고 부르지 않습니다.
따라서 jQuery가 중소 규모 웹사이트에 더 적합하다고 말하는 것이 합리적입니다. Douban의 오픈 소스 프런트 엔드 경량 프레임워크인 Do 프레임워크와 마찬가지로 이 프레임워크도 jQuery를 기반으로 구축되어 모듈식 관리 아이디어 레이어와 동기식 파일 로딩 기능을 캡슐화합니다.

[네임스페이스에 대하여]

자, 다시 본론으로 돌아가서 위의 방법으로 전역 객체를 사용하여 네임스페이스를 생성하는 것만으로도 효과적으로 전역 변수를 줄이고 변수 이름 오염 문제를 피할 수 있습니다. . . 그러나 웹 사이트가 커지거나 프로젝트가 많아지면 여러 전역 개체의 이름 공간을 관리하는 데 여전히 문제가 있습니다. 우연히 이름 충돌이 발생하면 한 모듈이 다른 모듈의 속성을 덮어쓰게 되어 하나 또는 둘 다 제대로 작동하지 않게 됩니다. 그리고 문제가 발생하면 이를 파악하는 것도 상당히 번거롭습니다. 따라서 네임스페이스를 생성할 때 중복된 이름이 있는지 확인할 수 있는 메커니즘이나 도구가 필요할 수 있습니다.

반면, 서로 다른 모듈, 즉 서로 다른 네임스페이스는 완전히 독립적이지 않습니다. 때로는 서로 다른 네임스페이스에서 동일한 메서드나 속성을 생성해야 하는 경우도 있습니다. 문제가 되세요.

위 두 가지 측면에 대해 조금 생각해보고 테스트도 해봤지만, 아직 실수가 있는 부분이 있습니다. 오늘 다시 『코뿔소 책』을 읽었습니다. 위의 문제를 쉽게 해결한 고전입니다. "Rhinoceros Book"의 솔루션과 데모를 바탕으로 몇 가지 수정과 단순화를 가했습니다. 일반적인 이해를 공유하십시오. 더 중요한 점은 다음과 같습니다.

--각 하위 모듈의 사용성 테스트

우리의 네임스페이스는 객체이므로 객체가 가져야 할 계층 관계를 가지고 있으므로 감지 이러한 계층적 관계를 기반으로 네임스페이스의 가용성을 판단하고 등록해야 합니다. 이는 하위 네임스페이스를 등록할 때 특히 중요합니다. 예를 들어 새로운 네임스페이스를 Hongru로 등록한 다음 다른 네임스페이스를 Hongru.me로 등록해야 합니다. 즉, 원래 의도는 me 네임스페이스가 Hongru의 하위 네임스페이스이므로 다음과 같습니다. 아버지와 아들의 관계. 따라서 네임스페이스를 등록할 때에는 '.'으로 나누어서 하나씩 대응 판단을 해줘야 합니다. 따라서 네임스페이스를 등록하는 코드는 대략 다음과 같습니다.

코드 복사 코드는 다음과 같습니다.

// 네임스페이스 생성 --> 최상위 네임스페이스 반환
Module.createNamespace = function (이름, 버전) {
if (!name) throw new Error('이름 필요');
if (name.charAt(0) == '.' || name.charAt(name.length-1) == '.' || name.indexOf('..') != -1) throw new Error('잘못된 이름');

var parts = name.split('.');

var 컨테이너 = Module.globalNamespace
for (var i=0; ivar 부분[i];
if (!container[part]) 컨테이너[part] =
container[부분]
}

var 네임스페이스 = 컨테이너;
if (namespace.NAME) throw new Error('모듈 "' 이름 '"이 이미 정의되어 있습니다.'); 🎜>if ( 버전) 네임스페이스.VERSION = 버전;

Module.modules[name] = 네임스페이스;
return 네임스페이스
} 참고: 위의 모듈은 네임스페이스를 등록하고 관리하는 공통 모듈입니다. "기본 모듈"로서 새로 등록된 네임스페이스를 저장하는 데 사용되는 모듈 큐 속성을 가지고 있으므로 네임스페이스를 쉽게 확인할 수 있습니다. 가 등록되었습니다:





코드 복사
코드는 다음과 같습니다.

var Module;
//모듈 확인 --> '모듈'이 존재하지 않는지 확인하세요.
if (!!Module && (typeof Module != 'object' || Module.NAME )) throw new Error("NameSpace '모듈'이 이미 존재합니다!")

Module = {};

Module.NAME = 'Module.VERSION = 0.1 ;

Module.EXPORT = ['require',
'importSymbols']

Module.EXPORT_OK = ['createNamespace',
'isDefined',
' module',
'globalNamespace'];

Module.globalNamespace = this;

Module.modules = {'Module': Module}; 위 코드의 마지막 줄은 네임스페이스 큐이며, 새로 생성된 모든 네임스페이스가 여기에 배치됩니다. 이전 코드 조각과 결합하면 기본적으로 네임스페이스를 매우 잘 관리할 수 있습니다. "기본 모듈" 모듈의 경우 나중에 설명할 EXPORT와 같은 다른 속성도 있습니다. 다음은 네임스페이스 생성 테스트 데모입니다.




코드 복사
코드는 다음과 같습니다. Module.createNamespace('Hongru', 0.1);//Hongru라는 네임스페이스 등록, 버전 0.1
위의 두 번째 버전 매개변수도 필요하지 않으면 생략 가능 버전 번호. chrome-debugger
에서 새로 등록된 네임스페이스를 볼 수 있습니다.

새로 등록된 Hongru 네임스페이스가 적용된 것을 확인할 수 있습니다. 모듈의 모듈 큐를 살펴보세요.

새로 등록된 Hongru도 추가된 것을 확인할 수 있습니다. 모듈 대기열의 모듈입니다. 또한 모듈에는 require, isDefined 및 importSymbols와 같은 여러 메서드가 있다는 사실도 모두가 발견했습니다.
require(버전 감지) 및 isDefined(네임스페이스 감지 시 이미 등록됨) 두 가지 방법은 어렵지 않으므로 조금 더 간단합니다.


--버전 및 중복 이름 감지



코드 복사
코드는 다음과 같습니다. // 이름이 정의되었는지 확인하세요. Module.isDefined = function(name) {
Module.modules에 이름을 반환합니다. 🎜>} ;
// 버전 확인
Module.require = function (이름, 버전) {
if (!(Module.modules의 이름)) throw new Error('모듈 ' 이름 '이 아닙니다. 정의됨') ;
if (!version) return;
var n = Module.modules[name]
if (!n.VERSION || n.VERSION < version) throw new Error(' 'version' 이상의 버전이 필요합니다');
};


위의 두 가지 방법 중 하나는 대기열의 이름이 동일한지 확인하는 것이라는 점을 모두가 이해하고 있을 것입니다. 다른 하나는 버전이 요구 사항 버전을 충족하는지 확인하는 것입니다. 특별한 내용은 없으므로 자세히 설명하지 않겠습니다. 좀 더 복잡한 것은 네임스페이스 간 속성이나 메서드의 상호 가져오기입니다.
--네임스페이스에서 태그의 속성 또는 메소드 내보내기
우리가 원하는 것은 범용 네임스페이스 등록 및 관리 도구이므로 태그를 가져오거나 내보낼 때 구성 가능성을 고려해야 합니다. 태그를 한꺼번에 가져오거나 내보낼 수는 없습니다. . 따라서 모듈 템플릿에는 내보내기가 허용된 속성이나 메서드를 저장하는 태그 대기열로 표시되는 두 개의 배열 EXPORT 및 EXPORT_OK가 있습니다. 그 중 EXPORT는 공개 태그 대기열이고 EXPORT_OK는 사용자 정의할 수 있는 태그 대기열입니다. 명확하지 않다고 생각되면 하나의 태그 대기열만 사용하여 허용된 태그 속성이나 메서드를 저장할 수도 있습니다. 내보내다.
태그 대기열을 사용하여 수행하는 내보내기 작업은 EXPORT 및 EXPORT_OK 태그 대기열의 태그에만 적용됩니다.




코드 복사
코드는 다음과 같습니다.

// import module
Module.importSymbols = function (from) {
if (typeof form == 'string') from = Module.modules[from];
var to = Module.globalNamespace; //잘못
var 기호 = [];
var firstsymbol = 1;
if (arguments.length>1 && typeof 인수[1] == 'object' && 인수[1] != null) {
to = 인수[1];
첫 번째 기호 = 2;
}
for (var a=firstsymbol; asymbols.push(arguments[a]);
}
if (symbols.length == 0) {
//기본 내보내기 목록
if (from.EXPORT) {
for (var i=0; ivar s = from.EXPORT[i];
to[s] = from[s];
}
반환;
} else if (!from.EXPORT_OK) {
// EXPORT 배열 && EXPORT_OK 배열 모두 정의되지 않음
for (var s in from) {
to[s] = from[s];
반환;
}
}
}
if (symbols.length > 0) {
var allowed;
if (from.EXPORT || form.EXPORT_OK) {
허용 = {};
if (from.EXPORT) {
for (var i=0; iallowed[from.EXPORT[i]] = true;
}
}
if (from.EXPORT_OK) {
for (var i=0; i허용[form.EXPORT_OK[i] ] = 사실;
}
}
}
}
//기호 가져오기
for (var i=0; ivar s = 기호 [나];
if (!(s in from)) throw new Error('기호 ' s '가 정의되지 않았습니다.');
if (!!allowed && !(s in allowed)) throw new Error(s '는 공개가 아니므로 가져올 수 없습니다');
to[s] = 형식[s];
}
}

这个方법중계 네임스페이스)参数也是可选,为你想导出的具体属性或solution,默认是标记队列里的试选.
下side是测试demo:
제제대码 代码如下:

Module.createNamespace('홍루');
Module.createNamespace('me', 0.1);
me.EXPORT = ['define']
me.define = function () {
this.NAME = '__me';
}
Module.importSymbols(나, 홍루);//把me 이름자 空间下的标记导入到Hongru 이름자 空间下

可以看到测试结果:
 

 

 본인은 나에게 이름을 지정하는 방법을 정의합니다.问和使용 정의() 방법입니다.

最后贴下源码:


复代码 代码如下:

/* == 모듈 및 NameSpace tool-func ==
* 작성자 : hongru.chen
* 날짜 : 2010-12-05
*/
var Module;
//모듈 확인 --> '모듈'이 존재하지 않는지 확인하세요
if (!!Module && (typeof Module != 'object' || Module.NAME)) throw new Error("NameSpace 'Module'이 이미 존재합니다!");
모듈 = {};
모듈.NAME = '모듈';
Module.VERSION = 0.1;
Module.EXPORT = ['require',
'importSymbols'];
Module.EXPORT_OK = ['createNamespace',
'isDefined',
'modules',
'globalNamespace'];
Module.globalNamespace = 이;
Module.modules = {'모듈': 모듈};
// 네임스페이스 생성 --> 최상위 네임스페이스 반환
Module.createNamespace = function (이름, 버전) {
if (!name) throw new Error('이름 필요');
if (name.charAt(0) == '.' || name.charAt(name.length-1) == '.' || name.indexOf('..') != -1) throw new Error('잘못된 이름');
var parts = name.split('.');
var 컨테이너 = Module.globalNamespace;
for (var i=0; ivar part = parts[i];
if (!컨테이너[부분]) 컨테이너[부분] = {};
컨테이너 = 컨테이너[부분];
}
var 네임스페이스 = 컨테이너;
if (namespace.NAME) throw new Error('모듈 "' 이름 '"이 이미 정의되어 있습니다.');
namespace.NAME = 이름;
if (버전) 네임스페이스.VERSION = 버전;
Module.modules[이름] = 네임스페이스;
네임스페이스를 반환합니다.
};
// 이름이 정의되었는지 확인하세요.
Module.isDefined = function (name) {
Module.modules에 이름을 반환합니다.
};
// 버전 확인
Module.require = function (이름, 버전) {
if (!(Module.modules의 이름)) throw new Error('모듈 ' 이름 '이(가) 정의되지 않았습니다.');
(!version)이 반환되는 경우;
var n = Module.modules[이름];
if (!n.VERSION || n.VERSION < version) throw new Error('버전 '버전' 이상이 필요합니다.');
};
// 모듈 가져오기
Module.importSymbols = function (from) {
if (typeof form == 'string') from = Module.modules[from];
var to = Module.globalNamespace; //잘못
var 기호 = [];
var firstsymbol = 1;
if (arguments.length>1 && typeof 인수[1] == 'object' && 인수[1] != null) {
to = 인수[1];
첫 번째 기호 = 2;
}
for (var a=firstsymbol; asymbols.push(arguments[a]);
}
if (symbols.length == 0) {
//기본 내보내기 목록
if (from.EXPORT) {
for (var i=0; ivar s = from.EXPORT[i];
to[s] = from[s];
}
반환;
} else if (!from.EXPORT_OK) {
// EXPORT 배열 && EXPORT_OK 배열 모두 정의되지 않음
for (var s in from) {
to[s] = from[s];
반환;
}
}
}
if (symbols.length > 0) {
var allowed;
if (from.EXPORT || form.EXPORT_OK) {
허용 = {};
if (from.EXPORT) {
for (var i=0; iallowed[from.EXPORT[i]] = true;
}
}
if (from.EXPORT_OK) {
for (var i=0; i허용[form.EXPORT_OK[i] ] = 사실;
}
}
}
}
//기호 가져오기
for (var i=0; ivar s = 기호 [나];
if (!(s in from)) throw new Error('기호 ' s '가 정의되지 않았습니다.');
if (!!allowed && !(s in allowed)) throw new Error(s '는 공개가 아니므로 가져올 수 없습니다');
to[s] = 형식[s];
}
}
관련 라벨:
원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿