찾다
웹 프론트엔드JS 튜토리얼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]; }

match[3]과 match[4]는 모두 undefine이므로 else 문 본문이 실행됩니다.

코드 복사 코드는 다음과 같습니다.
else if(인용되지 않음
              && rpseudo.test(따옴표 없음)  
​​​​&& (초과 = 토큰화(따옴표 없음, true))
​​​​&& (초과 = unquoted.indexOf(")", unquoted.length - 초과) - unquoted.length)

이때 unquoted = ".class:contain('span')):eq(3"은 true이고, unquoted가 contain:contain('span')이므로 정규식 rpseudo와 일치하므로 rpseudo입니다. test(unquoted)가 true이고, 다음과 같이 tokenize를 다시 호출하여 인용되지 않은 부분을 다시 구문 분석합니다.


코드 복사 코드는 다음과 같습니다.
초과 = 토큰화(따옴표 없음, true)

이번에 토큰화 함수를 호출할 때 들어오는 선택기 매개변수는 ".class:contain('span')):eq(3"과 같고,parseOnly는 true와 같습니다. 함수 본문의 실행 프로세스는 다음과 같습니다. 다음과 같습니다:

코드 복사 코드는 다음과 같습니다.
지금까지 = 선택기

soFar = ".class:contain('span')):eq(3"

처음으로 while 루프에 들어갈 때 match에는 값이 할당되지 않았기 때문에 if의 다음 문 본문이 실행됩니다. 토큰 변수를 초기화하고 토큰을 그룹 배열에 푸시합니다.

코드 복사 코드는 다음과 같습니다.
groups.push(토큰 = [])

뒤에 for 문을 입력합니다.

첫 번째 for 루프: Expr.filter에서 첫 번째 요소 "TAG"를 가져와서 유형 변수에 할당하고 루프 본문 코드를 실행합니다.


코드 복사 코드는 다음과 같습니다.
if ((match = matchExpr[type].exec(soFar))
          && (!preFilters[유형] || (일치 = preFilters[유형]
(일치)))) {

현재 남은 선택기는 TAG 선택기가 아니므로 이번 사이클이 종료됩니다.

두 번째 for 루프: Expr.filter에서 두 번째 요소 "CLASS"를 가져와서 유형 변수에 할당하고 루프 본문 코드를 실행합니다.

match = matchExpr[type].exec(soFar)의 실행 결과는 다음과 같습니다.

일치 = ["클래스", "클래스"]

preFilters["CLASS"]가 존재하지 않으므로 if 내의 문 본문이 실행됩니다.


코드 복사 코드는 다음과 같습니다.
일치 = match.shift()

일치 항목의 첫 번째 요소 클래스를 제거하고 해당 요소를 일치하는 변수에 할당합니다. 이때, match="class", match = ["class"]

코드 복사 코드는 다음과 같습니다.
토큰.푸시({
값 : 일치,
유형 : 유형,
일치 : 일치
}

새 개체 { 값: "클래스", 유형: "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')", "contain", "'span'", "'", "span", 정의되지 않음, 정의되지 않음, 정의되지 않음, 정의되지 않음, 정의되지 않음, 정의되지 않음]


코드 복사 코드는 다음과 같습니다. 따옴표 없음 = !match[5] && match[2];

따옴표 없음 = "범위"


코드 복사

코드는 다음과 같습니다. if (matchExpr["CHILD"].test(match[0])) { null을 반환합니다.
}

":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')"이 분석을 위해 다시 제출되면 캐시에 저장되므로 현재 실행 속도만 향상됩니다.

이 시점에서 전체 실행 과정이 종료되었습니다.

성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
jquery实现多少秒后隐藏图片jquery实现多少秒后隐藏图片Apr 20, 2022 pm 05:33 PM

实现方法:1、用“$("img").delay(毫秒数).fadeOut()”语句,delay()设置延迟秒数;2、用“setTimeout(function(){ $("img").hide(); },毫秒值);”语句,通过定时器来延迟。

jquery怎么在body中增加元素jquery怎么在body中增加元素Apr 22, 2022 am 11:13 AM

增加元素的方法:1、用append(),语法“$("body").append(新元素)”,可向body内部的末尾处增加元素;2、用prepend(),语法“$("body").prepend(新元素)”,可向body内部的开始处增加元素。

jquery怎么修改min-height样式jquery怎么修改min-height样式Apr 20, 2022 pm 12:19 PM

修改方法:1、用css()设置新样式,语法“$(元素).css("min-height","新值")”;2、用attr(),通过设置style属性来添加新样式,语法“$(元素).attr("style","min-height:新值")”。

axios与jquery的区别是什么axios与jquery的区别是什么Apr 20, 2022 pm 06:18 PM

区别:1、axios是一个异步请求框架,用于封装底层的XMLHttpRequest,而jquery是一个JavaScript库,只是顺便封装了dom操作;2、axios是基于承诺对象的,可以用承诺对象中的方法,而jquery不基于承诺对象。

jquery中apply()方法怎么用jquery中apply()方法怎么用Apr 24, 2022 pm 05:35 PM

在jquery中,apply()方法用于改变this指向,使用另一个对象替换当前对象,是应用某一对象的一个方法,语法为“apply(thisobj,[argarray])”;参数argarray表示的是以数组的形式进行传递。

jquery怎么删除div内所有子元素jquery怎么删除div内所有子元素Apr 21, 2022 pm 07:08 PM

删除方法:1、用empty(),语法“$("div").empty();”,可删除所有子节点和内容;2、用children()和remove(),语法“$("div").children().remove();”,只删除子元素,不删除内容。

jquery on()有几个参数jquery on()有几个参数Apr 21, 2022 am 11:29 AM

on()方法有4个参数:1、第一个参数不可省略,规定要从被选元素添加的一个或多个事件或命名空间;2、第二个参数可省略,规定元素的事件处理程序;3、第三个参数可省略,规定传递到函数的额外数据;4、第四个参数可省略,规定当事件发生时运行的函数。

jquery怎么去掉只读属性jquery怎么去掉只读属性Apr 20, 2022 pm 07:55 PM

去掉方法:1、用“$(selector).removeAttr("readonly")”语句删除readonly属性;2、用“$(selector).attr("readonly",false)”将readonly属性的值设置为false。

See all articles

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

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

AI Clothes Remover

AI Clothes Remover

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

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

AI Hentai Generator

AI Hentai Generator

AI Hentai를 무료로 생성하십시오.

인기 기사

R.E.P.O. 에너지 결정과 그들이하는 일 (노란색 크리스탈)
3 몇 주 전By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 최고의 그래픽 설정
3 몇 주 전By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 아무도들을 수없는 경우 오디오를 수정하는 방법
3 몇 주 전By尊渡假赌尊渡假赌尊渡假赌
WWE 2K25 : Myrise에서 모든 것을 잠금 해제하는 방법
3 몇 주 전By尊渡假赌尊渡假赌尊渡假赌

뜨거운 도구

WebStorm Mac 버전

WebStorm Mac 버전

유용한 JavaScript 개발 도구

Dreamweaver Mac版

Dreamweaver Mac版

시각적 웹 개발 도구

안전한 시험 브라우저

안전한 시험 브라우저

안전한 시험 브라우저는 온라인 시험을 안전하게 치르기 위한 보안 브라우저 환경입니다. 이 소프트웨어는 모든 컴퓨터를 안전한 워크스테이션으로 바꿔줍니다. 이는 모든 유틸리티에 대한 액세스를 제어하고 학생들이 승인되지 않은 리소스를 사용하는 것을 방지합니다.

VSCode Windows 64비트 다운로드

VSCode Windows 64비트 다운로드

Microsoft에서 출시한 강력한 무료 IDE 편집기

메모장++7.3.1

메모장++7.3.1

사용하기 쉬운 무료 코드 편집기