> 웹 프론트엔드 > JS 튜토리얼 > jQuery_jquery의 프로그래밍 패러다임에 대한 자세한 설명

jQuery_jquery의 프로그래밍 패러다임에 대한 자세한 설명

WBOY
풀어 주다: 2016-05-16 16:27:01
원래의
1483명이 탐색했습니다.

이 글에서는 jQuery의 프로그래밍 패러다임을 자세히 분석합니다. 참고할 수 있도록 모든 사람과 공유하세요. 세부 내용은 다음과 같습니다.

2005년 이후 브라우저 프런트엔드 프로그래밍의 면모는 엄청난 변화를 겪었습니다. 이는 단순히 풍부한 기능을 갖춘 수많은 기본 라이브러리가 등장하여 비즈니스 코드를 보다 편리하게 작성할 수 있게 되었다는 의미가 아닙니다. 프런트엔드 관련 방식으로 프로그래머 생산성을 극대화하는 방법에 대한 명확한 인식과 함께 프런트엔드 기술을 보는 방식에 큰 변화가 있었습니다. 여기에서는 jQuery 소스 코드의 구현 원리를 바탕으로 JavaScript에서 나타나는 프로그래밍 패러다임과 일반적인 기술에 대해 간략하게 소개합니다.

1. AJAX: 상태 지속성, 비동기 업데이트

먼저, 약간의 역사입니다.

A. 1995년 Netscape의 Brendan Eich는 동적이고 약한 유형의 프로토타입 기반 스크립트 언어인 JavaScript 언어를 개발했습니다.
B. 1999년에 XMLHTTP ActiveX 컨트롤이 포함된 Microsoft IE5가 출시되었습니다.
C. Microsoft IE6은 2001년에 출시되었으며 DOM 레벨 1 및 CSS 2 표준을 부분적으로 지원했습니다.
D. Douglas Crockford는 2002년에 JSON 형식을 발명했습니다.

이 시점에서는 Web 2.0이 의존하는 기술적 요소가 기본적으로 구체화되었다고 볼 수 있지만, 업계 전체에 당장 큰 영향을 미치지는 않았습니다. 일부 "비동기 부분 페이지 새로 고침" 기술이 프로그래머들 사이에서 비밀리에 유포되고 심지어 바인드와 같은 거대하고 부풀어 오른 클래스 라이브러리가 생성되기도 하지만 일반적으로 프런트 엔드는 황량하고 더러운 늪으로 간주되며 오직 백엔드 기술만이 왕입니다. 없어진 물건 있어요?

당시 인재들이 작성한 코드를 포함하여 2005년 이전의 js 코드를 오늘날의 관점에서 되돌아보면 프로그램 제어에 있어서 그들의 약점이 확연히 느껴집니다. 2005년 이전의 js 기술 자체에 문제가 있었던 것이 아니라, 단지 개념적인 차원에서 흩어져 있거나, 통일된 개념이 부족하거나, 그들만의 독특한 스타일과 영혼이 부족했을 뿐입니다. 당시 대부분의 사람들과 대부분의 기술은 전통적인 객체지향 언어를 시뮬레이션하고 전통적인 객체지향 기술을 사용하여 전통적인 GUI 모델의 모방을 구현하려고 했습니다.

2005년은 변화의 해이자 컨셉 창출의 해였습니다. Google이 일련의 새로운 대화형 애플리케이션을 출시하면서 Jesse James Garrett의 "Ajax: 웹 애플리케이션에 대한 새로운 접근 방식"이라는 기사가 널리 퍼졌습니다. 프론트엔드 전용 개념인 Ajax는 흩어져 있던 여러 관행을 동일한 슬로건 아래 빠르게 통합하여 웹 프로그래밍의 패러다임 전환을 촉발시켰습니다. 이름이 옳지 않으면 말이 옳지 않다는 말이 있듯이 이제 알려지지 않은 대중도 조직을 찾을 수 있습니다. Ajax 이전에 사람들은 B/S 아키텍처의 핵심 기능이 브라우저와 서버의 상태 공간이 분리되어 있다는 것을 오랫동안 인식해 왔습니다. 그러나 일반적인 해결책은 이러한 구분을 숨기고 전경 상태를 배경과 동기화하는 것이었습니다. ASP.NET과 같은 통합된 논리적 처리. 전경 상태 지속성을 지원하는 성숙한 디자인 패턴이 부족하기 때문에 페이지를 변경할 때 로드된 js 개체가 강제로 삭제됩니다. 이런 식으로 복잡한 작업이 완료될 것이라고 누가 기대할 수 있습니까?

Ajax는 인터페이스가 부분적으로 새로 고쳐지고 상태가 포그라운드에 있음을 명확하게 명시하므로 js 객체는 더 오랫동안 포그라운드에 존재해야 합니다. 이는 또한 이러한 개체와 기능을 효과적으로 관리해야 함을 의미하며, 이는 보다 복잡한 코드 구성 기술을 의미하며, 이는 모듈성과 공통 코드 기반에 대한 요구를 의미합니다.

실제로 jQuery의 기존 코드 중 실제로 Ajax와 관련된 부분은 거의 없습니다(XMLHTTP 컨트롤을 사용하여 백그라운드 반환 데이터에 비동기적으로 액세스). 그러나 Ajax가 없었다면 jQuery는 공개 코드 베이스로 존재할 이유가 없었을 것입니다.

2. 모듈화: 네임스페이스 관리

많은 양의 코드가 생성될 때 우리에게 필요한 가장 기본적인 개념은 모듈화, 즉 작업을 분해하여 재사용하는 것입니다. 작업 분해의 핵심은 각자가 독립적으로 작업한 결과를 하나로 통합할 수 있다는 점이다. 이는 각 모듈이 일관된 기본 개념을 기반으로 하고 상호 작용할 수 있어야 함을 의미합니다. 즉, 공통 코드 기반을 기반으로 하고 기본 브라우저의 불일치를 보호하며 통합 추상화 계층을 구현해야 합니다. 통합 이벤트 관리 메커니즘. 통합된 코드 베이스보다 더 중요한 것은 모듈 간에 이름 충돌이 없어야 한다는 것입니다. 그렇지 않으면 두 모듈 간의 상호 작용 없이도 두 모듈이 함께 작동하지 않습니다.

