소개
많은 전통적인 언어 (C/C ++/Java/C#등)에서 기능은 2 등석 시민으로 존재합니다. 언어 키워드로 만 함수를 선언 한 다음 호출 할 수 있습니다. 함수를 매개 변수로 다른 함수로 전달하거나 로컬 변수에 값을 할당하거나 반환 값으로 할당 해야하는 경우 기능 포인터 및 프록시 (Delegate)와 같은 특수 메소드를 통해 획기적인 방법을 만들어야합니다.
JavaScript 세계에서 기능은 일류 시민입니다. 전통적인 기능 (선언 및 호출)을 사용하는 모든 방법을 가질뿐만 아니라 값을 할당하고 매개 변수를 전달하며 간단한 값처럼 반환 할 수 있습니다. 이러한 기능은 일류 기능이라고도합니다. 뿐만 아니라 JavaScript의 기능도 클래스 생성자 역할을하며 기능 클래스의 사례이기도합니다. 이러한 여러 정체성은 JavaScript 기능을 매우 중요하게 만듭니다.
1. JavaScript 함수 엔트리 레벨
평범한 언어와 마찬가지로 JavaScript 기능은 먼저 선언의 원칙을 따르고 사용합니다. 함수 이름에는 문자, 숫자, 밑줄 또는 $ 만 포함 할 수 있으며 숫자로 시작할 수 없습니다. 기능을 선언하는 두 가지 일반적인 방법이 있습니다.
코드 사본은 다음과 같습니다.
// 함수 myFunc을 직접 선언합니다
함수 myfunc (/ * arguments */) {
}
// 로컬 변수 myFunc에 익명 함수를 할당합니다
var myfunc = function (/ * arguments */) {
}
위의 두 함수 선언 방법에는 미묘한 차이가 있습니다. 첫 번째 방법은 선언 될 때 명명 된 함수, 전, 호출 후 선언 된 기능이든, 심지어 실행되지 않는 위치 (예 : 반환 문 또는 바닥에서는 사실이 아닌 지점에서) 전체 범위에서 액세스 할 수 있습니다. 두 번째 방법은 변수에 익명 함수를 할당하는 것입니다. 엄밀히 말하면, 이것은 함수 선언이 아니라 함수 표현식입니다. 할당하기 전에이 함수는 모든 코드로 액세스 할 수 없으므로 호출 전에 할당을 완료해야합니다. 그렇지 않으면 "TypeError : undefined는 함수가 아닙니다"라고 호출 할 때 오류가 나타납니다. 예를 들어:
코드 사본은 다음과 같습니다.
myfunc1 (); // myFunc1은 직접 선언 방법을 사용하기 때문에 정상적으로 호출 될 수 있습니다.
함수 myfunc1 () {
}
myfunc2 (); // Error TypeError : 정의되지 않은 것은 함수가 아닙니다
var myfunc2 = function () {
};
기능의 기본 호출 방법은 전통적인 언어와 같은 방식으로 호출됩니다 : myfunc (). JavaScript 기능은 또한 직접 또는 간접적 인 재귀 호출을 지원합니다. 예를 들어, 클래식 Fibonacci 기능은 다음과 같은 JavaScript로 구현할 수 있습니다.
코드 사본은 다음과 같습니다.
기능 fib (n) {
if (n == 1 || n == 2) {
반환 1;
} 또 다른 {
리턴 fib (n -2) + fib (n -1);
}
}
JavaScript의 함수는 가변 길이 매개 변수를 처리 할 수 있습니다. 그들은 모두 함수 내부에 인수라는 로컬 변수를 가지고 있습니다. 호출 할 때 전달 된 모든 매개 변수를 포함하고 매개 변수 수를 나타내는 길이 속성을 갖는 배열과 같은 객체입니다. 예를 들어:
코드 사본은 다음과 같습니다.
기능 test () {
경고 (arguments.length);
}
시험 (1); // 1
테스트 (1, 'a'); // 2
test (true, [], {}); // 3 인수를 사용하여 C 언어로 printf와 유사한 함수를 구현하고 방법의 다형성을 구현하는 데 사용될 수도 있습니다.
2. 고급 JavaScript 함수
2.1 익명 및 중첩 된 기능
JavaScript에서는 익명 함수 (익명 함수)라는 이름이없는 함수를 선언 할 수 있습니다. 동시에 JavaScript는 또한 내부 함수, 중첩 함수라고하는 함수 선언을 허용하며 중첩 함수의 범위는 전체 상위 기능입니다.
함수 선언의 이전 부분에서 익명 함수와 중첩 된 기능의 사용을 보았습니다. 익명의 기능에는 이름이 없으므로 컨텍스트를 오염시키기 위해 새로운 변수를 도입하지 않으며 새로운 변수 스코프를 가져올 것입니다. 따라서 익명 기능은 종종 지구 환경 오염을 방지하는 데 사용됩니다.
JavaScript 런타임에는 특별한 글로벌 객체가 있습니다. 이 개체는 글로벌 기능과 변수를 저장합니다. 실제 개발에서는 여러 타사 라이브러리 또는 여러 JS 파일이 종종 사용됩니다. 우연히 전역 객체에 중복 변수 또는 함수 선언을 도입하면 코드 실행에 혼란이 발생합니다. 예를 들어, 두 개의 JS 파일이 연속적으로 소개되고 자체 기능 로그는 내부 사용으로 정의됩니다. 두 번째 소개 된 기능은 첫 번째 기능의 정의를 덮어 쓰고 오류를 던지지 않습니다. 후속 실행에서 로그 함수를 호출하면 오류가 발생할 수 있습니다. 이때 익명 기능을 사용하여 전체 JS에 논리를 랩핑하면이 오류를 피할 수 있습니다. 이 방법은 대부분의 오픈 소스 JS 라이브러리에서 사용되었습니다.
코드 사본은 다음과 같습니다.
(function () {// 익명 함수
함수 로그 (msg) {
Console.log (MSG);
}
// 다른 코드
} ()); // 즉시 실행하십시오
위의 코드는 간단한 예입니다. 로그 함수의 범위는이 익명 함수로 제한됩니다. 익명 함수는 외부의 괄호 () 쌍에 포함되어 함수 표현식을 형성합니다. 표현식의 값은 함수이며, 한 쌍의 브래킷이 뒤 따릅니다. 함수가 즉시 실행되므로 원래 코드가 정상적으로 실행될 수 있습니다. 그러나 이러한 방식으로 선언 된 기능, VAR 등을 통해 선언 된 변수는 내부이며 익명 함수 이외의 코드는 액세스 할 수 없습니다. 일부 기능을 인터페이스로 노출 해야하는 경우 몇 가지 방법이 있습니다.
코드 사본은 다음과 같습니다.
var mylib = (function (global) {
함수 로그 (msg) {
Console.log (MSG);
}
log1 = log; // 방법 1 : VAR없이 변수 선언의 기본 동작을 사용하여 LOG1의 글로벌 변수가됩니다 (권장되지 않음)
Global.log2 = log; // 메소드 2 : Global Object에 Log2 속성을 직접 추가하여 로그 함수에 할당합니다 (권장)
return {// 메소드 3 : 익명 함수를 통해 일련의 인터페이스 함수 수집 객체를 반환하고 글로벌 변수 mylib (권장)에 할당합니다.
로그 : 로그
};
}(창문));
2.2 고차 기능
함수가 매개 변수 또는 리턴 값으로 사용되면이를 고차 함수라고합니다. JavaScript의 함수는 고차 기능으로 사용될 수 있으며, 이는 첫 번째 유형의 함수의 기능이기도합니다. 아래 의이 두 가지 사용 방법을 분석하겠습니다.
코드 사본은 다음과 같습니다.
기능 부정 (n) {
반품 -n; // n의 반대 값을 취합니다
}
기능 제곱 (n) {
반환 n*n; // n의 제곱
}
기능 프로세스 (Nums, Callback) {
var result = [];
for (var i = 0, 길이 = nums.length; i <length; i ++) {
결과 [i] = 콜백 (nums [i]); // 배열의 모든 요소를 배열 NUM을 처리하기 위해 콜백으로 전달하고 결과적으로 리턴 값을 저장합니다.
}
반환 결과;
}
var nums = [-3, -2, -1, 0, 1, 2, 3, 4];
var n_neg = 프로세스 (nums, negative);
// n_neg = [3, 2, 1, 0, -1, -2, -3, -4];
var n_square = 프로세스 (Nums, Square);
// n_square = [9, 4, 1, 0, 1, 4, 9, 16];
위의 코드는 기능을 다른 함수 프로세스 호출로 전달하는 예를 보여줍니다. 프로세스 함수의 구현에서 콜백은 블랙 박스로 간주되어 매개 변수를 전달한 다음 리턴 값을 얻습니다. 콜백의 특정 구현은 통화 전에 명확하지 않습니다. 20 및 22 라인이 실행될 때만 콜백은 각각 음수 또는 정사각형으로 표시되며 각 요소는 반대 값 또는 제곱 값으로 사용됩니다.
코드 사본은 다음과 같습니다.
함수 생성기 () {
var i = 0;
return function () {
반환 i ++;
};
}
var gen1 = generator (); // 자연 번호 생성기를 얻습니다
var gen2 = generator (); // 다른 자연 번호 생성기를 얻습니다
var r1 = gen1 (); // r1 = 0
var r2 = gen1 (); // r2 = 1
var r3 = gen2 (); // r3 = 0
var r4 = gen2 (); // r4 = 1
위의 코드는 함수를 반환 값으로 사용하는 예를 보여줍니다. 생성기는 자연 번호 생성기 기능이며 리턴 값은 자연 번호 생성기 기능입니다. 생성기가 호출 될 때마다 익명 함수가 결과적으로 반환됩니다. 이 익명 기능은 실제로 호출 될 때 각 자연 번호를 차례로 반환합니다. 이 익명 함수가 호출 될 때마다 생성기의 변수 i가 1 씩 증가합니다. 이는 실제로 폐쇄입니다. 아래에 폐쇄를 소개합시다.
2.3 폐쇄
클로저는 새로운 개념이 아니며 많은 기능적 언어가 클로저를 사용합니다. JavaScript에서는 임베디드 함수에서 외부 함수 범위 내에서 변수를 사용하면 클로저를 사용합니다. 일반적으로 사용되는 비유를 사용하여 클로저와 클래스 간의 관계를 설명하십시오. 클래스는 기능이있는 데이터이며 클래스는 데이터와의 함수입니다.
클로저에 사용 된 변수는 부모 함수가 돌아올 때 해제되지 않지만 폐쇄 수명주기가 끝나면 끝납니다. 예를 들어, 이전 섹션의 생성기 예에서와 같이 Gen1과 Gen2는 각각 독립 변수 I을 사용합니다 (Gen1의 I가 1 씩 증가 할 때, Gen2의 I는 영향을받지 않을 것입니다). 두 변수 Gen1 또는 Gen2 변수가 JavaScript 엔진에 의해 수집되지 않는 한, 해당 변수는 해제되지 않습니다. JavaScript 프로그래밍에서 클로저는 무의식적으로 사용됩니다. 이 클로저의 기능은 사용하기 쉽지만 메모리 누출 문제로 쉽게 이어집니다. 예를 들어:
코드 사본은 다음과 같습니다.
var elem = document.getElementById ( 'test');
elem.addeventListener ( 'click', function () {
ALERT ( 'CLICKED' + ELEM.TAGNAME);
});
이 코드의 목적은 노드를 클릭 할 때 레이블 이름을 표시하는 것입니다. DOM 노드의 클릭 이벤트 처리 기능으로 익명 기능을 등록합니다. DOM Object Elem은 함수에서 참조되어 폐쇄를 형성합니다. 이것은 원형 기준, 즉 : dom-> clossary-> dom-> clossary를 생성합니다 ... 폐쇄가 풀리기 전에 DOM 객체는 해제되지 않습니다. 그리고 폐쇄는 DOM 객체의 이벤트 처리 기능으로 존재하므로 DOM 객체가 해제되기 전에 폐쇄가 해제되지 않습니다. DOM 객체가 DOM 트리에서 삭제 되더라도이 원형 기준의 존재로 인해 DOM 객체 나 폐쇄는 해제되지 않습니다. 이 메모리 누출은 다음 방법을 사용하여 피할 수 있습니다.
코드 사본은 다음과 같습니다.
var elem = document.getElementById ( 'test');
elem.addeventListener ( 'click', function () {
Alert ( '당신은' + this.tagname을 클릭했습니다); // 더 이상 Elem 변수를 직접 참조하지 않습니다
});
위의 코드에서, 이것은 Elem 대신에 사용되므로 (이 포인터는 DOM 이벤트 처리 기능의 DOM 요소 자체를 가리 킵니다) JS 런타임은 더 이상 기능이 부모 클래스 변수를 사용한다고 믿지 않으므로 더 이상 폐쇄를 형성하지 않습니다.
폐쇄는 또한 많은 비슷한 메모리 누출 문제를 가져올 것입니다. 코드를 작성할 때만 폐쇄에주의를 기울이고 그러한 문제를 피하려고 노력할 수 있습니다.
2.4 클래스 생성자
JavaScript 함수도 클래스 생성자로 사용되므로 새로운 키워드를 사용하여 함수를 선언하는 한 클래스 인스턴스를 생성 할 수 있습니다.
코드 사본은 다음과 같습니다.
기능인 (이름) {
this.name = 이름;
this.tostring = function () {
'안녕하세요,' + this.name + '!';
};
}
var p = 새로운 사람 ( 'Ghosttheaven');
경고 (p); // 안녕하세요, Ghosttheaven! 위의 예에서는 개인 기능이 클래스 생성자로 사용됩니다. 이 시점에서 이것은 새로 생성 된 인스턴스 객체를 가리키며 인스턴스에 속성과 메소드를 추가 할 수 있습니다. 자세한 객체 지향 JavaScript 프로그래밍은이 기사를 참조하십시오. 여기서 말하고 싶은 것은 JavaScript 함수를 클래스 생성자로 사용할 때의 반환 값 문제입니다.
코드 사본은 다음과 같습니다.
함수 myclass (이름) {
this.name = 이름;
반환 이름; // 생성자의 반환 값?
}
var obj1 = new myclass ( 'foo');
var obj2 = myclass ( 'foo');
var obj3 = new MyClass ({});
var obj4 = myclass ({});
위의 생성자는 return 문이있는 매우 특별하므로 OBJ1 ~ OBJ4는 어떤 개체가 지적합니까? 실제 결과는 다음과 같습니다.
코드 사본은 다음과 같습니다.
OBJ1 = MyClass 객체
obj2 = 'foo'
OBJ3 = {}
OBJ4 = {}
이 기사에서 구체적인 이유가 설명되어 있으며이 기사에서는 반복하지 않을 것입니다. 리턴 값이있는 생성자는 이상한 결과를 얻을 수 있으므로 생성자에 리턴 값이있는 리턴 명령문을 호출하지 마십시오 (빈 반환이 수행 될 수 있음).
3. JavaScript 기능 몬스터 레벨
몬스터 수준의 기능 교육 구역에 오신 것을 환영합니다. 여기서 오래된 괴물을 침착하고 자유롭게 마주 보는 방법이 주어집니다. . .
3.1 기능 클래스
JavaScript 런타임에는 기능이 내장 된 클래스가 있습니다. 함수 키워드로 함수를 선언하는 것은 실제로 기능 클래스 객체를 작성하기위한 약어입니다. 모든 함수에는 Call, Apply, Bind 등과 같은 기능 클래스의 모든 방법이 있습니다. 키워드 인스턴스를 통해이 문을 확인할 수 있습니다.
함수는 클래스이므로 생성자는 기능 (기능 클래스의 객체)이며 기능 객체는 새 키워드를 통해 생성되어야합니다. 첫 번째 몬스터가 여기 있습니다. 이것은 함수 클래스를 사용하여 함수를 구성하는 방법입니다. 함수의 구문은 다음과 같습니다.
코드 사본은 다음과 같습니다.
새 함수 ([arg1 [, arg2 [, ... argn]],] functionbody)
여기서 arg1, arg2, ... argn은 매개 변수 이름을 나타내는 문자열이며, 함수 바디는 또한 함수 본문을 나타내는 문자열이기도합니다. 이전 매개 변수 이름은 다소 낮습니다. 함수 생성자는 마지막 매개 변수를 기능 본문으로, 이전 매개 변수를 매개 변수로 취급합니다.
코드 사본은 다음과 같습니다.
var func1 = new 함수 ( 'name', 'return "hello," + name + "!";');
func1 ( 'Ghosttheaven'); // 안녕하세요, Ghosttheaven!
위의 방법은 함수를 통해 함수를 구성하며, 이는 기능 키워드로 선언 된 다른 함수와 정확히 동일합니다.
이것을보고, 많은 사람들이 왜 그런 괴물이 필요한지 물어볼 수 있습니까? "존재하는 것이 합리적입니다", 함수 클래스는 고유 한 목적을 가지고 있습니다. 이를 사용하여 다양한 기능 논리를 동적으로 생성하거나 평가 함수의 기능을 대체하고 현재 환경이 오염되지 않도록 할 수 있습니다.
3.2 자기 업데이트 기능
많은 언어에서 함수가 선언되면 동일한 이름의 기능을 다시 선언 할 수 없으며 구문 오류가 발생합니다. JavaScript의 기능은 반복적으로 선언 할뿐만 아니라 스스로 업데이트 할 수 있습니다. 내가 먹는 괴물이 여기 있습니다!
코드 사본은 다음과 같습니다.
함수 selfupdate () {
window.selfupdate = function () {
경고 ( '두 번째 실행!');
};
경고 ( '첫 번째 실행!');
}
selfupdate (); // 첫 번째 실행!
selfupdate (); // 두 번째 실행! 이 기능은 한 번만 실행되는 논리에 사용될 수 있으며 첫 번째 실행 후에는 새로운 논리로 대체됩니다.
요약
JavaScript의 기능은 매우 강력합니다. 많은 문제를 아름답게 해결하지만 많은 부정적인 문제도 가져옵니다. 몬스터 수준의 기능은 일반적으로 거의 알려지지 않은 사용으로 사용됩니다. 특히 필요하지 않은 한, 코드 판독에 어려움이 생기고 팀 개발 효율성에 영향을 미칩니다.
* 새로운 ECMAScript에서 엄격한 모드가 소개되었습니다. 엄격한 모드에서, 평가 함수는 크게 제한되며 환경이 오염되지 않도록 할 수 있습니다.
당신은 매우 실용적이라는 것을 이해하십니까? 누락 된 장소가 있으면 조언을하고 함께 진행하십시오.