> 웹 프론트엔드 > JS 튜토리얼 > JavaScript 시리즈의 심층적 이해 (1) 고품질 JavaScript 코드 작성의 기본 포인트_javascript 기술

JavaScript 시리즈의 심층적 이해 (1) 고품질 JavaScript 코드 작성의 기본 포인트_javascript 기술

WBOY
풀어 주다: 2016-05-16 17:57:14
원래의
1039명이 탐색했습니다.

특히 전역 변수 방지, 단일 변수 선언 사용, 루프에서 길이 사전 캐싱, 코드 읽기 수행 등과 같은 고품질 JavaScript 작성의 몇 가지 요소가 있습니다.
이 요약에는 API 문서 작성, 동료 검토 수행, JSLint 실행 등 코드와는 덜 관련되지만 전체 코드 생성과 더 관련이 있는 몇 가지 습관도 포함되어 있습니다. 이러한 습관과 모범 사례는 지금부터 몇 달 또는 몇 년 후에 자랑스럽게 생각하게 될 코드를 더 잘 작성하고 이해하기 쉽게 작성하고 유지하는 데 도움이 될 수 있습니다.
유지 관리 가능한 코드 작성
소프트웨어 버그를 수정하는 데는 비용이 많이 들고 시간이 지남에 따라 이러한 버그의 비용도 증가합니다. 특히 이러한 버그가 과거에 출시된 소프트웨어에 숨어 천천히 나타날 경우 더욱 그렇습니다. 버그를 발견하자마자 수정하는 것이 가장 좋습니다. 이때 코드에서 해결하려는 문제는 여전히 마음속에 명확하게 남아 있습니다. 그렇지 않으면 다른 작업으로 넘어가 특정 코드 부분을 잊어버리고 나중에 해당 코드를 다시 방문하려면 다음이 필요합니다.
문제를 배우고 이해하는 데 시간을 투자하세요
문제 코드를 이해하는 데 시간이 걸립니다. 해결되세요
특히 대규모 프로젝트나 회사의 경우 문제가 있습니다. 버그를 수정하는 사람은 코드를 작성한 사람이 아닙니다(그리고 버그를 발견한 사람과 버그를 수정한 사람은 코드를 작성한 사람이 아닙니다). 같은 사람). 그러므로, 자신이 얼마 전에 작성한 코드이든, 다른 팀원이 작성한 코드이든, 코드를 이해하는 데 걸리는 시간을 줄이는 것이 중요합니다. 이는 레거시 코드를 유지 관리하는 데 몇 시간과 며칠을 소비하는 대신 새롭고 흥미로운 것을 구축해야 하기 때문에 수익(수익)과 개발자 행복에 관한 것입니다.
소프트웨어 개발 생활에 대한 또 다른 사실은 코드를 읽는 것보다 코드를 읽는 것이 훨씬 더 오래 걸린다는 것입니다. 때로는 문제에 집중하고 깊이 생각할 때 오후에 앉아서 많은 코드를 작성할 수 있습니다.
귀하의 코드는 매우 빠르게 작동하지만 애플리케이션이 성숙해짐에 따라 검토, 수정 및 조정이 필요한 다른 많은 일이 발생하게 됩니다. 예:
버그가 노출됨
애플리케이션에 새로운 기능이 추가됨
프로그램이 새로운 환경에서 작동함(예: 새 브라우저가 출시됨)
코드 용도 변경
코드는 처음부터 완전히 다시 작성되거나 다른 아키텍처로 또는 다른 언어로 포팅되어야 합니다.
이러한 변경으로 인해 소수의 사람이 작성하는 데 몇 시간이 걸렸던 코드가 결국 읽는 데 몇 주가 걸리게 됩니다. . 이것이 바로 유지 관리 가능한 코드를 만드는 것이 애플리케이션의 성공에 중요한 이유입니다.
유지 관리 가능한 코드는 다음을 의미합니다.
읽기 가능
일관성
예측 가능
동일한 사람이 작성한 것처럼 보입니다
문서화됨
최소 전역 변수(Minimizing Globals)
JavaScript는 다음을 통해 범위를 관리합니다. 기능. 함수 내부에 선언된 변수는 함수 내부에서만 사용할 수 있고 함수 외부에서는 사용할 수 없습니다. 반면, 전역 변수는 함수 외부에서 선언되거나 선언되지 않고 단순히 사용되는 변수입니다.
각 JavaScript 환경에는 함수 외부에서 이를 사용할 때 액세스할 수 있는 전역 개체가 있습니다. 생성한 모든 변수는 이 전역 개체의 속성이 됩니다. 브라우저에서 편의를 위해 전역 객체에는 (보통) 전역 객체 자체를 가리키는 window라는 추가 속성이 있습니다. 다음 코드 조각은 브라우저 환경에서 전역 변수를 생성하고 액세스하는 방법을 보여줍니다.

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

myglobal = "hello"; // 권장되지 않음
console.log(myglobal); // "hello"
console.log(window.myglobal) // "hello" "
console.log(window["myglobal"]); // "안녕하세요"
console.log(this.myglobal); // "안녕하세요"

전역 변수 문제
전역 변수의 문제는 이러한 전역 변수가 JavaScript 애플리케이션과 웹 페이지의 모든 코드에서 공유되며 동일한 전역 네임스페이스에 있다는 것입니다. 따라서 프로그램의 서로 다른 두 부분이 이름은 같지만 기능이 다른 전역 변수를 정의하면 이름 충돌이 불가피합니다.
웹 페이지에는 페이지 개발자가 작성하지 않은 코드가 포함되어 있는 경우가 많습니다. 예를 들어
타사 JavaScript 라이브러리
광고주의 스크립트 코드
타사 사용자 추적 및 분석 스크립트 코드
다양한 유형의 위젯, 로고 및 버튼
예를 들어, 타사 스크립트는 result라는 전역 변수를 정의한 다음 함수에서 result라는 전역 변수도 정의합니다. 결과적으로 나중 변수가 이전 변수를 덮어쓰고 타사 스크립트가 갑자기 트림됩니다!
따라서 다른 스크립트와 좋은 이웃이 되려면 전역 변수를 최대한 적게 사용하는 것이 중요합니다. 전역 변수를 줄이기 위한 몇 가지 전략(예: 네임스페이스 모드 또는 자동 함수 즉시 실행)이 책의 뒷부분에서 언급되지만, 전역 변수를 줄이는 데 가장 중요한 것은 항상 var를 사용하여 변수를 선언하는 것입니다.
자바스크립트의 두 가지 특성으로 인해 무의식적으로 전역 변수를 생성하는 것은 놀라울 정도로 쉽습니다. 첫째, 변수를 선언하지 않고도 사용할 수 있습니다. 둘째, JavaScript에는 암시적 전역 개념이 있습니다. 즉, 선언하지 않은 모든 변수는 전역 객체 속성이 됩니다. 아래 코드를 참고하세요.
코드 복사 코드는 다음과 같습니다.