현재 jQuery가 홍보하는 주요 판매 포인트 중 하나는 네임스페이스에 대한 효과적인 제어입니다. 이는 점점 더 완전한 기능 포인트를 제공하는 것보다 훨씬 더 중요합니다. 좋은 모듈성을 통해 우리는 모든 소스의 코드를 재사용할 수 있으며 모든 사람의 작업을 누적하고 중첩할 수 있습니다. 그리고 기능 구현은 일시적인 작업 부하의 문제일 뿐입니다. jQuery는 모듈 패턴의 변형을 사용하여 전역 네임스페이스에 대한 영향을 줄이고 jQuery 개체(즉, $function)만 창 개체에 추가합니다.

일명 모듈 패턴 코드는 다음과 같습니다. 익명 함수를 사용하여 임시 변수의 범위를 제한하는 것이 핵심입니다.

코드 복사 코드는 다음과 같습니다.
var 기능 =(function() {

//개인 변수 및 함수
var privateThing = '비밀',
PublicThing = '비밀 아님',

changePrivateThing = function() {
        privateThing = '극비';
},

sayPrivateThing = function() {
console.log(privateThing);
        changePrivateThing();
};

// 공개 API로 돌아가기
반환 {
PublicThing : publicThing,
sayPrivateThing : sayPrivateThing
}
})();

JS 자체에는 패키지 구조가 부족하지만 수년간의 시도 끝에 업계에서는 점차 패키지 로딩에 대한 이해를 통일하여 일정한 공감대를 얻은 RequireJs 라이브러리와 같은 솔루션을 형성했습니다. jQuery는 RequireJS 라이브러리와 잘 통합되어 보다 완전한 모듈 종속성 관리를 달성할 수 있습니다. http://requirejs.org/docs/jquery.html

코드 복사 코드는 다음과 같습니다.
require(["jquery", "jquery.my"], function () {
//jquery.js와 jquery.my.js가 모두 성공적으로 로드되었을 때 실행
$(함수(){
​​​ $('#my').myFunc();
});
});


my/shirt 모듈은 my/cart 및 my/inventory 모듈에 따라 달라지는 다음 함수 호출을 통해 정의됩니다.
코드 복사 코드는 다음과 같습니다.
require.def("my/shirt",
["내/카트", "내/인벤토리"],
기능(장바구니, 인벤토리) {
// 여기서 모듈 패턴을 사용하여 my/shirt 모듈에 의해 노출된 API를 반환합니다
         반품 {
            색상: "파란색",
크기: "대형"
                addToCart: function() {
// 감소는 my/inventory
에 의해 노출되는 API입니다. Inventory.decrement(this);
                  cart.add(this);
            }
}
}
);

3. Magic$: 개체 승격

$function을 처음 봤을 때 어떤 생각이 들었나요? 전통적인 프로그래밍 이론은 항상 함수 이름 지정이 정확해야 하며 작성자의 의도를 명확하게 표현해야 한다고 말합니다. 긴 이름이 모호함의 가능성을 줄이기 때문에 짧은 이름보다 낫다고 주장하기까지 합니다. 그런데 $는 무엇입니까? 잘못된 코드? 그것이 전달하는 메시지는 너무 모호하고 모호합니다. $는 프로토타입.js 라이브러리에 의해 발명되었으며 기본 DOM 노드를 복잡한 동작을 가진 객체로 향상시킬 수 있기 때문에 진정한 마법의 기능입니다. 프로토타입.js의 원래 구현에서 $function은
으로 정의되었습니다.

코드 복사 코드는 다음과 같습니다.
var $ = 함수(id) {
"문자열" == id 유형 반환 ? document.getElementById(id) : id;
};

이것은 기본적으로 다음 수식에 해당합니다
e = $(id)

이것은 기발한 함수 이름 약어일 뿐만 아니라 더 중요한 것은 개념적 수준에서 텍스트 ID와 DOM 요소 간의 일대일 대응을 설정한다는 것입니다. $가 있기 전에는 id와 해당 요소 사이의 거리가 매우 멀습니다. 일반적으로 해당 요소는
과 같은 변수에 캐시되어야 합니다.

코드 복사 코드는 다음과 같습니다.
var ea = docuement.getElementById('a');
var eb = docuement.getElementById('b');
ea.style....

그런데 $를 사용하고 나면 여기저기서 다음과 같은 글을 볼 수 있습니다
코드 복사 코드는 다음과 같습니다.
$('header_' id).style...
$('body_' id)....

id와 element 사이의 거리가 제거된 것처럼 보이며 매우 밀접하게 얽힐 수 있습니다.

prototype.js는 나중에 $의 의미를 확장했습니다.

코드 복사 코드는 다음과 같습니다.
function $() {
var 요소 = new Array();
 
for (var i = 0; i < 인수.길이; i ) {
        var 요소 = 인수[i];
If (요소 유형 == '문자열')
            요소 = document.getElementById(element);
 
            if (arguments.length == 1)
           요소 반환
 
        elements.push(element);
}
 
요소 반환;
}

이는 다음 공식에 해당합니다.
[e,e] = $(id,id)

안타깝게도 Prototype.js는 이 단계에서 길을 잃었고 이 접근 방식은 실질적인 가치가 거의 없습니다.
$를 실제로 홍보하는 것은 jQuery이고 $는
수식에 해당합니다. [o] = $(선택기)
다음은 세 가지 개선 사항입니다.
A. 선택자는 더 이상 단일 노드 위치자가 아니라 복잡한 컬렉션 선택자입니다
B. 반환된 요소는 원래 DOM 노드가 아니지만 복잡한 함수 호출 체인을 시작할 수 있는 jQuery에 의해 더욱 향상된 풍부한 동작을 가진 개체입니다.
C. $에 의해 반환된 패키징 개체는 배열 형태로 구성되어 컬렉션 작업을 호출 체인에 자연스럽게 통합합니다.

물론 위의 내용은 마법의 $에 대한 설명을 지나치게 단순화한 것일 뿐 실제 기능은 훨씬 더 복잡합니다. 특히 매우 일반적으로 사용되는 직접 구성 기능이 있습니다.

