JavaScript 모듈형 개발 라이브러리 SeaJS
SeaJS는 국내 천재 라이프싱어가 개발했습니다. 현재 버전은 1.1.1이고, 소스코드는 1500라인 미만이고, 4k로 압축되어 있고, 품질이 매우 높습니다.
이 글에서는 SeaJS의 몇 가지 기본적인 사용법에 대해 이야기할 것입니다. 모든 내용을 다루지는 않지만 개인적인 이해를 바탕으로 공식 문서에 언급되지 않은 몇 가지 세부 사항에 대해 이야기하겠습니다.
1. SeaJS의 글로벌 인터페이스
SeaJS는 seajs와 정의라는 두 가지 식별자를 세상에 노출합니다.
프로젝트에서 이미 seajs 식별자를 사용했고 이를 변경하고 싶지 않은 경우. 이때 SeaJS는 글로벌 SeaJ를 포기할 수 있습니다. 예를 들어
var boot = seajs.noConstrict();
이때 boot는 이전 seajs와 동일합니다.
프로젝트에서 식별자 정의를 사용하더라도 이를 변경하고 싶지 않을 것입니다. SeaJS는 매우 관대하며 그 정의도 공개될 수 있습니다. 예를 들어
var boot = seajs.noConstrict(true);
는 위보다 true를 하나만 더 전달합니다. 현재 전역 정의는 사라졌습니다. 이때 이전 정의를 대체하려면 boot.define을 사용해야 합니다.
2. SeaJS에서 모듈 작성 방법
SeaJS는 기본적으로 전역 정의 함수를 사용하여 모듈을 작성합니다(define은 구문 키워드로 간주할 수 있음). 뎁스, 팩토리.
define(id?, deps?, Factory);
이 정의는 AMD의 유일한 API인 정의 함수를 쉽게 상기시켜 줍니다. 즉, SeaJS와 RequireJS 정의 사이에 혼란을 야기하고 혼란을 초래합니다.
모두 3개의 형식 매개변수가 있는 전역 정의를 갖고 있으며 해당 형식 매개변수 이름도 동일합니다. SeaJS가 AMD의 구현이라고 오해할 수 있습니다.
사실 SeaJS와 RequireJS에서 정의의 처음 두 매개변수는 실제로 동일합니다.
ID는 모두 문자열이며 모듈 식별자를 따릅니다. deps는 모두 종속 모듈을 참조하며 해당 유형은 배열입니다. 유일한 차이점은 세 번째 매개변수 팩토리에 있습니다. 유형도 함수이지만 팩토리 매개변수의 의미는 다릅니다.
RequireJS에는 두 가지 팩토리 매개변수가 있습니다.
a 및 deps(배열) 요소는 일대일로 대응됩니다. 즉, 여러 개의 Dep이 있고 여러 개의 실제 팩토리 매개변수가 있습니다.
정의(['a', 'b'], function(a, b){
// todo
});
b.require,exports,module( 모듈/래핑 형식).
Define(function(require,exports, module){
// todo
});
이 메서드는 나중에 RequireJS를 Modules/Wrappings로 절충한 것입니다. 그것과 호환됩니다. SeaJS의 정의는 RequireJS를 작성하는 두 번째 방법인 모듈/래핑만 지원합니다.
참고: SeaJS는 모듈/래핑 및 모듈/1.1.1을 따릅니다. 이 두 사양에는 정의 키워드에 대한 언급이 없습니다. 모듈/래핑에서는 정의 대신 module.declare를 사용하여 모듈을 정의해야 합니다. 그러나 AMD 사양에만 정의의 정의가 있습니다. 즉, SeaJS는 AMD의 구현은 아니지만 매우 오해하기 쉬운 식별자 정의를 사용합니다.
말을 너무 많이 해서 아직 모듈 작성을 시작하지 않았습니다. 가장 간단한 것부터 시작해 보겠습니다.
1. 간단한 모듈
정의({
addEvent: function(el, type, fn){},
RemoveEvent: function(el, type, fn){ } ,
fireEvent: function(el, type){}
});
이렇게 하면 이벤트 모듈이 작성되는데 이는 싱글톤을 작성하는 것과 다르지 않습니다. 이 방법은 순수 데이터 모듈을 정의하는 데 더 자주 사용됩니다.
var E = {
addEvent: function(el, type, fn){},
RemoveEvent: function(el, type, fn){},
fireEvent: function(과 유사합니다. el , type){}
};
2. 단순 패키징 모듈
Define(function() {
// 일부 내부 보조 기능
// ...
function addEvent() {
}
function RemoveEvent() {
}
function fireEvent() {
// . .
}
return {
의 경우 이 익명 함수에서 수행할 수 있는 작업이 많습니다. 마지막으로 필요한 인터페이스를 노출합니다.
var E = function() {
// 일부 내부 도우미 함수
// ...
function addEvent() {
}
function RemoveEvent()와 유사합니다. {
}
function fireEvent() {
}
return {
addEvent: addEvent,
removeEvent:removeEvent,
fireEvent:fireEvent
};
}();
3. NodeJS 스타일 패키징 모듈
위 두 가지 이 작성 방법에는 NodeJS 스타일(Modules/1.1.1)의 흔적이 없으므로 "방법 2"와 동일하게 다시 작성합니다.
Define(function(require,exports) {
// 일부 내부 도우미 함수
// ...
function addEvent() {
}
function RemoveEvent() {
}
function fireEvent() {
}
// 객체를 반환하는 대신 모듈 인터페이스를 내보내려면 내보내기를 사용하세요.
내보내기.addEvent = addEvent;
내보내기.addEvent = 제거이벤트;
exports.addEvent = fireEvent;
});
"방법 2"와의 차이점을 확인할 수 있습니다. 내용은 다음과 같습니다.
1: 익명 함수에는 require와exports라는 두 개의 매개 변수가 있습니다.
2: 내보내기 인터페이스는 객체를 반환하지 않고 내보내기를 사용합니다.
Export는 정확히 NodeJS 스타일 아닌가요? 주의깊은 학생들은 이 예에서 require 매개변수가 사용되지 않는다는 것을 발견할 수 있으며, 이에 대해서는 아래에서 설명합니다.
4. 종속성이 있는 모듈
SeaJS의 "종속성"은 require 함수를 사용하여 얻어야 합니다. SeaJS 정의의 두 번째 매개변수인 deps도 "종속성"을 의미하는데 사용됩니다. 패키징 도구(SPM)를 제공합니다. 또한 SeaJS의 require는 익명 함수에 매개변수로 전달되고 RequireJS의 require는 전역 변수입니다. www.2cto.com
위의 정의는 종속성이 없는 모듈이며, 다음은 종속성이 있는 모듈입니다.
정의(함수(요구, 내보내기) {
var 캐시 = require('캐시');
// ...
내보내기.bind = 바인딩;
exports.unbind = unbind;
exports.trigger=trigger;
});
이 이벤트 모듈은 캐시 모듈에 따라 달라지며 함수에는 require와exports라는 두 가지 형식 매개변수가 있습니다. 외부 익명 함수를 제쳐두고 정의하는 것은 표준 NodeJS 형식입니다. require 함수를 사용하여 종속 모듈을 가져오고 내보내기를 사용하여 기존 모듈 인터페이스를 내보냅니다.
실제로 SeaJS에서 종속성이 있는 모듈은 "방법 4"에 따라 작성되어야 합니다. 즉, 래퍼 모듈이어야 하며 익명 함수의 첫 번째 매개 변수는 식별자 "require"여야 합니다. 즉, 전역적이지는 않지만 require를 원래 구문 키워드로 사용할 수 있습니다.
익명 함수 매개변수 require 및 내보내기의 흥미로운 현상을 살펴보겠습니다
a. require 이외의 것을 작성하고 req로 변경하면 어떻게 될까요?
정의(함수(req, 내보내기) {
var 캐시 = req('캐시');
// ...
내보내기.bind = 바인딩;
exports.unbind = unbind;
exports.trigger=trigger;
});
Firebug 네트워크 요청은 다음과 같습니다
b. 익명 함수의 형식 매개변수만 req로 변경하고 함수 내부에서는 계속 require를 사용합니다.
정의(함수(req, 내보내기) {
// ...
내보내기.bind = 바인딩;
exports.unbind = unbind;
exports.trigger=trigger;
});
네트워크 요청을 살펴보세요
이번에는 "캐시" 모듈이 실제로 요청했습니다.
위의 익명 함수 코드에서 require가 선언되지 않았고 형식 매개변수 req가 require가 아닌 부분을 주의 깊게 살펴보세요. 그러면
?
1 var 캐시 = require('cache');
의 require는 어디에서 왔나요?
SeaJS 소스 코드를 보면 정의 함수가 익명 함수의 toString을 사용하고 일반 매칭을 사용하여 "캐시"(비공개 ParseDependency 함수)를 구문 분석하는 것을 볼 수 있습니다.
또한 캐시 요청이 완료되었음에도 불구하고 실행 단계에서 require가 정의되지 않았기 때문에 여전히 오류가 보고되는 것을 볼 수 있습니다. 따라서 종속 모듈을 작성할 때 익명 함수의 첫 번째 매개변수는 필수여야 하며 변경할 수 없습니다.
factory.toString 및 일반 구문 분석 종속성이 사용되기 때문에 require의 매개변수는
//와 같은 표현식이 될 수 없습니다. require의 매개변수는 표현식 연산이 될 수 없습니다.
require("ui-" + "대화상자");
//와 같은 require 별칭을 사용할 수 없습니다. require를 다른 변수에 할당할 수 없습니다.
var req = require;
req("ui-dialog");
c . 내보내기를 expo로 수정
정의(function(require, expo) {
var 캐시 = require('cache');
// ...
expo.bind = 바인딩;
expo.unbind = unbind;
expo.trigger = Trigger;
});
실행에는 문제가 없습니다. 즉, 두 번째 매개변수인 "exports"를 사용자 정의할 수 있습니다. 분명히 SeaJS는 "내보내기"를 다른 것으로 변경하는 데 동의하지 않습니다. 이는 분명히 NodeJS 스타일(모듈/1.1.1) 모듈 사양을 파괴합니다. 그들은 "내보내기"를 사용하여 모듈 인터페이스를 내보냅니다. 그러나 이는 SeaJS에서는 시행할 수 없으며 단지 인위적인 합의일 수 있습니다.
5. 쓰기 방식이 혼합된 모듈
위에서는 다양한 상황에서 모듈을 작성하는 방법을 소개했습니다. NodeJS 스타일과 일관성을 유지하려면 "종속성"을 얻으려면 require를 사용하고 "인터페이스"를 내보내려면 내보내기를 사용하세요. SeaJS에는 종속성을 얻는 데 제한이 있습니다. 즉, require를 사용해야 합니다. 그러나 내보내기를 반드시 사용할 필요는 없습니다. 즉, 내보내기를 다른 것으로 변경할 수 있습니다. "반환 값"을 직접 사용할 수도 있습니다.
정의(function(require) {
var 캐시 = require('cache');
// ...
// 반환 값을 사용하여 인터페이스 내보내기
return {
바인딩: function() {},
unbind: function() {},
fire: function() {}
};
});
우리는 모듈이 NodeJS에서만 객체일 수 있다는 것을 알고 있습니다. 즉, 내보내기 시 항상 메서드를 중단하세요. SeaJS에서 인터페이스를 내보내는 데 내보내기를 사용하는 경우에도 모듈은 JS 개체일 수 있습니다. "반환 값"을 사용하여 인터페이스를 내보내는 경우 모듈은 모든 JS 유형이 될 수 있습니다. 다음은 함수 유형 모듈을 반환합니다.
define(function(require) {
var 캐시 = require('cache');
function ad() {
} //...
}
// 함수형 모듈
return ad;
});
3. SeaJS 로딩 방식
다양한 로딩 방식(동기식, 비동기식)을 제공하지만, 가장 쉬운 방법은 페이지에 직접 스크립트 태그를 작성하는 것입니다. SeaJS를 소개한 후 시작하는 대부분의 시간은 seajs.use 메소드입니다.
seajs.use에는 두 개의 매개변수가 있습니다. 첫 번째 매개변수는 문자열(모듈 이름) 또는 배열(여러 모듈)일 수 있습니다. 두 번째 매개변수는 콜백 함수입니다. 모듈 로딩 후 콜백. 콜백 함수의 매개변수는 첫 번째 매개변수와 일대일로 대응됩니다.
seajs.use('dom', function(dom) {
// todo with dom
});
dom 모듈은 콜백 함수에서 다음과 같이 사용됩니다. 물론 바로가기 data-main(RequireJS와 동일)도 제공합니다.