function sum( x, y) {
// 권장되지 않음: 암시적 전역 변수
result = x y;
return result
}

이 코드의 결과는 선언되지 않습니다. . 코드는 여전히 잘 작동하지만 함수를 호출한 후에는 추가 전역 네임스페이스가 생겨 문제의 원인이 될 수 있습니다.
향상된 sum() 함수에서 볼 수 있듯이 경험상 항상 var를 사용하여 변수를 선언하는 것이 좋습니다.
코드 복사 코드는 다음과 같습니다.

function sum(x, y) {
var result = x y
return result; 🎜>또 다른 생성 암시적 전역 변수에 대한 반례는 작업 체인을 사용하는 부분 var 선언입니다. 다음 코드 조각에서 a는 지역 변수이지만 b는 전역 변수이므로 원하는 결과가 아닐 수도 있습니다.



코드 복사
코드는 다음과 같습니다. // 반례, function foo() {
var a = b = 0
// ...
}


이런 현상이 발생하는 이유는 이 오른쪽에서 왼쪽으로의 할당이 우선 할당식 b = 0인데, 이 경우 b는 선언되지 않기 때문입니다. 이 표현식의 반환 값은 0이고, 이 0은 var에 의해 정의된 지역 변수 a에 할당됩니다. 즉, 다음과 같이 입력하는 것과 같습니다.
var a = (b = 0);
변수를 선언할 준비가 되었다면 전역 변수와 같은 예상치 못한 결과 없이 체인 할당을 사용하는 것이 좋습니다. as:




코드 복사
코드는 다음과 같습니다. function foo() { var a, b;
// ... a = b = 0; // 두 지역 변수
}


그러나 전역 변수를 피하는 또 다른 이유는 이식성입니다. 코드를 다른 환경(호스트)에서 실행하려면 전역 변수를 사용하는 것이 쉽지 않습니다. 원래 환경에 존재하지 않는 호스트 개체를 실수로 덮어쓰게 되기 때문입니다. 따라서 이름을 안전하게 사용할 수 있다고 생각했습니다. 사실 위의 내용은 일부 경우에는 적용되지 않습니다.)
var를 잊어버렸을 때의 부작용
암시적 전역 변수와 명시적으로 정의된 전역 변수 사이에는 약간의 차이가 있는데, 이는 삭제 연산자를 통해 변수를 정의되지 않은 상태로 두는 기능입니다.
var를 통해 생성된 전역 변수(함수 이외의 모든 프로그램에서 생성됨)는 삭제할 수 없습니다.
var 없이 생성된 암시적 전역 변수(함수에서 생성되었는지 여부에 관계 없음)는 삭제할 수 있습니다.
이는 기술적으로 암시적 전역 변수가 실제 전역 변수는 아니지만 전역 개체의 속성임을 보여줍니다. 속성은 삭제 연산자를 통해 삭제할 수 있지만 변수는 삭제할 수 없습니다.




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

// 3개의 전역 변수 정의
var global_var = 1;
global_novar = 2; // 부정 교재
(function () {
global_fromfunc = 3; // 부정 Textbook
}());
// 삭제 시도
delete global_var; // false
delete global_novar; // true
delete global_fromfunc; this
typeof global_var; // "number"
typeof global_novar; // "undefine"
typeof global_fromfunc; // "undefine"
코드 복사
변수로 작업할 때 오류가 발생합니다(예: 이전 코드 조각의 두 가지 부정적인 예).
전역 개체에 대한 액세스
브라우저에서 전역 개체는 창 속성을 통해 코드의 어느 곳에서나 액세스할 수 있습니다(이름을 창의 로컬 변수로 선언하는 등의 터무니없는 작업을 수행하지 않는 한). 그러나 다른 상황에서는 이 편의 속성을 다른 이름으로 부를 수도 있습니다(또는 프로그램에서 사용할 수 없는 경우도 있음). 하드 코딩된 창 식별자 없이 전역 개체에 액세스해야 하는 경우 모든 수준의 함수 범위에서 다음을 수행할 수 있습니다.
var global = (function () {
return this;
} ());

이 메서드는 (새 구성을 통하지 않고) 함수에서 함수로 호출되기 때문에 언제든지 전역 개체를 얻을 수 있으며 이는 항상 전역 개체를 가리킵니다. 실제로 이 버그는 ECMAScript 5 엄격 모드에는 적용되지 않으므로 엄격 모드에서는 다른 형식을 취해야 합니다. 예를 들어 JavaScript 라이브러리를 개발하는 경우 코드를 즉시 함수로 래핑한 다음 전역 범위에서 이에 대한 참조를 직접 함수의 매개 변수로 전달할 수 있습니다.
단일 var 패턴
함수 상단에 단일 var 문을 사용하는 것이 더 유용한 형식입니다.
함수에 필요한 모든 로컬 부분을 찾을 수 있는 단일 위치를 제공합니다. 🎜> 정의 전에 변수를 사용할 때 논리적 오류를 방지합니다
선언된 전역 변수를 기억하는 데 도움이 되므로 전역 변수가 적습니다. //zxx: 여기서 조금 헷갈립니다...
적은 코드(유형, 값, 및 한 줄 완성)
단일 var 형식은 다음과 같습니다.


function func() {
var a = 1,
b = 2,
sum = a b,
myobject = {},
i ,
j;
// 함수 본문...
}


