jQuery 선택기 소스 코드 해석(5): tokenize_jquery의 구문 분석 프로세스
다음 분석은 jQuery-1.10.2.js 버전을 기준으로 작성되었습니다.
다음은 $("div:not(.class:contain('span')):eq(3)")를 예로 들어 토큰화 및 preFilter 코드가 어떻게 조정되어 구문 분석을 완료하는지 설명합니다. tokenize 메소드와 preFilter 클래스의 각 코드 라인에 대한 자세한 설명을 알고 싶으시면 다음 두 글을 참고해주세요.
http://www.jb51.net/article/63155.htm
http://www.jb51.net/article/63163.htm
다음은 tokenize 메소드의 소스코드입니다. 단순화를 위해 캐싱, 쉼표 매칭, 관계형 문자 매칭과 관련된 코드를 모두 제거하고 현재 예시와 관련된 핵심 코드만 남겨두었습니다. 제거된 코드는 매우 간단합니다. 필요한 경우 위 기사를 읽어보세요.
또한 설명 텍스트 위에 코드가 적혀 있습니다.
함수 토큰화(선택기, 구문 분석 전용) {
var 일치, 일치, 토큰, 유형, soFar, 그룹, preFilters;
soFar = 선택기;
그룹 = [];
preFilters = Expr.preFilter;
동안(지금까지) {
if (!matched) {
groups.push(토큰 = []);
}
일치 = 거짓;
for (Expr.filter 입력) {
If ((match = matchExpr[type].exec(soFar))
&& (!preFilters[유형] || (일치 = preFilters[유형]
(일치)))) {
일치 = match.shift();
토큰.푸시({
값: 일치,
유형 : 유형,
일치: 일치
});
SoFar = soFar.slice(matched.length);
}
}
if (!matched) {
휴식;
}
}
return parseOnly ? soFar.length : soFar ? Sizzle.error(selector) :
tokenCache(선택기, 그룹).slice(0);
}
먼저, jQuery 실행 중 select 메소드에 의해 tokenize가 처음으로 호출되고, "div:not(.class:contain('span')):eq(3)"이 선택기 매개변수로 메소드에 전달됩니다.
soFar = 선택기;
soFar = "div:not(.class:contain('span')):eq(3)"
처음으로 while 루프에 들어갈 때 match에는 값이 할당되지 않았기 때문에 if의 다음 문 본문이 실행됩니다. 토큰 변수를 초기화하고 토큰을 그룹 배열에 푸시합니다.
groups.push(토큰 = [])
그런 다음 for 문을 입력합니다.
첫 번째 for 루프: Expr.filter에서 첫 번째 요소 "TAG"를 가져와서 유형 변수에 할당하고 루프 본문 코드를 실행합니다.
If ((match = matchExpr[type].exec(soFar))
&& (!preFilters[유형] || (일치 = preFilters[유형]
(일치)))) {
match = matchExpr[type].exec(soFar)의 실행 결과는 다음과 같습니다.
일치 =["div", "div"]
예제의 첫 번째 선택자는 div이며 matchExpr["TAG"]의 정규 표현식과 일치하며 preFilters["TAG"]가 존재하지 않으므로 if 내의 문 본문이 실행됩니다.
일치 = match.shift()
일치 항목의 첫 번째 요소인 div를 제거하고 해당 요소를 일치하는 변수에 할당합니다. 이때, match="div", match = ["div"]
토큰.푸시({
값: 일치,
유형 : 유형,
일치: 일치
}
새 개체 { 값: "div", 유형: "TAG", 일치: ["div"] }를 만들고 개체를 토큰 배열에 푸시합니다.
SoFar = soFar.slice(matched.length);
soFar 변수는 div를 삭제합니다. 이때 soFar=":not(.class:contain('span')):eq(3)"
두 번째 for 루프: Expr.filter에서 두 번째 요소 "CLASS"를 가져와서 유형 변수에 할당하고 루프 본문 코드를 실행합니다.
If ((match = matchExpr[type].exec(soFar))
&& (!preFilters[유형] || (일치 = preFilters[유형]
(일치)))) {
현재 soFar=":not(.class:contain('span')):eq(3)"은 CLASS 유형의 정규 표현식과 일치하지 않으므로 이 루프가 종료됩니다.
세 번째 for 루프: Expr.filter에서 세 번째 요소 "ATTR"을 가져와서 유형 변수에 할당하고 루프 본문 코드를 실행합니다.
마찬가지로 현재 나머지 선택자는 속성 선택자가 아니므로 이 주기가 종료됩니다.
네 번째 for 루프: Expr.filter에서 네 번째 요소 "CHILD"를 가져와서 유형 변수에 할당하고 루프 본문 코드를 실행합니다.
마찬가지로 현재 남아 있는 선택자는 CHILD 선택자가 아니므로 이 주기가 종료됩니다.
다섯 번째 for 루프: Expr.filter에서 다섯 번째 요소 "PSEUDO"를 가져와서 유형 변수에 할당하고 루프 본문 코드를 실행합니다.
If ((match = matchExpr[type].exec(soFar))
&& (!preFilters[유형] || (일치 = preFilters[유형]
(일치)))) {
match = matchExpr[type].exec(soFar)의 실행 결과는 다음과 같습니다.
[":not(.class:contain('span')):eq(3)", "not", ".class:contain('span')):eq(3", 정의되지 않음, 정의되지 않음, 정의되지 않음, 정의되지 않음 , 정의되지 않음, 정의되지 않음, 정의되지 않음, 정의되지 않음]
preFilters["PSEUDO"]가 존재하므로 다음 코드가 실행됩니다.
일치 = preFilters[유형](일치)
preFilters["PSEUDO"] 코드는 다음과 같습니다.
"PEUDO": 함수(일치) {
var 초과, 인용되지 않음 = !match[5] && match[2];
if (matchExpr["CHILD"].test(match[0])) {
null을 반환합니다.
}
if (match[3] && match[4] !== 정의되지 않음) {
일치[2] = 일치[4];
} else if (인용되지 않음
&& rpseudo.test(따옴표 없음)
&& (초과 = 토큰화(따옴표 없음, 참))
&& (초과 = unquoted.indexOf(")", unquoted.length
- 초과)
- 인용되지 않은 길이)) {
match[0] = match[0].slice(0, 초과);
match[2] = 인용되지 않은.slice(0, 초과);
}
match.slice(0, 3) 반환;
}
전달된 일치 매개변수는 다음과 같습니다.
[":not(.class:contain('span')):eq(3)", "not", ".class:contain('span')):eq(3", 정의되지 않음, 정의되지 않음, 정의되지 않음, 정의되지 않음 , 정의되지 않음
따옴표 없음 = !match[5] && match[2]
따옴표가 없음 = ".class:contain('span')):eq(3"
if (matchExpr["CHILD"].test(match[0])) {
null 반환
}
match[0] = ":not(.class:contain('span')):eq(3)"은 matchExpr["CHILD"] 정규 표현식과 일치하지 않으며 return null 문을 실행하지 않습니다. .
if (일치[3] && match[4] !== 정의되지 않음) {
일치[2] = 일치[4]; }
&& rpseudo.test(따옴표 없음)
&& (초과 = 토큰화(따옴표 없음, true))
&& (초과 = unquoted.indexOf(")", unquoted.length - 초과) - unquoted.length)
처음으로 while 루프에 들어갈 때 match에는 값이 할당되지 않았기 때문에 if의 다음 문 본문이 실행됩니다. 토큰 변수를 초기화하고 토큰을 그룹 배열에 푸시합니다.
첫 번째 for 루프: Expr.filter에서 첫 번째 요소 "TAG"를 가져와서 유형 변수에 할당하고 루프 본문 코드를 실행합니다.
&& (!preFilters[유형] || (일치 = preFilters[유형]
(일치)))) {
두 번째 for 루프: Expr.filter에서 두 번째 요소 "CLASS"를 가져와서 유형 변수에 할당하고 루프 본문 코드를 실행합니다.
일치 = ["클래스", "클래스"]
preFilters["CLASS"]가 존재하지 않으므로 if 내의 문 본문이 실행됩니다.
값 : 일치,
유형 : 유형,
일치 : 일치
}
새 개체 { 값: "클래스", 유형: "CLASS", 일치 항목: ["클래스"] }를 만들고 개체를 토큰 배열에 푸시합니다.
soFar = soFar.slice(matched.length)
soFar 변수는 이때 클래스를 삭제합니다. soFar = ":contain('span')):eq(3"
세 번째 for 루프: Expr.filter에서 세 번째 요소 "ATTR"을 가져와서 유형 변수에 할당하고 루프 본문 코드를 실행합니다.
마찬가지로 현재 나머지 선택자는 속성 선택자가 아니므로 이 주기가 종료됩니다.
네 번째 for 루프: Expr.filter에서 네 번째 요소 "CHILD"를 가져와서 유형 변수에 할당하고 루프 본문 코드를 실행합니다.
마찬가지로 현재 남아 있는 선택자는 CHILD 선택자가 아니므로 이 주기가 종료됩니다.
다섯 번째 for 루프: Expr.filter에서 다섯 번째 요소 "PSEUDO"를 가져와서 유형 변수에 할당하고 루프 본문 코드를 실행합니다.
if ((match = matchExpr[type].exec(soFar))
&& (!preFilters[유형] || (일치 = preFilters[유형]
(일치)))) {
match = matchExpr[type].exec(soFar)의 실행 결과는 다음과 같습니다.
[":contain('span')", "contain", "'span'", "'", "span", 정의되지 않음, 정의되지 않음, 정의되지 않음, 정의되지 않음, 정의되지 않음, 정의되지 않음]
preFilters["PSEUDO"]가 존재하므로 다음 코드가 실행됩니다.
일치 = preFilters[유형](일치)
preFilters["PSEUDO"] 코드는 위에 표시되어 있으며 여기에 나열되지 않습니다.
"PEUDO": 함수(일치) {
var 초과, 따옴표 없음 = !match[5] && match[2]
If (matchExpr["CHILD"].test(match[0])) {
null 반환; }
If (일치[3] && match[4] !== 정의되지 않음) {
일치[2] = 일치[4];
} else if(인용되지 않음
> && (초과 = 토큰화(인용 안함, 참)) && (초과 = unquoted.indexOf(")", unquoted.length
~
- 인용되지 않은 길이)) {
match[0] = match[0].slice(0, 초과)
match[2] = unquoted.slice(0, 초과)
}
match.slice(0, 3) 반환
}
들어오는 일치 매개변수는 다음과 같습니다.
따옴표 없음 = "범위"
코드 복사
":contain('span')"은 matchExpr["CHILD"] 정규식과 일치하지 않으므로 내부 문 본문이 실행되지 않습니다.
if (match[3] && match[4] !== 정의되지 않음) {
일치[2] = 일치[4];
}
match[3] = "'"이고 match[4] ="span"이므로 내부 if 문 본문이 실행되고 "span"이 match[2]에 할당됩니다.
return match.slice(0, 3)
일치의 처음 세 요소의 복사본을 반환합니다
이때, tokenize 메소드의 for 루프로 돌아가서 실행을 계속합니다. 이때, 각 변수의 값은 다음과 같습니다.
일치 = [":contain('span')", "contain", "span"]
soFar = ":contain('span')):eq(3"
일치 = match.shift()
일치 배열에서 ":contain('span')"을 제거하고 일치하는 변수에 할당합니다.
토큰.푸시({
값 : 일치,
유형 : 유형,
일치 : 일치
}
새 개체 만들기 {값:
":contain('span')", 유형:"PSEUDO", ["contain", "span"] }과 일치하고 객체를 토큰 배열에 푸시합니다.
soFar = soFar.slice(matched.length)
soFar 변수는 ":contain('span')"을 삭제합니다. 이때 soFar="):eq(3)"는 이후 for 루프가 끝나고 while 루프가 다시 실행될 때까지 존재합니다. 유효한 선택자가 없습니다. 따라서 while 루프를 종료하십시오.
반환 parsOnly ? soFar.length : soFar ? Sizzle.error(selector) :
tokenCache(선택기, 그룹).slice(0)
이때는 parseOnly = true이므로 이때 soFar의 길이인 6이 반환되고, preFilters["PSEUDO"]의 코드가 계속 실행됩니다
else if(인용되지 않음
&& rpseudo.test(따옴표 없음)
&& (초과 = 토큰화(따옴표 없음, true))
&& (초과 = unquoted.indexOf(")", unquoted.length - 초과) - unquoted.length)
초과 변수에 6을 할당한 후 코드
초과 = unquoted.indexOf(")", unquoted.length - 초과) - unquoted.length
계산: 선택기 끝 위치가 아님(예: 오른쪽 대괄호 위치) 22
match[0] = match[0].slice(0, 초과)
match[2] = unquoted.slice(0, 초과)
전체 :not 선택기 문자열(match[0])과 해당 괄호 안의 문자열(match[2])을 각각 계산합니다.
match[0] = ":not(.class:contain('span'))"
match[2] = ".class:contain('span')"
return match.slice(0, 3)
일치하는 처음 세 요소의 복사본을 반환합니다.
토큰화 함수로 돌아가서 이제 일치 = [":not(.class:contain('span'))", "not", ".class:contain('span')"]
일치 = match.shift()
일치에서 첫 번째 요소인 ":not(.class:contain('span'))"을 제거하고 해당 요소를 일치된 변수에 할당합니다. 이때 match="":not(.class:contain( ' 스팬'))"",
match = ["not", ".class:contain('span')"]
토큰.푸시({
값 : 일치,
유형 : 유형,
일치 : 일치
}
새 개체 만들기 { 값: ":not(.class:contain('span'))"", 유형: "PSEUDO", 일치: ["not", ".class:contain('span') "] }를 입력하고 개체를 토큰 배열에 푸시합니다. 이때 토큰에는 선택기가 아닌 div라는 두 가지 요소가 있습니다.
soFar = soFar.slice(matched.length)
SoFar 변수는 ":not(.class:contain('span'))"을 삭제합니다. 이때 soFar=":eq(3)"는 이 for 루프를 종료한 후 다시 while 루프로 돌아갑니다. 같은 방식으로 토큰의 세 번째 요소에 대한 eq 선택기를 얻으려면 프로세스가 not과 일치하므로 여기서는 자세히 설명하지 않겠습니다. 최종 조별 결과는 다음과 같습니다.
group[0][0] = {값: "div", 유형: "TAG", 일치: ["div"] }
group[0][1] = {값: ":not(.class:contain('span'))", 유형: "PSEUDO", 일치: ["not", ".class:contain(' 스팬')"] }
group[0][2] = {값: ":eq(3)", 유형: "PSEUDO", 일치: ["eq", "3"] }
반환 parsOnly ? soFar.length : soFar ? Sizzle.error(selector) :
tokenCache(선택기, 그룹).slice(0)
parseOnly = 정의되지 않았으므로 tokenCache(selector, groups).slice(0)이 실행됩니다. 이 문은 그룹을 캐시에 푸시하고 해당 복사본을 반환합니다.
여기에서 모든 구문 분석이 완료됩니다. 여기서 두 번째 요소는 구문 분석되지 않습니다. 실제 작업에서 다시 구문 분석해야 합니다. 물론 방금 "class:contain('span')):eq(3"을 구문 분석할 때 유효한 선택기의 결과를 캐시에 저장할 수 있다면 다시 구문 분석하는 것을 방지하고 실행 속도를 향상시킬 수 있습니다. 실행 중에 ".class:contain('span')"이 분석을 위해 다시 제출되면 캐시에 저장되므로 현재 실행 속도만 향상됩니다.

핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

Video Face Swap
완전히 무료인 AI 얼굴 교환 도구를 사용하여 모든 비디오의 얼굴을 쉽게 바꾸세요!

인기 기사

뜨거운 도구

메모장++7.3.1
사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전
중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기
강력한 PHP 통합 개발 환경

드림위버 CS6
시각적 웹 개발 도구

SublimeText3 Mac 버전
신 수준의 코드 편집 소프트웨어(SublimeText3)

뜨거운 주제











jQuery 참조 방법에 대한 자세한 설명: 빠른 시작 가이드 jQuery는 웹 사이트 개발에 널리 사용되는 JavaScript 라이브러리로, JavaScript 프로그래밍을 단순화하고 개발자에게 풍부한 기능을 제공합니다. 이 기사에서는 jQuery의 참조 방법을 자세히 소개하고 독자가 빠르게 시작할 수 있도록 구체적인 코드 예제를 제공합니다. jQuery 소개 먼저 HTML 파일에 jQuery 라이브러리를 도입해야 합니다. CDN 링크를 통해 소개하거나 다운로드할 수 있습니다.

jQuery에서 PUT 요청 방법을 사용하는 방법은 무엇입니까? jQuery에서 PUT 요청을 보내는 방법은 다른 유형의 요청을 보내는 것과 유사하지만 몇 가지 세부 사항과 매개 변수 설정에 주의해야 합니다. PUT 요청은 일반적으로 데이터베이스의 데이터 업데이트 또는 서버의 파일 업데이트와 같은 리소스를 업데이트하는 데 사용됩니다. 다음은 jQuery에서 PUT 요청 메소드를 사용하는 구체적인 코드 예제입니다. 먼저 jQuery 라이브러리 파일을 포함했는지 확인한 다음 $.ajax({u를 통해 PUT 요청을 보낼 수 있습니다.

jQuery를 사용하여 요소의 높이 속성을 제거하는 방법은 무엇입니까? 프런트엔드 개발에서는 요소의 높이 속성을 조작해야 하는 경우가 종종 있습니다. 때로는 요소의 높이를 동적으로 변경해야 할 수도 있고 요소의 높이 속성을 제거해야 하는 경우도 있습니다. 이 기사에서는 jQuery를 사용하여 요소의 높이 속성을 제거하는 방법을 소개하고 구체적인 코드 예제를 제공합니다. jQuery를 사용하여 높이 속성을 연산하기 전에 먼저 CSS의 높이 속성을 이해해야 합니다. height 속성은 요소의 높이를 설정하는 데 사용됩니다.

제목: jQuery 팁: 페이지에 있는 모든 태그의 텍스트를 빠르게 수정하세요. 웹 개발에서는 페이지의 요소를 수정하고 조작해야 하는 경우가 많습니다. jQuery를 사용할 때 페이지에 있는 모든 태그의 텍스트 내용을 한 번에 수정해야 하는 경우가 있는데, 이는 시간과 에너지를 절약할 수 있습니다. 다음은 jQuery를 사용하여 페이지의 모든 태그 텍스트를 빠르게 수정하는 방법을 소개하고 구체적인 코드 예제를 제공합니다. 먼저 jQuery 라이브러리 파일을 도입하고 다음 코드가 페이지에 도입되었는지 확인해야 합니다. <

제목: jQuery를 사용하여 모든 태그의 텍스트 내용을 수정합니다. jQuery는 DOM 작업을 처리하는 데 널리 사용되는 인기 있는 JavaScript 라이브러리입니다. 웹 개발을 하다 보면 페이지에 있는 링크 태그(태그)의 텍스트 내용을 수정해야 하는 경우가 종종 있습니다. 이 기사에서는 jQuery를 사용하여 이 목표를 달성하는 방법을 설명하고 구체적인 코드 예제를 제공합니다. 먼저 페이지에 jQuery 라이브러리를 도입해야 합니다. HTML 파일에 다음 코드를 추가합니다.

jQuery는 웹 페이지에서 DOM 조작 및 이벤트 처리를 처리하는 데 널리 사용되는 인기 있는 JavaScript 라이브러리입니다. jQuery에서 eq() 메서드는 지정된 인덱스 위치에서 요소를 선택하는 데 사용됩니다. 구체적인 사용 및 적용 시나리오는 다음과 같습니다. jQuery에서 eq() 메서드는 지정된 인덱스 위치에 있는 요소를 선택합니다. 인덱스 위치는 0부터 계산되기 시작합니다. 즉, 첫 번째 요소의 인덱스는 0이고 두 번째 요소의 인덱스는 1입니다. eq() 메소드의 구문은 다음과 같습니다: $("s

jQuery 요소에 특정 속성이 있는지 어떻게 알 수 있나요? jQuery를 사용하여 DOM 요소를 조작할 때 요소에 특정 속성이 있는지 확인해야 하는 상황이 자주 발생합니다. 이 경우 jQuery에서 제공하는 메소드를 사용하여 이 기능을 쉽게 구현할 수 있습니다. 다음은 jQuery 요소에 특정 속성이 있는지 확인하기 위해 일반적으로 사용되는 두 가지 방법을 특정 코드 예제와 함께 소개합니다. 방법 1: attr() 메서드와 typeof 연산자를 // 사용하여 요소에 특정 속성이 있는지 확인

jQuery는 웹 개발에 널리 사용되는 인기 있는 JavaScript 라이브러리입니다. 웹 개발 중에 JavaScript를 통해 테이블에 새 행을 동적으로 추가해야 하는 경우가 많습니다. 이 기사에서는 jQuery를 사용하여 테이블에 새 행을 추가하는 방법을 소개하고 특정 코드 예제를 제공합니다. 먼저 HTML 페이지에 jQuery 라이브러리를 도입해야 합니다. jQuery 라이브러리는 다음 코드를 통해 태그에 도입될 수 있습니다.