코드 복사 코드는 다음과 같습니다.
$("
...
")....

jQuery는 들어오는 html 텍스트를 기반으로 일련의 DOM 노드를 직접 구성하고 이를 jQuery 객체로 패키징합니다. 이는 어느 정도 선택기의 확장으로 볼 수 있습니다. html 콘텐츠 설명 자체는 고유 지정입니다.

$(function{}) 이 함수는 실제로 약간 말문이 막힙니다. 이는 document.ready가 실행될 때 이 콜백 함수가 호출된다는 의미입니다. 정말, $는 마법의 함수입니다. 궁금한 점이 있으면 물어보세요.

요약하자면 $는 일반 DOM 및 텍스트 설명 세계에서 풍부한 개체 동작을 갖춘 jQuery 세계로의 전환 채널입니다. 이 문을 지나면 우리는 유토피아에 도착했다.

4. 비정형 매개변수: 제약보다는 표현에 중점

약한 유형의 언어에는 "약한"이라는 단어가 머리에 있기 때문에 사람들이 선천적으로 약간의 부족함을 느낄 수밖에 없습니다. 프로그램에 유형 제약이 없다는 것이 실제로 전통적인 강력한 유형 언어의 주요 단점입니까? , 함수 매개변수의 유형과 개수는 모두 컴파일러가 확인하는 제약사항이지만 이러한 제약사항은 여전히 ​​충분하지 않습니다. 일반 애플리케이션에서는 제약사항을 강화하기 위해 C와 같이 항상 많은 양의 방어 코드가 추가됩니다. 일반적으로 ASSERT를 사용하며, Java에서는 매개변수 값의 범위를 결정해야 하는 경우가 많습니다.

코드 복사 코드는 다음과 같습니다.
if (index < 0 || index >= size)
           새로운 IndexOutOfBoundsException 발생(
"색인: " index ", 크기: " size);

분명히 이러한 코드는 프로그램에서 기능하지 않는 수많은 실행 경로로 이어질 것입니다. 즉, 우리는 많은 판단을 내렸고 코드가 특정 지점까지 실행되면 시스템은 다음과 같이 외치며 예외를 발생시킵니다. 이 경로는 차단됩니다. 우리가 특정 판단을 내린 후에 이러한 판단의 결과를 사용하여 무언가를 할 수 있습니까? JavaScript는 추세를 따르면 자동으로 매개 변수 유형을 제한할 수 없습니다. 그리고 매개변수의 모양을 더욱 약화시키면 "약함"이 극단으로 밀려나게 됩니다. 약할 일이 없을 때 약함은 상징적인 특징이 될까요?

jQuery에서 이벤트 바인딩 함수인 바인드를 살펴보세요.
A. 한 번에 하나의 이벤트 바인딩

코드 복사 코드는 다음과 같습니다.
$("#my") .bind(" mouseover", function(){});

B. 한 번에 여러 이벤트 바인딩
코드 복사 코드는 다음과 같습니다.
$("#my") .bind( "mouseover mouseout",function(){})

C. 양식 변경 및 여러 이벤트 바인딩
코드 복사 코드는 다음과 같습니다.
$("#my").bind({mouseover:function( ){} , mouseout:function(){});

D. 이벤트 리스너에 일부 매개변수를 전달하고 싶습니다
코드 복사 코드는 다음과 같습니다.
$('#my').bind('click', { foo: " xxxx"}, function(event) { event.data.foo..})

E. 단체 이벤트 청취자를 원하시는 분
코드 복사 코드는 다음과 같습니다.
$("#my").bind("click.myGroup" , 함수( ){});

F. 왜 이 기능은 미쳐버리지 않았나요???

유형이 불확실하더라도 고정된 위치에 있는 매개변수의 의미는 확실해야겠죠? 한발 물러나 매개변수 위치가 중요하지 않더라도 함수 자체의 의미는 확실해야겠죠? 이거요?

값 값 = o.val(), 값 o.val(3) 설정
       
함수가 어떻게 그렇게 과할 수 있고, 전달된 매개변수의 유형과 개수에 따라 어떻게 다르게 동작할 수 있습니까? 그런데 이것이 우리의 가치입니다. 방지할 수 없기 때문에 의도적으로 허용됩니다. . 형태는 다양하지만, 말도 안되는 표현은 한 마디도 하지 않습니다. (저는 겁을 주려고 온 것이 아닙니다.)

5. 체인 운영: 선형화의 점진적인 개선

초창기 jQuery의 주요 장점은 소위 체인 운영이었습니다

.

코드 복사 코드는 다음과 같습니다.
$('#content') // 콘텐츠 요소 찾기
.find('h3') // 모든 하위 h3 노드를 선택합니다
.eq(2) // 컬렉션을 필터링하고 세 번째 요소를 유지합니다
​​​​.html('세 번째 h3의 텍스트 변경')
.end() // 이전 h3 컬렉션으로 돌아갑니다
.eq(0)
​​​​.html('첫번째 h3의 텍스트를 변경하세요');

일반적인 명령형 언어에서는 항상 중첩 루프에서 데이터를 필터링해야 하며 실제로 데이터를 조작하는 코드는 데이터를 찾는 코드와 얽혀 있습니다. 그러나 jQuery는 컬렉션을 먼저 구성한 후 적용하는 방법을 사용합니다. 이 방법은 두 논리의 분리와 중첩 구조의 선형화를 달성합니다. 실제로 $('div.my input:checked')와 같은 절차적 사고에 의존하지 않고도 컬렉션을 직관적으로 이해할 수 있습니다. 프로세스 동작을 추적하기보다는 직접적인 설명으로 볼 수 있습니다.

루프란 우리의 생각이 되감기를 반복하는 상태를 의미하며, 선형화 후에는 한 방향으로 곧게 가므로 생각의 부담이 크게 줄어들고 코드의 구성성이 향상됩니다. chain을 사용하여 jQuery는 놀라운 아이디어를 고안했습니다. jQuery는 객체 자체를 배열(컬렉션)처럼 래핑합니다. 컬렉션은 새 컬렉션에 매핑될 수 있으며 컬렉션은 자체 하위 컬렉션으로 제한될 수 있습니다. 결과도 컬렉션이 될 수 있습니다. 일부 구조적 변경이 발생했지만 여전히 집합은 개념적 고정점입니다. 이는 함수형 언어에서 흡수된 디자인 아이디어입니다. 컬렉션 작업은 너무 일반적인 작업입니다. Java에서는 소위 캡슐화 함수가 실제로 일부 컬렉션 순회 작업을 캡슐화한다는 것을 쉽게 알 수 있습니다. jQuery에서는 컬렉션 작업이 너무 간단하여 캡슐화할 필요가 없습니다.

연쇄 호출은 항상 "현재" 개체를 가지며 모든 작업이 이 현재 개체에서 수행된다는 것을 의미합니다. 이는 다음 수식에 해당합니다
x = dx
호출 체인의 각 단계는 현재 개체에 대한 증분 설명이자 최종 목표를 향한 단계별 개선 프로세스입니다. 이 아이디어는 Witrix 플랫폼에서도 널리 사용됩니다. 특히 플랫폼 메커니즘과 비즈니스 코드의 통합을 실현하기 위해 플랫폼은 개체(컨테이너)의 기본 콘텐츠를 제공하며, 기본 설정을 취소하는 것을 포함하여 이를 기반으로 비즈니스 코드를 점진적으로 개선하고 수정할 수 있습니다.

그런데 jQuery의 체인 호출은 표면적으로는 매우 간단하지만 내부적으로 구현할 때는 추가 루프 계층을 작성해야 합니다. 왜냐하면 컴파일러는 "컬렉션의 각 요소에 자동으로 적용"하는 방법을 모르기 때문입니다.

코드 복사 코드는 다음과 같습니다.
$.fn['someFunc'] = function(){
return this.each(function(){
​​ jQuery.someFunc(this,...);
}
}


6. 데이터: 통합 데이터 관리

js 라이브러리로서 해결해야 할 큰 문제는 js 객체와 DOM 노드 간의 상태 연관 및 공동 관리입니다. 일부 js 라이브러리는 js 객체에 중점을 두고 js 객체의 멤버 변수에 DOM 노드 포인터를 저장하는 방식을 선택하며, 액세스할 때 항상 js 객체를 진입점으로 사용하고 js 함수를 통해 간접적으로 DOM 객체를 작동합니다. 이러한 종류의 캡슐화에서 DOM 노드는 실제로 인터페이스로 표시되는 낮은 수준의 "어셈블리"입니다. jQuery의 선택은 HTML 자체의 구조를 기반으로 하는 Witrix 플랫폼과 유사합니다. 이는 js를 통해 DOM 노드의 기능을 향상시키고 이를 복잡한 동작을 가진 확장 객체로 승격시킵니다. 여기서의 아이디어는 비침입적 설계(non-intrusive)와 우아한 성능 저하 메커니즘(graceful 저하)입니다. 의미 구조는 기본 HTML 수준에서 완성됩니다. js의 역할은 대화형 동작을 강화하고 프레젠테이션 형식을 제어하는 ​​것입니다.

매번 $('#my')를 통해 해당 패키징 개체에 액세스하면 오랫동안 유지해야 하는 일부 상태 변수가 어디에 저장되어 있나요? jQuery는 통합된 전역 데이터 관리 메커니즘을 제공합니다.

데이터 가져오기:

코드 복사 코드는 다음과 같습니다.
$('#my').data ('myAttr')

데이터 설정:
코드 복사 코드는 다음과 같습니다.
$('#my').data('myAttr ',3 );

이 메커니즘은 HTML5 데이터 속성 처리를 자연스럽게 통합합니다.
코드 복사 코드는 다음과 같습니다.

HTML로 설정된 데이터는 $('#my').data('myAttr')를 통해 읽을 수 있습니다.

처음으로 데이터에 액세스할 때 jQuery는 DOM 노드에 고유한 uuid를 할당한 다음 이를 DOM 노드의 특정 확장 속성에 설정합니다. jQuery는 이 uuid가 이 페이지에서 반복되지 않도록 합니다.

코드 복사 코드는 다음과 같습니다.
elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ];

위의 코드는 DOM 노드와 순수 js 객체를 모두 처리할 수 있습니다. js 객체라면 js 객체 자체에 데이터가 직접 배치되고, DOM 노드라면 캐시를 통해 균일하게 관리됩니다.

모든 데이터는 데이터 메커니즘을 통해 균일하게 관리되며, 특히 모든 이벤트 리스닝 기능(data.events)은 jQuery를 통해 안전하게 리소스 관리를 구현할 수 있습니다. 노드를 복제할 때 관련 이벤트 수신 기능이 자동으로 복제될 수 있습니다. DOM 노드의 내용이 교체되거나 DOM 노드가 파괴되면 jQuery는 이벤트 청취 기능을 자동으로 취소하고 관련 js 데이터를 안전하게 해제할 수도 있습니다.

7. 이벤트: 통합 이벤트 모델

"객체 트리를 따라 전파되는 이벤트"라는 그림은 객체 지향 인터페이스 프로그래밍 모델의 핵심입니다. 객체의 구성은 인터페이스 구조의 안정적인 설명을 구성합니다. 이벤트는 객체 트리의 특정 노드에서 지속적으로 발생하고 버블링 메커니즘을 통해 위쪽으로 전파됩니다. 객체 트리는 자연스럽게 제어 구조가 됩니다. 각 하위 노드와의 연결을 명시적으로 설정하지 않고도 상위 노드의 모든 하위 노드에서 이벤트를 수신할 수 있습니다.

다양한 브라우저의 이벤트 모델에 대한 통합 추상화를 구축하는 것 외에도 jQuery는 주로 다음과 같은 개선 사항을 적용했습니다.
A. 커스텀 이벤트(custom) 메커니즘을 추가했습니다. 이벤트 전파 메커니즘은 원칙적으로 이벤트 내용 자체와 관련이 없으므로, 커스텀 이벤트는 브라우저 내장 이벤트와 동일한 처리 경로를 통과하고 동일한 모니터링 방법을 사용할 수 있습니다. . 사용자 정의 이벤트를 사용하면 코드의 응집력을 강화하고 코드 결합을 줄일 수 있습니다. 예를 들어 사용자 정의 이벤트가 없는 경우 관련 코드가 관련 객체를 직접 조작해야 하는 경우가 많습니다.

코드 복사 코드는 다음과 같습니다.
$('.switch, .clapper').click(function( ) {
var $light = $(this).parent().find('.lightbulb');
If ($light.hasClass('on')) {
          $light.removeClass('on').addClass('off');
} 그 밖의 {
          $light.removeClass('off').addClass('on');
}
});

사용자 정의 이벤트를 사용하면 표현된 의미가 더욱 제한적이고 명확해집니다.
코드 복사 코드는 다음과 같습니다.
$('.switch, .clapper').click(function( ) {
$(this).parent().find('.lightbulb').trigger('changeState');
});

B. 동적으로 생성된 노드에 대한 이벤트 모니터링이 추가되었습니다. 예를 들어, 바인딩 기능은 기존 DOM 노드에만 등록할 수 있습니다.
코드 복사 코드는 다음과 같습니다.
$('li.trigger').bind('click', 함수() {}}
bind 호출 후 다른 li 노드가 생성되면 해당 노드의 클릭 이벤트가 모니터링되지 않습니다.

jQuery의 대리자 메커니즘은 상위 노드에 청취 기능을 등록할 수 있으며, 하위 노드에서 트리거된 이벤트는 선택기에 따라 해당 handlerFn에 자동으로 전달됩니다. 이런 식으로 지금 등록하면 청취할 수 있습니다.

미래에 생성되는 노드.

코드 복사 코드는 다음과 같습니다.
$('#myList').delegate('li.trigger' , '클릭', handlerFn);
최근 jQuery 1.7에서는 바인드, 라이브 및 위임 메커니즘이 통합되었으며 온/오프만 통합되었습니다.


코드 복사 코드는 다음과 같습니다.
$('li.trigger').on('click', handlerFn); // 바인딩
과 동일 $('#myList').on('click', 'li.trigger', handlerFn) // 위임과 동일

 
8. 애니메이션 대기열: 글로벌 시계 조정

jQuery 구현은 제쳐두고 인터페이스에 애니메이션 효과를 적용하려면 먼저 무엇을 해야 하는지 생각해 보세요. 예를 들어 div의 너비를 1초 내에 100px에서 200px로 늘리고 싶습니다. 일정 기간 동안 div의 너비를 수시로 조정해야 하며 [동시에] 일반 함수 호출과 달리 애니메이션 명령을 실행한 후 다른 코드도 실행해야 한다는 것을 쉽게 상상할 수 있습니다. 원하는 결과를 즉시 얻을 수는 없으며 결과가 도착하기를 기다릴 수도 없습니다. 애니메이션의 복잡성은 일회성 표현 후 일정 시간 내에 실행되어야 한다는 점에 있습니다. 동시에 펼쳐져야 하는 여러 논리적 실행 경로

위대한 아이작 뉴턴 경은 "자연 철학의 수학적 원리"에서 "절대적이고 진실하며 수학적 시간 자체는 흐른다"라고 썼습니다. 모든 사건은 타임라인에 정렬될 수 있으며 이는 단계를 실행하기 위한 고유한 조정입니다. A1부터 A5까지, B1부터 B5까지 동시에 실행하려면 t1 시간에 [A1, B1], t2 시간에 [A2, B2]만 실행하면 됩니다.
t1 | t3 | t5 ...
A1 | A3 | A5 | 지하1층 | 지하3층 | 지하5층 |
구체적인 구현 형식은 다음과 같습니다.

A. 각 애니메이션에 대해 하나의 애니메이션 개체로 나누어 내부적으로 여러 단계로 나누어져 있습니다.

animation = new Animation(div,"width",100,200,1000,
단계 분할을 담당하는 보간 함수와 애니메이션 완료 시 콜백 함수); B. 글로벌 관리자에 애니메이션 객체 등록
timeFuncs.add(애니메이션);
C. 글로벌 시계가 트리거되는 순간마다 등록된 각 실행 시퀀스를 한 단계 더 진행하고, 종료된 경우 글로벌 관리자에서 삭제합니다.



코드 복사 코드는 다음과 같습니다.timerFuncs의 각 애니메이션에 대해           if(!animation.doOneStep())
           timeFuncs.remove(애니메이션)


원리 문제를 해결한 후, 우리가 자주 직면해야 하는 실제 문제를 가장 간결하게 표현하기 위한 인터페이스 기능을 디자인하는 방법을 살펴보겠습니다. A. 유사한 애니메이션을 구현하기 위해서는 여러 요소가 필요합니다

B. 각 요소에는 동시에 변경해야 하는 여러 속성이 있습니다.
C. 하나의 애니메이션을 실행한 후 다른 애니메이션을 시작하세요

이러한 질문에 대한 jQuery의 답변은 js의 문법적 표현의 마지막 남은 값을 짜낸다고 할 수 있습니다

.



코드 복사

코드는 다음과 같습니다.$('input') .animate({왼쪽:' =200px',위:'300'},2000) .animate({왼쪽:'-=200px',top:20},1000)
.queue(함수(){
//여기서 dequeue는 먼저 대기열의 마지막 함수를 실행하므로, Alert("y")
         $(this).dequeue();
경고('x');
})
.queue(함수(){
경고("y");
// 적극적으로 대기열에서 제거하지 않으면 대기열 실행이 중단되고 자동으로 계속되지 않습니다.
           $(this).dequeue();
});

A. jQuery에 내장된 선택기 메커니즘을 사용하여 컬렉션 처리를 자연스럽게 표현합니다.
B. 맵을 사용하여 여러 속성 변경 사항 표현
C. 마이크로포맷을 사용하여 도메인별 델타 개념을 표현합니다. '=200px'은 기존 값에 200px을 추가하는 것을 의미합니다
D. 함수 호출 순서를 사용하여 애니메이션 실행 순서를 자동으로 정의합니다. 실행 대기열에 추가된 애니메이션은 시작하기 전에 이전 애니메이션이 완전히 실행될 때까지 자연스럽게 대기합니다.

jQuery 애니메이션 큐의 구현 내용은 대략 다음과 같습니다.

A. animate 함수는 실제로 queue(function(){dequeue는 실행이 끝날 때 호출되어야 합니다. 그렇지 않으면 다음 메서드가 구동되지 않습니다.})
큐 함수가 실행될 때 fx 큐이고 현재 실행 중인 애니메이션이 없는 경우(animate가 연속으로 두 번 호출되면 두 번째 실행 함수가 큐에서 대기함) 큐 제거 작업이 자동으로 트리거되어 실행 대기열.
fx 대기열인 경우 대기열에서 빼낼 때 "inprogress" 문자열이 자동으로 대기열 상단에 추가되어 애니메이션이 곧 실행될 것임을 나타냅니다.
B. 각 속성에 대해 jQuery.fx 개체를 만듭니다. 그런 다음 fx.custom 함수(start와 동일)를 호출하여 애니메이션을 시작합니다.
C. 사용자 정의 함수에서 fx.step 함수를 전역 타이머Funcs에 등록한 후 전역 타이머를 시작해 보세요.
타이머Id = setInterval( fx.tick, fx.interval );
D. 정적 틱 함수는 각 fx의 단계 함수를 순서대로 호출합니다. 단계 함수에서는 easing을 통해 속성의 현재 값을 계산한 다음 fx 업데이트를 호출하여 속성을 업데이트합니다.
E. fx의 단계 함수는 모든 속성 변경이 완료되면 다음 메소드를 구동하기 위해 Dequeue가 호출되는지 결정합니다.

매우 흥미로운 점은 jQuery 구현 코드에 분명히 많은 릴레이 트리거 코드가 있다는 것입니다. 다음 애니메이션을 실행해야 하면 꺼내서 실행하고, 타이머를 시작해야 하면 타이머를 시작하고, 이는 js 프로그램이 단일 스레드이기 때문입니다. 실행 스레드가 중단되지 않도록 하려면 함수가 서로 도와야 합니다. 프로그램 내부의 엔진, 심지어 무한 실행 엔진이라 할지라도 프로그램의 모습은 본질적으로 바뀔 것입니다. 이 경우 루프에 비해 재귀가 더 자연스러운 설명이 됩니다.

9. 약속 패턴: 인과관계 파악

실제로는 항상 독립적으로 진화하는 수많은 타임라인이 있고, 사람과 사물은 시간과 공간에서 교차하지만, 소프트웨어에서는 원인과 결과가 발생하지 않으며, 소스 코드에 기능이 나열되어 있기 때문에 필연적으로 몇 가지 질문이 발생합니다. .왜 앞의 사람이 먼저 처형되어야 하지 않겠습니까? 온 우주가 1, 2, 3을 외치며 전진하게 하십시오. 정보 교환이 없고 상호 의존성이 없다면, 한 좌표계에서 순차적으로 발생하는 사건이 다른 좌표계에서 보면 반대 순서로 나타날 수 있으며, 그런 다음 약속 패턴을 발명했습니다.

Promise와 future 패턴은 기본적으로 동일합니다. 먼저 Java에서 친숙한 future 패턴을 살펴보겠습니다.


코드 복사 코드는 다음과 같습니다.
futureResult = doSomething();
...
realResult = futureResult.get();
함수 호출을 실행한다는 것은 단지 어떤 일이 발생했음을 의미할 뿐이며 반드시 호출자가 해당 문제의 최종 결과를 알아야 한다는 의미는 아닙니다. 함수가 즉시 반환하는 것은 단지 이행될 약속(미래 유형)일 뿐입니다. 실제로는 일종의 핸들입니다. 핸들이 전달되고, 중간에 손을 바꾸는 코드는 실제 결과가 무엇인지, 코드 조각이 의존해야 하는지 여부에 무관합니다. 실제 결과가 반환되면 future.get()은 실제 결과를 즉시 반환하고, 그렇지 않으면 결과가 반환될 때까지 현재 실행 경로를 차단합니다. 이후 future.get()을 호출하면 인과관계가 확립되었기 때문에 항상 즉시 반환되며, [결과 반환] 이 이벤트는 이전에 발생했음에 틀림없으며 다시는 변경되지 않습니다.

future 모드는 일반적으로 외부 개체가 future의 반환 값을 적극적으로 확인하는 것을 의미하고, promise 모드는 외부 개체가 promise에 콜백 함수를 등록하는 것을 의미합니다.


코드 복사 코드는 다음과 같습니다.
getData() 함수{
$.get('/foo/').done(function(){
반환 console.log('AJAX 요청 성공 후 실행');
}).fail(함수(){
console.log('AJAX 요청 실패 후 실행');
});
}

함수 showDiv(){
var dfd = $.Deferred();
$('#foo').fadeIn( 1000, dfd.resolve );
dfd.promise()를 반환합니다.
}

$.when( getData(), showDiv() )
.then(함수(ajaxResult,ignoreResultFromShowDiv){
console.log('showDiv()와 AJAX 요청이 모두 성공한 후에 실행됩니다!');
​​​​ // 'ajaxResult'는 서버의 응답입니다
});

jQuery는 Deferred 구조를 도입하고 Promise 모드에 따라 ajax, queue, document.ready 등을 재구성하고 비동기 실행 메커니즘을 통합합니다. then(onDone, onFail)은 Promise에 콜백 함수를 추가합니다. 호출이 성공적으로 완료되면(해결) 콜백 함수 onDone이 실행되고, 호출이 실패하면(거부) 여러 Promise 객체를 기다릴 수 있을 때 onFail이 실행됩니다. Promise의 장점은 비동기 실행 이후입니다. 시작했거나 끝났어도 콜백 함수 등록은 가능합니다

someObj.done(콜백).sendRequest() 대 someObj.sendRequest().done(콜백)

비동기 호출을 실행하기 전에 콜백 함수를 등록하는 것과 비동기 호출을 실행한 후에 등록하는 것은 완전히 동일합니다. 이는 프로그램 표현이 결코 완전히 정확하지 않으며 이러한 고유한 차원이 효과적으로 사용될 수 있다면 항상 고유한 변경 차원이 있음을 나타냅니다. 활용 가변성은 동시 프로그램의 성능을 크게 향상시킬 수 있습니다.

Promise 모드의 구체적인 구현은 매우 간단합니다. jQuery._Deferred는 다음 기능을 포함하는 함수 대기열을 정의합니다.

A. 콜백 함수를 저장합니다.
B. 해결 또는 거부 시 저장된 모든 기능을 실행합니다.
C. 실행 후 추가 기능이 즉시 실행됩니다.

특히 분산 컴퓨팅이나 병렬 컴퓨팅을 지향하는 일부 언어에는 E 언어와 같이 언어 수준에서 약속 모드가 내장되어 있습니다.

코드 복사 코드는 다음과 같습니다.
def carPromise := carMaker <- producer("Mercedes");
Def 온도Promise := carPromise <- getEngineTemperature()
...
When (온도약속) -> 완료(온도) {
           println(`자동차 엔진의 온도는 $temp`)
} 전자를 잡아라 {
          println(`엔진 온도를 얻을 수 없습니다. 오류: $e`)
}
E 언어에서 <-는 결국 실행될 것이라는 의미이지만 지금은 반드시 그런 것은 아닙니다. 일반적인 car.moveTo(2,3)은 즉시 실행되어 결과를 얻게 될 것임을 의미합니다. 컴파일러는 모든 약속 종속성을 식별하고 자동으로 스케줄링을 구현합니다.


10. 확장: 상속이 필요하지 않습니다 JS는 프로토타입 기반 언어이며 상속 메커니즘이 내장되어 있지 않습니다. 이는 전통적인 객체 지향 교육을 깊이 배운 많은 학생들을 항상 괴롭혔습니다. 그러나 상속이 우리에게 무엇을 가져올 수 있습니까? 가장 간단한 대답은 코드 재사용입니다. 따라서 먼저 코드 재사용 수단으로서의 상속 가능성을 분석해 보겠습니다.

초사이어인 버전의 상속 개념인 '다중 상속'이라는 개념이 있었는데, 안타깝게도 나중에 선천적 결함이 있는 것으로 진단되어 상속 개념에 대한 해석이 등장했습니다. 상속은 "is a" 관계이고, 파생 개체 "is a"에는 기본 클래스가 많아 정신분열증을 유발할 수 있으므로 다중 상속은 좋지 않습니다.


코드 복사 코드는 다음과 같습니다.
class A{ public: void f(){ f in A } }
클래스 B{ 공개: void f(){ f in B } }
클래스 D: 공개 A, B{}

클래스 D가 두 개의 기본 클래스 A와 B에서 상속되고 클래스 A와 B가 모두 동일한 함수 f를 구현하는 경우 클래스 D의 f는 A의 f이거나 B의 f입니다. 아니면 f일까요? 이 딜레마의 출현은 실제로 D의 기본 클래스 A와 B가 교환 법칙과 결합 법칙을 충족한다는 사실에서 비롯됩니다. 어떤 개념 사이에 두 가지 종속 관계가 나타날 것이라는 점을 인식하기 어려울 수 있습니다. 그러나 개념적 수준의 요구 사항을 완화하고 운영 수준에서 코드 재사용 문제를 더 고려하면 B가 A를 기반으로 작동한다고 간단히 생각할 수 있습니다. 즉, A와 B 사이의 교환법칙을 포기하고 결합법칙만 유지하여 A, B를 확장하고 B를 확장하면 A는 두 가지 다른 결과를 얻게 되며 더 이상 존재하지 않습니다. 스칼라 언어의 소위 특성 메커니즘은 실제로 이 전략을 채택합니다.

객체지향 기술이 발명된 지 오래지 않아, 소위 AOP(Aspect-Oriented 프로그래밍)가 등장했습니다. AOP는 클래스만 보는 위치 지정 및 수정 기술이라는 점에서 OOP와 다릅니다. AOP도 다중 상속과 유사한 코드 재사용 방법을 제공하는데, 이는 멤버 변수와 메소드의 집합을 임의로 열어서 수정할 수 있는 Map으로 간주됩니다.
개체 본체에 직접 주입되어 동작이 변경됩니다. 프로토타입.js 라이브러리에는 확장 기능
이 도입되었습니다.

코드 복사 코드는 다음과 같습니다.
Object.extend = function(destination, source) {
for(소스의 var 속성) {
목적지[속성] = 소스[속성];
}
귀국지;
}

은 Maps 간의 커버링 작업이지만 매우 효과적이며 jQuery 라이브러리에서 확장되었습니다. 이 작업은 jQuery에서 코드 재사용의 주요 기술 수단인 mixin과 유사합니다. 상속이 없는 경우.

11. 이름 매핑: 모든 것이 데이터입니다

코드가 좋으면 루프 판단이 적어야 합니다. 루프와 판단 문은 프로그램의 기본 구성 요소이지만 우수한 코드 라이브러리에서는 찾을 수 없는 경우가 많습니다. 이러한 문이 얽히면 주요 라인이 흐려지기 때문입니다. 시스템의 논리를 추적하는 데 정신이 팔려요. jQuery 자체는 각각 및 확장과 같은 함수를 통해 루프 문의 필요성을 크게 줄였습니다. 예를 들어, 매핑 테이블을 통해 처리됩니다. jQuery의 val( ) 함수는 태그마다 다른 처리를 수행해야 하므로 tagName을 키로 사용하여 함수 매핑 테이블을 정의하세요.

코드 복사 코드는 다음과 같습니다.
valHooks: { 옵션: {get:function(){}}}

이렇게 하면 프로그램의 모든 곳에
를 쓸 필요가 없습니다.
코드 복사 코드는 다음과 같습니다.
if(elm.tagName == 'OPTION'){
복귀...;
}else if(elm.tagName == 'TEXTAREA'){
복귀...;
}

통일된 처리가 가능합니다
코드 복사 코드는 다음과 같습니다.
(valHooks[elm.tagName.toLowerCase()] || defaultHandler) .get( 느릅나무);


매핑 테이블은 함수를 일반 데이터로 관리하며 특히 동적 언어에서 널리 사용됩니다. 특히 객체 자체가 함수 및 변수의 컨테이너이므로 매핑 테이블이라고 간주할 수 있습니다. jQuery에서 광범위하게 사용되는 기술은 이름 매핑을 동적으로 사용하는 것입니다. 예를 들어 myWidth 및 myHeight와 매우 유사한 두 가지 함수를 구현하려면
이 필요하지 않습니다.
코드 복사 코드는 다음과 같습니다.
jQuery.fn.myWidth = function(){
반환 parInt(this.style.width,10) 10;
}
 
jQuery.fn.myHeight = 함수(){
반환 parInt(this.style.height,10) 10;
}

대신
을 동적으로 생성하도록 선택할 수 있습니다.
코드 복사 코드는 다음과 같습니다.
jQuery.each(['너비','높이'],함수(이름){
jQuery.fn['내' 이름] = function(){
           returnparseInt(this.style[name.toLowerCase()],10) 10;
}
});


12. 인입 메커니즘: 사실 저는 굉장히 단순해요

이른바 jQuery의 플러그인은 실제로 $.fn에 추가된 기능입니다. 그렇다면 이 fn은 무엇일까요?

코드 복사 코드는 다음과 같습니다.
(function(window,undefine){
// 안에 또 다른 패키지가 있습니다
var jQuery = (함수() {
var jQuery = 함수(선택기, 컨텍스트) {
                   새로운 jQuery.fn.init( selector, context, rootjQuery ) 반환;
}
....
// fn은 사실 프로토타입의 약자입니다
jQuery.fn = jQuery.prototype = {
​​​​​생성자: jQuery,
            init: 함수(선택기, 컨텍스트, rootjQuery) {... }
}
 
// jQuery()를 호출하는 것은 new init()와 동일하며 init의 프로토타입은 jQuery의 프로토타입입니다
​​ jQuery.fn.init.prototype = jQuery.fn;
 
// // 여기에 반환된 jQuery 객체는 가장 기본적인 기능만 가지고 있습니다. 다음은 일련의 확장
입니다. jQuery를 반환합니다.
})();
...
//jQuery를 전역 객체로 노출
​ window.jQuery = window.$ = jQuery;
})(창);

분명히 $.fn은 실제로 jQuery.prototype의 약어입니다.

상태 비저장 플러그인은 매우 단순한 기능일 뿐입니다.

코드 복사 코드는 다음과 같습니다.
// 플러그인 정의
(함수($){
$.fn.hoverClass = 함수(c) {
           return this.hover(
                 function() { $(this).toggleClass(c) }
);
};
})(jQuery);

//플러그인 사용
$('li').hoverClass('hover');


보다 복잡한 플러그인 개발을 위해 jQuery UI는 위젯 팩토리 메커니즘을 제공합니다.
코드 복사 코드는 다음과 같습니다.
$.widget("ui.dialog", {
옵션: {
        autoOpen: true,...
},
_create: 함수(){ ... },
_init: 함수() {
           if ( this.options.autoOpen ) {
This.open();
}
},
_setOption: 함수(키, 값){ ... }
          파괴: function(){ ... }
});


$('#dlg').dialog(options) 호출 시 실제 실행되는 코드는 기본적으로 다음과 같습니다.
코드 복사 코드는 다음과 같습니다.
this.each(function() {
         var 인스턴스 = $.data( this, "dialog" );
          if (인스턴스 ) {
Instance.option( 옵션 || {} )._init();
         } else {
               $.data( this, "dialog", new $.ui.dialog( options, this ) );
}
}

$('#dlg').dialog() 함수를 처음 호출하면 window 객체 인스턴스가 생성되어 데이터에 저장되는 것을 볼 수 있습니다. 호출되며, 처음 호출되지 않으면 기존 객체 인스턴스에서 _init() 메서드가 호출됩니다. $('#dlg').dialog()를 여러 번 호출해도 여러 인스턴스가 생성되지 않습니다.

13. 브라우저 스니퍼와 기능 감지

브라우저 스니퍼는 jQuery 초기와 같이 한때 매우 인기 있는 기술이었습니다

코드 복사 코드는 다음과 같습니다.
jQuery.browser = {
버전:(userAgent.match(/.(?:rv|it|ra|ie)[/: ]([d.] )/) || [0,'0'])[1],
​​​ safari:/webkit/.test(userAgent),
​​​​opera:/opera/.test(userAgent),
          msie:/msie/.test(userAgent) && !/opera/.test(userAgent),
mozilla:/mozilla/.test(userAgent) && !/(호환|웹킷)/.test(userAgent)
};

특정 코드에서는 브라우저마다 다른 처리가 수행될 수 있습니다

코드 복사 코드는 다음과 같습니다.
if($.browser.msie) {
// 뭔가를 하세요
} else if($.browser.opera) {
// ...
}

그러나 브라우저 시장의 경쟁이 심화되면서 경쟁자들은 서로를 모방하고 위장하여 userAgent 혼란을 초래했으며 Chrome의 탄생과 Safari의 부상과 함께 IE도 표준을 향한 움직임을 가속화하기 시작했습니다. 더 이상 할 수 없습니다. 긍정적인 효과. 보다 세밀하고 구체적인 감지 방법인 기능 감지가 점차 브라우저 호환성을 처리하는 주류 방법이 되었습니다.

코드 복사 코드는 다음과 같습니다.
jQuery.support = {
// IE는 .innerHTML이 사용될 때 선행 공백을 제거합니다
​​​​leadingWhitespace: ( div.firstChild.nodeType === 3 ),
...
}
이전에 알고 있던 것보다 실제로 본 것에 기초하면 미래와의 호환성이 더 쉬워집니다.

14. 프로토타입과 jQuery

prototype.js는 새로운 사용자 경험을 제공하고, Ruby를 참조하여 JavaScript를 언어 수준에서 변환하고, 궁극적으로 js의 모습을 크게 바꾸는 것을 목표로 하는 라이브러리입니다. $, 확장, 각각, 바인드... 이러한 친숙한 개념은 모두 프로토타입.js에 의해 js 필드에 도입되었으며, 이를 먼저 활용하는 사람이 옳습니다. 반면에 jQuery는 더 실용적이며 목표는 단지 ​​적게 작성하고 더 많은 작업을 수행하는 것입니다.

그러나 급진적인 이상주의자들을 기다리는 운명은 그들의 야망이 성취되기 전에 죽는 경우가 많습니다. 프로토타입.js의 고유한 비법이자 아킬레스건이기도 합니다. 특히 jQuery를 모방하여 Element.extend(element)를 통해 향상된 객체를 반환하려고 하면 Prototype.js에 의해 완전히 수렁에 빠지게 됩니다. jQuery와는 다릅니다. 그러나 브라우저는 버그, 거짓말, 상업적인 음모로 가득 찬 분야입니다. 문제, 이름 충돌, 호환성 문제 등은 도움말 라이브러리의 기능으로 해결할 수 없습니다. Prototype.js 2.0 버전은 큰 변화를 겪고 있다고 합니다. 역사를 깨고 호환성을 포기해야 할지 모르겠습니다. , 아니면 계속해서 틈새에서 살아남기 위해 고군분투하세요.

이 기사가 모든 사람의 jQuery 프로그래밍에 도움이 되기를 바랍니다.

관련 라벨:
원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
최신 이슈
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