하나의 var 문을 사용하여 여러 변수를 쉼표로 구분하여 선언할 수 있습니다. 이처럼 변수와 값을 동시에 초기화하는 것이 좋습니다. 이는 논리 오류(초기화되지 않았지만 선언된 모든 변수의 초기 값은 정의되지 않음)를 방지하고 코드의 가독성을 높입니다. 코드를 본 후에는 초기화된 값을 기반으로 이러한 변수의 일반적인 목적(예: 개체로 사용할지 정수로 사용할지 여부)을 알 수 있습니다.
이전 코드에서 sum = a b와 같이 선언할 때 실제 작업을 수행할 수도 있습니다. 또 다른 예는 DOM(Document Object Model) 참조를 사용할 때 단일 var DOM 참조를 로컬로 함께 지정할 수 있다는 것입니다.


function updateElement() {
var el = document.getElementById("result"),
style = el.style;
// el과 style을 사용하여 다른 작업을 수행하세요...
}


Hoisting: A Problem with Scattered vars (Hoisting: A Problem with Scattered vars)
JavaScript에서는 함수 내 어디에서든 여러 개의 var 문을 선언할 수 있으며, 마치 선언된 것처럼 동작합니다. 함수 상단에는 호이스팅(hoisting)이라는 동작이 있습니다. 변수를 사용한 다음 나중에 함수에서 다시 선언하면 논리 오류가 발생할 수 있습니다. JavaScript의 경우 변수가 동일한 범위(동일한 함수)에 있으면 var 선언 이전에 사용되더라도 선언된 것으로 간주됩니다. 다음 예를 보세요.


// 반대 예
myname = "global"; // 전역 변수
function func() {
alert(myname); // "정의되지 않음"
var myname = "local"
alert(myname) ); // "로컬"
}
func()


이 예에서는 첫 번째 경고에 "global"이 표시되고 두 번째 경고에 "loacl"이 표시된다고 생각할 수 있습니다. 첫 번째 경고 당시 myname이 선언되지 않았기 때문에 이 기대는 이해할 수 있습니다. 이때 함수는 자연스럽게 전역 변수 myname을 봐야 하지만 실제로는 이것이 작동하는 방식이 아닙니다. 첫 번째 경고는 myname이 함수의 지역 변수로 처리되고(나중에 선언되더라도) "정의되지 않음" 팝업이 표시되고 모든 변수 선언이 함수 상단에 일시 중단되기 때문입니다. 따라서 이러한 혼란을 피하려면 사용하려는 모든 변수를 미리 선언하는 것이 가장 좋습니다.
위 코드 조각은 다음과 같이 동작할 수 있습니다.
코드 복사 코드는 다음과 같습니다.

myname = "global"; // 전역 변수
function func() {
var myname; // -> "undefine"
myname = "local";
alert(myname); // "local"}
func()

완전함을 위해 다시 언급하겠습니다. 실행 수준에서는 조금 더 복잡합니다. 코드 처리는 두 단계로 나누어집니다. 첫 번째 단계는 변수, 함수 선언, 일반 형식 매개변수 생성 단계입니다. 두 번째 단계는 함수 표현식과 규정되지 않은 식별자(선언된 변수에 대한)가 생성되는 코드 실행입니다. 그러나 실용적인 목적을 위해 ECMAScript 표준에는 정의되지 않고 일반적으로 동작을 설명하는 데 사용되는 "호이스팅" 개념을 채택합니다.
for 루프(for 루프)
for 루프에서는 배열 또는 인수 및 HTMLCollection 개체와 같은 배열과 유사한 개체의 값을 반복할 수 있습니다. 일반적인 루프 형식은 다음과 같습니다.

코드 복사 코드는 다음과 같습니다.
/ /두 번째로 좋은 루프
for (var i = 0; i < myarray.length; i ) {
// myarray[i]를 사용하여 작업
}

이 형식 반복의 단점은 반복할 때마다 배열의 길이를 얻어야 한다는 것입니다. 이렇게 하면 특히 myarray가 배열이 아니고 HTMLCollection 객체인 경우 코드가 줄어듭니다.
HTMLCollections는 DOM 메서드에서 반환된 개체를 참조합니다. 예:

코드 복사 코드는 다음과 같습니다.
document.getElementsByName()
document.getElementsByClassName()
document.getElementsByTagName()

DOM 표준 이전에 도입된 다른 HTMLCollection이 있으며 아직 거기 사용 중입니다.

코드 복사 코드는 다음과 같습니다.
document.images: 모든 이미지 페이지의 요소
document.links: 모든 태그 요소
document.forms: 모든 양식
document.forms[0].elements: 페이지의 첫 번째 양식에 있는 모든 필드

컬렉션의 문제점은 기본 문서(HTML 페이지)를 실시간으로 쿼리한다는 것입니다. 즉, 컬렉션의 길이에 액세스할 때마다 실시간으로 DOM을 쿼리해야 하며 DOM 작업은 일반적으로 비용이 많이 듭니다.
다음 코드와 같이 값을 반복할 때 배열(또는 컬렉션)의 길이를 캐시하는 것이 좋은 형식인 이유는 다음과 같습니다.

복사 code 코드는 다음과 같습니다.
for (var i = 0, max = myarray.length; i < max; i ) {
/ / Myarray[ i] 사용
}

이 방법으로 이 루프 중에 길이 값을 한 번만 검색할 수 있습니다.
콘텐츠 검색을 위해 반복할 때 HTMLCollection의 캐시 길이는 모든 브라우저에서 2배(Safari3)에서 190배(IE7) 사이로 더 빠릅니다. //zxx: 이 데이터는 참조용으로 매우 오래된 것 같습니다.
루프에서 컬렉션을 명시적으로 수정하려는 경우(예: DOM 요소 추가) 상수 대신 길이 업데이트를 선호할 수 있습니다.
단일 var 형식을 사용하면 다음과 같이 루프에서 변수를 가져올 수 있습니다.

function looper() {
var i = 0,
max,
myarray = []
// ...
for (i = 0, max = myarray.length; i < max; i ) {
// myarray[i]
}
}

로 작업 수행
이 형식은 단일 var 형식을 고수하므로 일관성이라는 이점이 있습니다. 단점은 코드를 리팩토링할 때 전체 루프를 복사하여 붙여넣는 것이 약간 어렵다는 것입니다. 예를 들어, 한 함수에서 다른 함수로 루프를 복사하는 경우 i와 max를 새 함수에 도입할 수 있는지 확인해야 합니다(여기서 유용하지 않으면 원래 함수에서 삭제해야 할 가능성이 높습니다). ) 잃다).
루프의 마지막 조정은 i를 아래 표현식 중 하나로 바꾸는 것입니다.
코드 복사 코드는 다음과 같습니다.

i = i 1
i = 1

JSLint는 "과도한 까다로움"을 조장하기 때문에 이 작업을 수행하라는 메시지를 표시합니다. //zxx: 코드를 더 어렵게 만들려는 의도인 것 같습니다.
직접 무시하면 JSLint의 plusplus 옵션이 false가 됩니다(기본값은 기본값임).
두 가지 변형도 있는데 다음과 같은 이유로 약간 개선되었습니다.
변수가 하나 적음(최대값 없음)
0과 비교하는 데 더 많은 시간이 걸리기 때문에 일반적으로 0까지 카운트다운하는 것이 더 빠릅니다. 배열과 비교하는 것보다 더 효율적입니다. 길이나 기타 0이 아닌 것
코드 복사 코드는 다음과 같습니다.

/ /첫 번째 변형:
var i, myarray = [];
for (i = myarray.length; i–-;) {
// myarray 사용[i ]뭔가
}
//두 번째 방법은 while 루프를 사용하는 것입니다.
var myarray = [],
i = myarray.length;
while (i–-) {
// myarray[ i] to do what
}

이러한 작은 개선 사항은 성능에만 반영되며 JSLint는 i-- 사용에 대해 불평합니다.
for-in 루프(for-in 루프)
For-in 루프는 배열이 아닌 객체를 순회하는 데 사용해야 합니다. for-in을 루프에 사용하는 것을 "열거"라고도 합니다.
기술적으로 배열에 대해 for-in 루프를 사용할 수 있지만(배열은 JavaScript의 객체이기 때문에) 이는 권장되지 않습니다. 배열 객체를 사용자 정의 함수로 강화한 경우 논리 오류가 발생할 수 있기 때문입니다. 또한 for-in에서는 속성 목록의 순서(순서)가 보장되지 않습니다. 따라서 배열에는 일반 for 루프를 사용하고 객체에는 for-in 루프를 사용하는 것이 가장 좋습니다.
객체 속성을 탐색할 때 프로토타입 체인에서 속성을 필터링할 수 있는 매우 중요한 hasOwnProperty() 메서드가 있습니다.
다음 코드 부분을 고려하세요.
코드 복사 코드는 다음과 같습니다.

// 객체
var man = {
손: 2,
다리: 2,
머리: 1
}// 코드 어딘가
// 주어진 모든 객체에 메소드 추가
if (typeof Object.prototype.clone === "undefine") {
Object.prototype.clone = function () {};


이 예에는 객체 리터럴을 사용하여 정의된 man이라는 객체가 있습니다. man 정의가 완료된 후 어딘가에 clone()이라는 유용한 메소드가 객체 프로토타입에 추가되었습니다. 이 프로토타입 체인은 라이브 상태이므로 모든 개체가 자동으로 새 메서드에 액세스할 수 있습니다. man을 열거할 때 clone() 메서드를 사용하지 않으려면 프로토타입 속성을 필터링하기 위해 hasOwnProperty() 메서드를 적용해야 합니다. 필터링이 수행되지 않으면 clone() 함수가 표시되며 이는 대부분의 경우 바람직하지 않습니다.


// 1.
// for-in 루프
for (var i in man) {
if (man.hasOwnProperty(i)) { // 필터
console.log(i, ":", man[i]);
}
}
/* 콘솔 표시 결과
손: 2
다리: 2
머리: 1
*/
// 2.
/ / 반대쪽 예:
// hasOwnProperty()를 확인하지 않은 for-in 루프
for (var i in man) {
console.log(i, ":", man[i])
}
/*
콘솔에 결과가 표시됩니다
hands: 2
legs: 2
heads: 1
clone: ​​​​function()
*/


hasOwnProperty()를 사용하는 또 다른 방법은 Object.prototype에서 메서드를 취소하는 것입니다. 예:


for (var i in man ) {
if (Object.prototype.hasOwnProperty.call(man, i)) { // Filter
console.log(i, ":", man[i])
}
}


man 객체가 hasOwnProperty를 재정의할 때 이름 지정 충돌을 피할 수 있다는 장점이 있습니다. 또한 긴 속성 조회 개체의 모든 방법을 피하고 지역 변수를 사용하여 이를 "캐시"할 수 있습니다.
코드 복사 코드는 다음과 같습니다.

var i, hasOwn = Object.prototype. hasOwnProperty;
for (i in man) {
if (hasOwn.call(man, i)) { // 필터
console.log(i, ":", man[i]); 🎜>}
}

엄밀히 말하면 hasOwnProperty()를 사용하지 않는 것은 실수가 아닙니다. 작업과 코드에 대한 자신감에 따라 루프 속도를 약간 높이기 위해 건너뛸 수도 있습니다. 그러나 현재 객체의 내용(및 해당 프로토타입 체인)이 확실하지 않은 경우에는 hasOwnProperty()를 추가하는 것이 더 안전합니다.
형식 변경(JSLint에 의해 전달되지 않음)은 단순히 중괄호를 무시하고 if 문을 같은 줄에 배치합니다. 장점은 루프 문이 완전한 아이디어처럼 읽힌다는 것입니다(각 요소에는 자체 속성 "X"가 있으며 "X"를 사용하여 작업을 수행할 수 있음).

코드 복사 코드는 다음과 같습니다.
// 경고: JSLint 감지를 통과하지 못했습니다.
var i, hasOwn = Object.prototype.hasOwnProperty for
(i in man) if (hasOwn.call(man, i)) { // 필터
console.log(i, ":", man[i])
}

(내장 프로토타입 보강 아님)
생성자의 프로토타입 속성을 보강하는 것은 기능을 추가하는 매우 강력한 방법이지만 때로는 너무 강력할 때도 있습니다.
내장 생성자 프로토타입(예: Object(), Array() 또는 Function())을 추가하고 싶지만 이렇게 하면 코드를 예측할 수 없게 되기 때문에 유지 관리성이 심각하게 떨어집니다. 귀하의 코드를 사용하는 다른 개발자는 추가하는 방법보다는 내장된 JavaScript 방법을 사용하여 지속적으로 작업하는 것을 선호할 것입니다.
또한 프로토타입에 추가된 속성으로 인해 hasOwnProperty 속성이 사용되지 않을 때 루프에 표시되어 혼란을 야기할 수 있습니다.
따라서 내장 프로토타입을 추가하지 않는 것이 가장 좋습니다. 다음 조건이 충족되는 경우에만 예외를 만드는 규칙을 지정할 수 있습니다.
향후 버전의 ECMAScript 또는 JavaScript 구현에서는 항상 이 기능을 내장 메서드로 구현할 것으로 예상됩니다. 예를 들어 브라우저가 따라잡을 때까지 ECMAScript 5에 설명된 메서드를 추가할 수 있습니다. 이 경우 유용한 메서드를 미리 정의하면 됩니다.
사용자 정의 속성이나 메소드가 더 이상 존재하지 않는 것을 확인한다면 아마도 코드의 다른 곳에 이미 구현되어 있거나 이미 지원되는 브라우저 JavaScript 엔진의 일부일 것입니다.
변경 사항을 명확하게 문서화하고 팀에 전달했습니다.
이 세 가지 조건이 충족되면 다음 형식으로 프로토타입에 맞춤형 추가를 할 수 있습니다.

코드 복사 코드는 다음과 같습니다:
if (typeof Object.protoype.myMethod !== "function") {
Object.protoype.myMethod = function () {
// 구현. ..
}
}

스위치 패턴
다음과 유사한 스위치 문을 사용하여 가독성과 견고성을 높일 수 있습니다.

코드 복사 코드는 다음과 같습니다.
var inform_me = 0,
result =
switch( Inspection_me) {
결과 = "0";
중단;
사례 1:
결과 = "1";
기본값:
result = "unknown";
}


이 간단한 예에서 따르는 스타일 규칙은 다음과 같습니다.
각 대소문자를 정렬하고 전환합니다(중괄호 들여쓰기 규칙 제외)
각 케이스의 코드 들여쓰기
각 케이스는 break 클리어로 끝납니다
삽입을 피하세요(break는 의도적으로 무시됩니다). 통과선이 최선의 접근 방식이라고 확신하는 경우 일부 독자에게는 잘못 보일 수 있으므로 이를 문서화하십시오.
기본값으로 스위치 종료: 일치하는 사례가 없더라도 항상 정상적인 결과가 나오는지 확인하세요.
암시적 유형 변환 방지
JavaScript 변수는 비교 시 암시적으로 유형 변환됩니다. 그렇기 때문에 false == 0 또는 "" == 0이 true를 반환합니다. 암시적 유형 변환의 혼란을 방지하려면 값 유형과 표현식 유형을 비교할 때 항상 === 및 !== 연산자를 사용하십시오.



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

var zero = 0;
if (zero === false) {
// 0은 0이므로 실행되지 않고 false가 아닙니다.
}
// 부정 예시
if (zero == false) {
// 실행됨...
}

==이면 충분=== 중복된다는 생각도 있습니다. 예를 들어, typeof를 사용하면 문자열을 반환한다는 것을 알 수 있으므로 엄격한 동등성을 사용할 이유가 없습니다. 그러나 JSLint는 엄격한 동등성을 요구하므로 코드를 보다 일관되게 보이게 하고 코드를 읽을 때 에너지 소비를 줄입니다. ("== 의도적인가 아니면 실수인가?")
eval() 피하기
현재 코드에서 eval()을 사용하는 경우 "eval()은 악마다"라는 격언을 기억하세요. 이 메서드는 모든 문자열을 받아들이고 이를 JavaScript 코드로 처리합니다. 문제의 코드가 미리 알려진 경우(런타임에 결정되지 않음) eval()을 사용할 이유가 없습니다. 코드가 런타임 시 동적으로 생성되는 경우 eval을 사용하지 않고 동일한 목표를 달성하는 더 좋은 방법이 있습니다. 예를 들어 대괄호 표기법을 사용하여 동적 속성에 액세스하는 것이 더 좋고 간단합니다.
코드 복사 코드는 다음과 같습니다. :

// 부정 예
var property = "name";
alert(eval("obj." property))
// Better
var property = "name ";
alert(obj[property]);

실행 중인 코드(예: 네트워크에서)가 보안 위험에 노출될 수도 있습니다. 변조되었습니다. 이는 Ajax 요청의 JSON 응답을 처리할 때 매우 흔히 발생하는 부정적인 교훈입니다. 이러한 경우 안전과 효율성을 보장하기 위해 JavaScript의 내장 메서드를 사용하여 JSON 응답을 구문 분석하는 것이 가장 좋습니다. 브라우저가 JSON.parse()를 지원하지 않는 경우 JSON.org의 라이브러리를 사용할 수 있습니다.
setInterval(), setTimeout() 및 Function() 생성자에 문자열을 전달하는 것은 대부분의 경우 eval()을 사용하는 것과 유사하므로 피해야 한다는 점을 기억하는 것도 중요합니다. 뒤에서 JavaScript는 프로그램에 전달한 문자열을 평가하고 실행해야 합니다.
코드 복사 코드는 다음과 같습니다.

// 부정 예
setTimeout("myFunc()", 1000)
setTimeout("myFunc(1, 2, 3)", 1000); 더 나은
setTimeout(myFunc, 1000);
setTimeout(function () {
myFunc(1, 2, 3);
}, 1000);

new Function() 구문은 eval()과 유사하므로 주의해서 접근해야 합니다. 이는 강력한 구조일 수 있지만 종종 오용됩니다. 반드시 eval()을 사용해야 한다면 대신 new Function()을 사용하는 것을 고려해 볼 수 있습니다. new Function()의 코드 평가는 로컬 함수 범위에서 작동하므로 코드에서 평가되는 var로 정의된 모든 변수는 자동으로 전역 변수가 되지 않으므로 작은 잠재적 이점이 있습니다. 자동 전역 변수를 방지하는 또 다른 방법은 eval() 호출을 즉시 함수로 래핑하는 것입니다.
un만이 네임스페이스를 전역 변수로 오염시키는 다음 예를 생각해 보세요.

코드 복사 코드는 다음과 같습니다.
console.log(typeof un) / / "정의되지 않음"
console.log(typeof deux); // "정의되지 않음"
console.log(typeof trois); // "정의되지 않음"
var jsstring = "var un = 1; console.log log(un );";
eval(jsstring); // "1"을 기록합니다.
jsstring = "var deux = 2; console.log(deux);";
new Function(jsstring)( ); / / 로그 "2"
jsstring = "var trois = 3; console.log(trois);"
(function () {
eval(jsstring);
}() ); / / 로그 "3"
console.log(typeof un); // 숫자
console.log(typeof deux) // "정의되지 않음"
console.log(typeof trois); / "undefine "

eval()과 Function 구문의 또 다른 차이점은 eval()이 범위 체인을 방해할 수 있는 반면 Function()이 더 안전하다는 것입니다. Function()을 어디에서 실행하든 전역 범위만 표시됩니다. 따라서 지역변수 오염을 효과적으로 방지할 수 있다. 다음 예에서 eval()은 Function이 수행할 수 없는 외부 범위의 변수에 액세스하고 수정할 수 있습니다(Function과 new Function을 사용하는 것은 동일합니다).

코드 복사 코드는 다음과 같습니다.
(function () {
var local = 1 ;
eval("local = 3; console.log(local)"); // "3"을 기록합니다.
console.log(local); // "3"을 기록합니다.
}( ));
(function () {
var local = 1;
Function("console.log(typeof local);")(); // 정의되지 않은 로그를 기록합니다
}());


parseInt())를 사용한 숫자 변환
parseInt()를 사용하면 문자열에서 숫자 값을 가져올 수 있습니다. 이 메서드는 종종 생략되지만 그렇게 해서는 안 되는 또 다른 기수 매개변수를 허용합니다. 문자열이 "0"으로 시작하면 문제가 발생할 수 있습니다. 예를 들어, 일시적으로 양식 필드를 입력할 때 ECMAScript 3에서는 "0"으로 시작하는 문자열이 8진수로 처리되지만 ECMAScript에서는 변경되었습니다. 5. 모순과 예상치 못한 결과를 방지하려면 항상 기수 매개변수를 지정하십시오.
코드 복사 코드는 다음과 같습니다.

var Month = "06",
year = "09";
month = parsInt(month, 10);
year = parsInt(year, 10)

이 예에서는 기본 매개변수를 무시합니다. 예를 들어, parInt(연도)를 사용하는 경우 "09"는 8진수로 처리되고(예: parsInt(year, 8) 실행) 09는 8진수의 유효한 숫자가 아니기 때문에 반환된 값은 0이 됩니다.
대체 방법은 다음을 포함하여 문자열을 숫자로 변환하는 것입니다.
코드 복사 코드는 다음과 같습니다.

"08" // 결과는 8입니다.
Number("08") // 8

parseInt를 사용하기 때문에 일반적으로parseInt()보다 빠릅니다. () 메소드는 이름에서 알 수 있듯이 단순한 구문 분석 및 변환이 아닙니다. 그러나 예를 들어 "08 hello"를 입력하려는 경우,parseInt()는 숫자를 반환하고, 그렇지 않으면 NaN으로 끝납니다.
코딩 규칙
코딩 규칙을 설정하고 따르는 것이 중요합니다. 이렇게 하면 코드가 일관되고 예측 가능하며 읽기 쉽고 이해하기 쉬워집니다. 팀에 합류한 새로운 개발자는 사양을 읽고, 다른 팀 구성원이 작성한 코드를 이해하고, 작업을 더 빠르게 시작할 수 있습니다.
회의나 메일링 리스트에서는 코딩 표준의 특정 측면(예: 코드 들여쓰기, 탭 또는 공백)에 대해 열띤 논쟁이 많이 발생합니다. 당신이 조직에서 규범의 채택을 제안하는 사람이라면, 다양한 반대나 강력한 의견에 직면할 준비를 하십시오. 규범의 세부 사항에 집착하는 것보다 규범을 확립하고 준수하는 것이 훨씬 더 중요하다는 것을 기억하십시오.
들여쓰기
들여쓰기 없이는 기본적으로 코드를 읽을 수 없습니다. 유일하게 나쁜 점은 들여쓰기가 일관성이 없다는 것입니다. 왜냐하면 사양을 따르는 것처럼 보이지만 도중에 혼란과 놀라움을 초래할 수 있기 때문입니다. 들여쓰기를 적절하게 사용하는 것이 중요합니다.
일부 개발자는 누구나 자신이 원하는 공백 수로 탭을 표시하도록 편집기를 조정할 수 있기 때문에 탭 들여쓰기를 선호합니다. 어떤 사람들은 공백을 좋아합니다. 일반적으로 4개는 팀의 모든 사람이 동일한 기준을 따르는 한 중요하지 않습니다. 예를 들어 이 책에서는 들여쓰기를 위해 4개의 공백을 사용합니다. 이는 JSLint의 기본 들여쓰기이기도 합니다.
어떤 내용을 들여쓰기해야 하나요? 규칙은 간단합니다. 중괄호 안에 무엇이 들어가는지입니다. 이는 함수 본문, 루프(do, while, for, for-in), if, 스위치 및 객체 리터럴의 객체 속성을 의미합니다. 다음 코드는 들여쓰기를 사용한 예시입니다.
코드 복사 코드는 다음과 같습니다.

함수 외부 (a, b) {
var c = 1,
d = 2,
내부
if (a > b) {
inner = 함수 () {
return {
r: c - d
};
}
} else {
inner = function () {
return {
r: c d
};
};
}
return inner;
}

중괄호{}(중괄호)
중괄호라고도 함 , 아래 동일)은 선택사항인 경우에도 항상 사용해야 합니다. 기술적으로 in 또는 for에 문이 하나만 있는 경우 중괄호가 필요하지 않지만 어쨌든 항상 중괄호를 사용해야 합니다. 이렇게 하면 코드가 더 일관되고 업데이트하기가 더 쉬워집니다.
문이 하나만 있는 for 루프가 있다고 가정해 보세요. 구문 분석 오류 없이 중괄호를 무시할 수 있습니다.
코드 복사 코드는 다음과 같습니다.

// 잘못된 예
( var i = 0; i < i = 1)
alert(i);

그러나 나중에 메인 루프에 다른 코드 줄이 추가되면 어떻게 될까요?
코드 복사 코드는 다음과 같습니다.

// 잘못된 예
( var i = 0; i < i = 1)
alert(i);
alert(i "는 "(i % 2 ? "홀수")

두 번째 경고는 이미 루프 외부에 있으므로 들여쓰기가 사용자를 속였을 수 있습니다. 장기적인 계획을 위해서는 항상 코드 한 줄에 해당하는 중괄호를 사용하는 것이 가장 좋습니다.
코드 복사 코드는 다음과 같습니다.

// 좋은 예
for (var i = 0; i < 10; i = 1) {
alert(i); >}

조건이 유사한 경우:

코드 복사 코드는 다음과 같습니다.
// Bad
if (true)
alert(1)
else
alert(2)
// OK
if (true); {
alert(1);
} else {
alert(2);
}

Brace Location 열기)
개발자마다 위치에 대한 선호도가 다릅니다. 여는 중괄호 - in 같은 줄 또는 다음 줄.

코드 복사 코드는 다음과 같습니다.
if (true) {
alert ("참입니다!");
}
//또는
if (참)
{
alert("참입니다!")
}

이 예에서는 인은 인을 보고 지혜는 지혜를 보지만 괄호의 위치가 다르면 행동이 달라지는 경우도 있습니다. 이는 세미콜론 삽입 메커니즘 때문입니다. JavaScript는 까다롭지 않으며 세미콜론으로 코드 줄을 끝내지 않기로 선택한 경우 이를 보완합니다. 예를 들어 객체 리터럴을 반환하고 여는 괄호가 다음 줄에 있는 경우 이 동작으로 인해 문제가 발생할 수 있습니다.

코드 복사 코드는 다음과 같습니다.
// 경고: 예상치 못한 반환 값
function func() {
return
// 다음 코드는 실행되지 않습니다
{
name : "Batman"
}
}

함수가 name 속성을 가진 객체를 반환할 것으로 기대한다면 놀랄 것입니다. 암시적 세미콜론으로 인해 함수는 정의되지 않은 값을 반환합니다. 이전 코드는

코드 복사 코드는 다음과 같습니다.
/ / 경고: 예기치 않은
function func()의 반환 값 {
return undefine;
// 다음 코드는 실행되지 않습니다.
{
name : "Batman"
}
}

즉, 항상 중괄호를 사용하고 항상 같은 줄에 중괄호 앞에 명령문을 넣으세요.

코드 복사 코드는 다음과 같습니다.
function func() {
return {
name : "Batman"
};


세미콜론에 대한 참고 사항: 중괄호를 사용하는 것과 마찬가지로 JavaScript 파서가 암시적으로 세미콜론을 생성할 수 있더라도 항상 세미콜론을 사용해야 합니다. 이는 보다 과학적이고 엄격한 코드를 촉진할 뿐만 아니라 이전 예제에서 볼 수 있듯이 혼란스러운 영역을 해결하는 데도 도움이 됩니다.
공백(White Space)
공백을 사용하는 것도 코드의 가독성과 일관성을 높이는 데 도움이 됩니다. 영어 문장을 작성할 때 쉼표와 마침표 뒤에 공백을 사용합니다. JavaScript에서는 목록과 같은 표현식(쉼표와 동일) 및 닫는 문("아이디어" 완성과 관련) 뒤에 공백을 추가하여 동일한 논리를 따를 수 있습니다.
공백을 사용하기에 적합한 위치는 다음과 같습니다.
for 루프의 세미콜론으로 구분된 부분: 예: for (var i = 0; i < 10; i = 1) {...}
for 루프 다음에서 초기화된 여러 변수(i 및 max): for (var i = 0, max = 10; i < max; i = 1) {...}
배열 항목을 구분하는 쉼표 뒤: var a = [1, 2, 3];
객체 속성의 쉼표와 속성 이름과 속성 값을 구분하는 콜론 뒤: var o = {a: 1, b: 2}
한정된 함수 매개변수 : myFunc(a , b, c)
함수 선언의 중괄호 앞: function myFunc() {}
익명 함수 표현식 뒤 function: var myFunc = function () {}
사용 모든 연산자와 피연산자를 구분하는 공백은 또 다른 좋은 용도입니다. 즉, -, *, =, <, >, <=, >=, ===, !==, &&, ||, 공백은 다음과 같습니다. = 등 전후에 필요합니다.


// 느슨하고 일정한 간격
// 코드를 더 읽기 쉽게 만듭니다
// 더 "통기성"으로 만듭니다.
var d = 0,
a = b
if (a && b && c) {
d = a % c;
a = d;
}
// 부정 예시
// 간격이 없거나 고르지 않음
// 코드를 혼란스럽게 만듭니다
var d = 0,
a = b
if (a&&b&c) {
d=a % c
a = d
}


마지막으로 주목해야 할 공간은 중괄호 사이의 간격입니다. 공백을 사용하는 것이 가장 좋습니다. 함수, if-else 문, 루프 및 객체 리터럴의 왼쪽 중괄호({) 앞에

else 또는 while 사이에 있는 오른쪽 중괄호(})
공백은 다음과 같습니다. 사용되는 한 가지 단점은 파일 크기가 증가하지만 압축에는 이러한 문제가 없다는 것입니다.
코드 가독성에서 흔히 간과되는 측면은 세로 공백을 사용하는 것입니다. 문헌에서 단락을 구분하는 것처럼 빈 줄을 사용하여 코드 단위를 구분할 수 있습니다.
명명 규칙
코드를 더욱 예측 가능하고 유지 관리하기 쉽게 만드는 또 다른 방법은 명명 규칙을 채택하는 것입니다. 이는 변수와 함수의 이름을 같은 방식으로 지정해야 함을 의미합니다.
다음은 제안된 명명 규칙을 그대로 채택하거나 원하는 대로 조정할 수 있습니다. 마찬가지로, 규범이 무엇인지보다 규범을 따르는 것이 더 중요합니다.
생성자를 대문자로 작성합니다(대문자화 생성자)
JavaScript에는 클래스가 없지만 new가 호출하는 생성자가 있습니다.
var adam = new Person()
생성자는 여전히 간단하기 때문입니다. 함수 , 함수 이름만 보면 이것이 생성자인지 일반 함수인지를 알 수 있습니다.
생성자 이름을 지정할 때 대문자의 첫 글자는 암시적인 효과가 있습니다. 소문자로 이름이 지정된 함수 및 메서드는 new로 호출하면 안 됩니다.
코드 복사 코드는 다음과 같습니다.

function MyConstructor() {...}
function myFunction() {...}

단어 분리 )
변수나 함수 이름에 여러 단어가 포함된 경우 단어 분리에 대한 통일된 표준을 따르는 것이 가장 좋습니다. 각 단어의 첫 글자를 대문자로 표기하세요.
생성자의 경우 MyConstructor()와 같이 대문자 카멜 표기법을 사용할 수 있습니다. 함수 및 메소드 이름에는 myFunction(),calculateArea() 및 getFirstName()과 같은 소문자 카멜 표기법을 사용할 수 있습니다.
변수가 함수가 아니면 어떻게 되나요? 개발자는 종종 camelCase 표기법을 사용하지만 대안은 소문자 단어와 밑줄을 사용하는 것입니다(예: first_name, favorite_bands 및 old_company_name). 이 표기법은 함수를 다른 식별자(프로토타입 및 객체)와 시각적으로 구별하는 데 도움이 됩니다.
ECMAScript 속성과 메서드는 Camel 표기법을 사용하지만 여러 단어로 구성된 속성 이름은 드물습니다(정규 표현식 객체의 lastIndex 및ignoreCase 속성).
기타 명명 패턴
때때로 개발자는 언어 기능을 보완하거나 대체하기 위해 명명 규칙을 사용합니다.
예를 들어 JavaScript에서는 상수를 정의할 수 있는 방법이 없습니다(Number, MAX_VALUE와 같은 일부 내장 상수는 있지만). 따라서 개발자는 전체 대문자 표기 규칙을 사용하여 수명 주기 동안 변경되지 않는 변수의 이름을 지정합니다. 다음과 같은 프로그램:
// 멀리서만 볼 수 있는 귀중한 상수
var PI = 3.14,
MAX_WIDTH = 800
코드 복사
모두 대문자로 사용하는 또 다른 규칙이 있습니다. : 전역변수 이름은 모두 대문자입니다. 전역 변수를 모두 대문자로 명명하면 전역 변수의 수를 줄이는 동시에 쉽게 구별할 수 있게 됩니다.
사양을 사용하여 기능을 시뮬레이션하는 또 다른 방법은 비공개 멤버를 사용하는 것입니다. JavaScript에서는 진정한 비공개가 가능하지만 개발자는 비공개 속성이나 메서드를 나타내기 위해 밑줄 접두사를 사용하는 것이 더 쉽다는 것을 알게 됩니다. 다음 예를 고려하십시오.
코드 복사 코드는 다음과 같습니다.

var person = {
getName: function () {
return this._getFirst() ' ' this._getLast()
},
_getFirst: function() {
// ...
},
_getLast: 함수 () {
// ...
}
};
이 예에서 getName()은 공개 메소드와 부분적으로 안정적인 API를 나타냅니다. 그리고 _getFirst() 및 _getLast()는 비공개를 나타냅니다. 이들은 여전히 ​​일반적인 공개 메소드이지만 밑줄 접두사는 person 객체의 사용자에게 이러한 메소드가 다음 버전에서 작동이 보장되지 않으며 직접 사용할 수 없음을 경고하는 데 사용됩니다. noman 옵션을 :false로 설정하지 않으면 JSLint는 밑줄 접두사를 사용하지 않습니다.
다음은 몇 가지 일반적인 _private 사양입니다.
name_ 및 getElements_()와 같이 개인용을 나타내려면 뒤에 밑줄을 사용하십시오.
_protected 속성을 나타내려면 밑줄 접두사를 사용하고 __private(Private)을 나타내려면 두 개의 밑줄 접두사를 사용하십시오. ) 속성
Firefox의 일부 내장 변수 속성은 언어의 기술적 부분에 속하지 않으며 __proto__ 및 __parent__와 같이 두 개의 선행 밑줄과 두 개의 후행 밑줄로 표시됩니다.
댓글 쓰기
다른 사람이 당신처럼 코드를 건드리지 않더라도 코드에 댓글을 달아야 합니다. 보통 문제를 깊이 있게 공부하면 그 코드가 어떤 용도로 사용되는지 확실히 알 수 있지만, 일주일 뒤에 다시 돌아오면 그것이 어떻게 작동하는지 알아내기 위해 많은 뇌세포를 소비했을 것입니다.
분명히 주석은 극단적으로 갈 수 없습니다. 각각의 개별 변수 또는 별도의 줄입니다. 그러나 일반적으로 모든 함수, 해당 매개변수 및 반환 값 또는 특이한 기술이나 방법을 문서화해야 합니다. 주석은 미래의 코드 독자에게 많은 힌트를 줄 수 있다는 점을 기억하십시오. 독자가 코드를 이해하려면 (너무 많이 읽지 않고도) 주석과 함수 속성 이름만 있으면 됩니다. 예를 들어, 특정 작업을 수행하는 프로그램 라인이 5~6개 있을 때 해당 라인의 목적과 해당 라인이 존재하는 이유에 대한 설명을 제공하면 독자는 이 세부 정보를 건너뛸 수 있습니다. 주석과 코드의 비율에 대한 엄격하고 빠른 규칙은 없으며 코드의 일부 부분(예: 정규 표현식)에는 코드보다 주석이 더 많을 수 있습니다.
가장 중요하지만 따라하기 가장 어려운 습관은 댓글을 최신 상태로 유지하는 것입니다. 오래된 댓글은 댓글이 전혀 없는 것보다 오해의 소지가 더 많기 때문입니다.
저자 소개
Stoyan Stefanov는 Yahoo! 웹 개발자, 작가, 기고자이자 여러 O'Reilly 도서의 기술 평론가입니다. 그는 컨퍼런스와 자신의 블로그(www.phpied.com)에서 웹 개발 주제에 관해 자주 강연합니다. Stoyan은 또한 smush.it 이미지 최적화 도구의 창시자이자 YUI 기고자이자 Yahoo의 성능 최적화 도구 YSlow 2.0의 설계자이기도 합니다.
이 기사의 출처: http://www.zhangxinxu.com/wordpress/?p=1173
원문 영문 텍스트: http://net.tutsplus.com/tutorials/javascript-ajax/the- Essentials-of- writing-high-quality-javascript/
동기화 및 결론
이 글은 디렉토리 색인에 동기화되었습니다: JavaScript 시리즈에 대한 심층적 이해
심층 원문 작성, 번역, 재인쇄 등 JavaScript 시리즈 기사에 대한 이해 다른 유형의 기사가 도움이 된다면 추천하고 지원하여 삼촌이 글을 쓸 동기를 부여해 주세요.
관련 라벨:
원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