자바스크립트 함수. 표현형 JavaScript: 함수에서 여러 값을 반환하는 Javascript 함수

사람들은 컴퓨터 과학이 천재들을 위한 예술이라고 생각합니다. 실제로는 그 반대입니다. 많은 사람들이 마치 작은 돌멩이로 벽을 쌓듯이 서로 겹겹이 쌓인 것들을 만들고 있습니다.

도널드 크누스

당신은 이미 Alert와 같은 함수에 대한 호출을 보았습니다. 함수는 JavaScript 프로그래밍의 빵과 버터입니다. 프로그램의 일부를 래핑하여 변수로 호출하는 아이디어는 매우 인기가 있습니다. 이는 대규모 프로그램을 구성하고, 반복을 줄이고, 서브루틴에 이름을 지정하고, 서브루틴을 서로 분리하는 도구입니다.

함수의 가장 확실한 용도는 새 사전을 만드는 것입니다. 평범한 인간 산문을 위해 단어를 만들어내는 것은 나쁜 형식입니다. 이는 프로그래밍 언어에서 필요합니다.

평균적인 성인 러시아어 사용자는 대략 10,000개의 단어를 알고 있습니다. 희귀한 프로그래밍 언어에는 10,000개의 내장 명령이 포함되어 있습니다. 그리고 프로그래밍 언어의 어휘는 더 명확하게 정의되어 있으므로 인간의 어휘보다 유연성이 떨어집니다. 그러므로 불필요한 반복을 피하기 위해 대개 우리 자신의 단어를 추가해야 합니다.

함수 정의 함수 정의는 변수가 받는 값이 함수인 일반적인 변수 정의입니다. 예를 들어, 다음 코드는 주어진 숫자의 제곱을 계산하는 함수를 참조하는 변수 square를 정의합니다.

Var square = function(x) ( return x * x; ); console.log(square(12)); // → 144

함수는 function 키워드로 시작하는 표현식으로 생성됩니다. 함수에는 일련의 매개변수(이 경우 x만)와 함수 호출 시 실행해야 하는 명령이 포함된 본문이 있습니다. 함수의 본문은 단일 명령문으로 구성되더라도 항상 중괄호로 묶입니다.

함수에는 여러 개의 매개변수가 있을 수도 있고 전혀 없을 수도 있습니다. 다음 예에서 makeNoise에는 매개변수 목록이 없지만 power에는 두 가지 매개변수 목록이 있습니다.

Var makeNoise = function() ( console.log("젠장!"); ); 소음을(); // → 크리야! var 거듭제곱 = 함수(밑, 지수) ( var 결과 = 1; for (var count = 0; 개수< exponent; count++) result *= base; return result; }; console.log(power(2, 10)); // → 1024

거듭제곱이나 제곱과 같은 일부 함수는 값을 반환하지만 makeNoise와 같은 다른 함수는 값을 반환하지 않아 부작용만 발생합니다. return 문은 함수가 반환하는 값을 지정합니다. 프로그램 처리가 이 명령에 도달하면 즉시 함수를 종료하고 함수가 호출된 코드의 위치에 이 값을 반환합니다. 표현식 없이 반환하면 정의되지 않은 값이 반환됩니다.

매개변수 및 범위 함수 매개변수는 동일한 변수이지만 초기값은 코드가 아닌 함수 호출 시 설정됩니다.

함수의 중요한 속성은 함수 내에서 생성된 변수(매개변수 포함)가 해당 함수에 대해 로컬이라는 것입니다. 이는 위의 예제에서 함수가 호출될 때마다 결과 변수가 생성되고 이러한 개별 구현은 서로 아무 관련이 없음을 의미합니다.

이 변수 지역성은 함수 내에서 생성된 매개변수와 변수에만 적용됩니다. 함수 외부에서 정의된 변수는 프로그램 전체에서 볼 수 있으므로 전역 변수라고 합니다. 동일한 이름의 지역 변수를 선언하지 않는 한 함수 내에서 이러한 변수에 액세스할 수도 있습니다.

다음 코드는 이를 보여줍니다. 변수 x에 값을 할당하는 두 개의 함수를 정의하고 호출합니다. 첫 번째는 이를 지역으로 선언하여 지역 변수만 변경합니다. 두 번째 것은 선언하지 않으므로 함수 내에서 x로 작업하는 것은 예제 시작 부분에 정의된 전역 변수 x를 참조합니다.

Var x = "외부"; var f1 = function() ( var x = "f1 내부"; ); f1(); console.log(x); // → 외부 var f2 = function() ( x = "inside f2"; ); f2(); console.log(x); // → f2 내부

이 동작은 기능 간의 우발적인 상호 작용을 방지하는 데 도움이 됩니다. 모든 변수가 프로그램의 어느 곳에서나 사용된다면 하나의 변수가 다른 목적으로 사용되지 않았는지 확인하기가 매우 어려울 것입니다. 그리고 변수를 재사용하는 경우 타사 코드가 변수 값을 손상시키면 이상한 효과가 발생하게 됩니다. 함수-로컬 변수를 함수 내에서만 존재하도록 처리함으로써 언어는 마치 별도의 작은 우주인 것처럼 함수 작업을 가능하게 하므로 전체 코드에 대해 걱정할 필요가 없습니다.

중첩된 범위 지정 JavaScript는 전역 변수와 지역 변수를 구분하는 것 이상을 구별합니다. 함수는 함수 내에서 정의될 수 있으므로 여러 수준의 지역성이 생성됩니다.

예를 들어, 다음과 같은 의미 없는 함수에는 내부에 두 개가 더 포함되어 있습니다.

Var Landscape = function() ( var result = ""; var flat = function(size) ( for (var count = 0; count< size; count++) result += "_"; }; var mountain = function(size) { result += "/"; for (var count = 0; count < size; count++) result += """; result += "\\"; }; flat(3); mountain(4); flat(6); mountain(1); flat(1); return result; }; console.log(landscape()); // → ___/""""\______/"\_

flat 및 Mountain 함수는 결과 변수를 정의하는 함수 내부에 있기 때문에 결과 변수를 봅니다. 하지만 한 함수의 변수가 다른 함수의 범위를 벗어나므로 서로의 카운트 변수를 볼 수 없습니다. 그리고 랜드스케이프 함수 외부의 환경에서는 이 함수 내부에 정의된 변수가 전혀 표시되지 않습니다.

즉, 각 로컬 범위 내에서 이를 포함하는 모든 범위를 볼 수 있습니다. 함수 내에서 사용할 수 있는 변수 세트는 프로그램에서 함수가 선언된 위치에 따라 결정됩니다. 메인 프로그램의 최상위 수준에서 정의된 변수를 포함하여 함수 정의 주변 블록의 모든 변수가 표시됩니다. 범위에 대한 이러한 접근 방식을 어휘라고 합니다.

다른 프로그래밍 언어를 공부한 사람들은 중괄호로 묶인 모든 블록이 자체 로컬 환경을 생성한다고 생각할 수 있습니다. 하지만 JavaScript에서는 함수만 범위를 만듭니다. 독립형 블록을 사용할 수 있습니다.

Var 뭔가 = 1; ( var Something = 2; // Something 변수로 무언가를 수행합니다... ) // 블록을 종료했습니다...

그러나 블록 내부의 무언가는 외부와 동일한 변수입니다. 이러한 블록은 허용되지만 if 문과 루프에만 사용하는 것이 좋습니다.

이것이 이상하게 보인다면 그렇게 생각하는 사람은 당신뿐만이 아닙니다. 버전 JavaScript 1.7에서 등장 예어 let은 var처럼 작동하지만 함수뿐만 아니라 특정 블록에 로컬인 변수를 생성합니다.

값으로서의 함수 함수 이름은 일반적으로 프로그램의 이름으로 사용됩니다. 이러한 변수는 한 번 설정되면 변경되지 않습니다. 그래서 함수와 이름을 혼동하기 쉽습니다.

그러나 이것은 두 가지 다른 것입니다. 함수 호출은 간단한 변수처럼 사용될 수 있습니다(예: 모든 표현식에 사용됨). 함수 호출을 새 변수에 저장하고 이를 다른 함수에 매개변수로 전달하는 등의 작업이 가능합니다. 또한 함수 호출을 저장하는 변수는 일반 변수로 유지되며 해당 값은 변경될 수 있습니다.

Var launchMissiles = function(value) ( ​​​​missileSystem.launch("or!"); ); if (safeMode) launchMissiles = function(value) (/* 취소 */);

5장에서는 함수 호출을 다른 함수에 전달하여 수행할 수 있는 놀라운 작업에 대해 논의합니다.

함수 선언 "var square = function..."이라는 표현의 더 짧은 버전이 있습니다. function 키워드는 명령문 시작 부분에 사용할 수 있습니다.

함수 square(x) ( return x * x; )

이것은 함수 선언입니다. 명령문은 square 변수를 정의하고 해당 변수에 지정된 함수를 할당합니다. 여태까지는 그런대로 잘됐다. 그러한 정의에는 단 하나의 함정이 있습니다.

Console.log("미래는 다음과 같습니다:", future()); function future() ( "우리는 아직 하늘을 나는 자동차가 없습니다."를 반환합니다.; )

이 코드는 이를 사용하는 코드 아래에 함수가 선언되어 있어도 작동합니다. 이는 함수 선언이 일반적인 하향식 프로그램 실행의 일부가 아니기 때문입니다. 해당 범위의 맨 위로 "이동"되며 해당 범위의 모든 코드에서 호출할 수 있습니다. 때로는 위의 모든 함수가 사용되는 위치를 정의해야 하는 것에 대해 걱정할 필요 없이 가장 적합한 순서로 코드를 작성할 수 있기 때문에 편리합니다.

조건부 블록이나 루프 안에 함수 선언을 배치하면 어떻게 되나요? 그렇게 할 필요는 없습니다. 역사적으로 다양한 JavaScript 실행 플랫폼은 이러한 경우를 다르게 처리해 왔으며 현재 언어 표준에서는 이를 금지합니다. 프로그램을 순차적으로 실행하려면 다른 함수나 기본 프로그램 내에서만 함수 선언을 사용하세요.

Function example() ( function a() () // Normal if (something) ( function b() () // 으아아아아아아아! ) )

호출 스택 실행 순서가 함수와 어떻게 작동하는지 자세히 살펴보는 것이 도움이 됩니다. 여기 간단한 프로그램여러 함수 호출을 사용하는 경우:

함수 Greeting(who) ( console.log("안녕하세요, " + who); ) Greeting("세면"); console.log("포케다");

다음과 같이 처리됩니다. Greeting을 호출하면 패스가 함수의 시작 부분으로 이동합니다. 제어를 가로채서 해당 작업을 수행하고 제어를 반환하는 내장 console.log 함수를 호출합니다. 그리고 인사를 마치고 부르심을 받은 곳으로 돌아갑니다. 다음 줄에서는 console.log를 다시 호출합니다.

이는 다음과 같이 개략적으로 표시될 수 있습니다.

상단 인사말 console.log 상단 인사말 console.log 상단

함수는 호출된 위치로 돌아가야 하기 때문에 컴퓨터는 함수가 호출된 컨텍스트를 기억해야 합니다. 어떤 경우에는 console.log가 인사를 위해 다시 반환되어야 합니다. 또 다른 경우에는 프로그램의 마지막 부분으로 돌아갑니다.

컴퓨터가 컨텍스트를 기억하는 곳을 스택이라고 합니다. 함수가 호출될 때마다 현재 컨텍스트가 스택의 맨 위로 푸시됩니다. 함수가 반환되면 스택에서 최상위 컨텍스트를 팝하고 이를 사용하여 계속 실행합니다.

스택 저장에는 메모리 공간이 필요합니다. 스택이 너무 커지면 컴퓨터는 실행을 멈추고 "스택 오버플로" 또는 "재귀가 너무 많습니다."와 같은 메시지를 표시합니다. 다음 코드는 이를 보여줍니다. 이 코드는 컴퓨터에 매우 복잡한 질문을 하여 두 기능 사이를 끊임없이 이동하게 만듭니다. 더 정확하게 말하면 컴퓨터에 무한 스택이 있으면 무한 점프가 됩니다. 실제로는 스택이 오버플로됩니다.

Function Chicken() ( return egg(); ) function egg() ( return Chicken(); ) console.log(chicken() + " came first."); // → ??

선택적 인수 다음 코드는 완전히 적법하며 문제 없이 실행됩니다.

Alert("안녕하세요", "안녕하세요", "안녕하세요 여러분!");

공식적으로 이 함수는 하나의 인수를 사용합니다. 하지만 이렇게 도전해도 그녀는 불평하지 않습니다. 그녀는 나머지 인수를 무시하고 "Hello"를 표시합니다.

JavaScript는 함수에 전달되는 인수 수에 대해 매우 까다롭습니다. 너무 많이 전송하면 추가 전송은 무시됩니다. 너무 적으면 누락된 항목에 정의되지 않은 값이 할당됩니다.

이 접근 방식의 단점은 누구도 불평하지 않고 잘못된 수의 인수를 함수에 전달할 수 있다는 것입니다.

장점은 선택적 인수를 사용하는 함수를 만들 수 있다는 것입니다. 예를 들어, 다음 버전의 power 함수에서는 두 개 또는 하나의 인수를 사용하여 호출할 수 있습니다. 후자의 경우 지수는 2와 같고 함수는 사각형처럼 작동합니다.

함수 거듭제곱(기본, 지수) ( if (지수 == 정의되지 않음) 지수 = 2; var 결과 = 1; for (var count = 0; count< exponent; count++) result *= base; return result; } console.log(power(4)); // → 16 console.log(power(4, 3)); // → 64

다음 장에서는 함수 본문에서 전달된 인수의 정확한 수를 알아내는 방법을 살펴보겠습니다. 이것은 유용하기 때문에... 원하는 개수의 인수를 취하는 함수를 생성할 수 있습니다. 예를 들어 console.log는 이 속성을 사용하고 여기에 전달된 모든 인수를 인쇄합니다.

Console.log("R", 2, "D", 2); // → R2D2

클로저 함수 호출을 변수로 사용하는 기능과 함수가 호출될 때마다 지역 변수가 새로 생성된다는 사실은 우리에게 흥미로운 질문을 던집니다. 함수가 작동을 멈추면 지역 변수는 어떻게 되나요?

다음 예에서는 이 문제를 보여줍니다. 지역 변수를 생성하는 WrapValue 함수를 선언합니다. 그런 다음 이 지역 변수를 읽고 해당 값을 반환하는 함수를 반환합니다.

함수 WrapValue(n) ( var localVariable = n; return function() ( return localVariable; ); ) var Wrap1 = WrapValue(1); var Wrap2 = WrapValue(2); console.log(wrap1()); // → 1 console.log(wrap2()); // → 2

이는 유효하며 정상적으로 작동합니다. 변수에 대한 액세스는 그대로 유지됩니다. 또한 동일한 변수의 여러 인스턴스가 동시에 존재할 수 있으므로 각 함수 호출마다 지역 변수가 다시 생성된다는 사실이 더욱 확인됩니다.

지역 변수의 인스턴스에 대한 참조로 작업하는 이러한 기능을 클로저라고 합니다. 지역 변수를 닫는 함수를 클로저라고 합니다. 다양한 수명에 대한 걱정을 덜어줄 뿐만 아니라 기능을 창의적으로 사용할 수 있게 해줍니다.

약간의 수정을 통해 예제를 숫자에 주어진 숫자를 곱하는 함수로 바꿉니다.

함수 승수(인수) ( 반환 함수(숫자) ( 반환 번호 * 인수; ); ) var 두 번 = 승수(2); console.log(twice(5)); // → 10

WrapValue 예제의 localVariable과 같은 별도의 변수는 더 이상 필요하지 않습니다. 매개 변수 자체가 지역 변수이기 때문입니다.

이런 식으로 생각하기 시작하려면 연습이 필요합니다. 좋은 옵션정신 모델은 함수가 코드를 본체에 고정하고 패키징으로 포장한다고 상상하는 것입니다. return function(...) (...)을 보면 나중에 사용하기 위해 동결된 코드 조각에 대한 제어판으로 생각하십시오.

예제에서 multiplier는 고정된 코드 조각을 반환하며 이를 두 번 변수에 저장합니다. 마지막 줄은 저장된 코드가 활성화되도록 하는 변수에 포함된 함수를 호출합니다(반환 번호 * 인자;). 승수를 호출할 때 정의된 요인 변수에 여전히 액세스할 수 있으며, 제상(5) 중에 숫자 매개변수로 전달된 인수에도 액세스할 수 있습니다.

재귀 함수는 스택이 오버플로되지 않도록 주의하는 한 자신을 호출할 수 있습니다. 이 함수를 재귀라고 합니다. 다음은 지수화의 대체 구현 예입니다.

함수 power(base, expont) ( if (exComponent == 0) return 1; else return base * power(base, expont - 1); ) console.log(power(2, 3)); // → 8

이것이 수학자들이 지수를 정의하는 대략적인 방법이며, 아마도 이것이 순환보다 개념을 더 우아하게 설명할 것입니다. 함수는 다중 곱셈을 달성하기 위해 다양한 인수를 사용하여 자신을 여러 번 호출합니다.

그러나 이 구현에는 문제가 있습니다. 정상적인 환경 JavaScript는 루프가 있는 버전보다 10배 느립니다. 루프를 통과하는 것이 함수를 호출하는 것보다 저렴합니다.

속도 대 우아함의 딜레마는 매우 흥미롭습니다. 인간의 편리함과 기계의 편리함 사이에는 일정한 차이가 있습니다. 어떤 프로그램이라도 더 크고 복잡하게 만들면 속도가 빨라질 수 있습니다. 프로그래머는 적절한 균형을 찾아야 합니다.

첫 번째 지수의 경우, 우아하지 않은 루프는 매우 간단하고 간단합니다. 재귀로 대체하는 것은 의미가 없습니다. 그러나 종종 프로그램은 가독성을 높여 효율성을 줄이고자 하는 복잡한 개념을 다루고 있습니다.

두 번 이상 반복되었으며 제가 전적으로 동의하는 기본 규칙은 프로그램 속도가 느려지고 있다는 것을 절대적으로 확신할 때까지 성능에 대해 걱정하지 않는 것입니다. 그렇다면 가장 오래 지속되는 부품을 찾아 그곳에서 효율성을 위해 우아함을 바꾸십시오.

물론 성능을 당장 완전히 무시해서는 안 됩니다. 많은 경우 지수 계산과 마찬가지로 우아한 솔루션에서는 그다지 단순함을 얻지 못합니다. 때때로 숙련된 프로그래머간단한 접근 방식으로는 결코 충분히 빠르지 않다는 것을 즉시 알 수 있습니다.

제가 이 점을 지적하는 이유는 너무 많은 초보 프로그래머들이 작은 일에도 효율성에 집착하기 때문입니다. 결과는 더 크고 복잡하며 오류가 없는 경우가 많습니다. 이러한 프로그램은 작성하는 데 시간이 더 오래 걸리지만 훨씬 빠르게 작동하지 않는 경우가 많습니다.

그러나 재귀가 항상 루프에 대한 덜 효율적인 대안은 아닙니다. 일부 문제는 재귀를 사용하여 해결하기가 더 쉽습니다. 대부분의 경우 이는 분기할 수 있는 트리의 여러 가지를 순회하는 것입니다.

여기에 수수께끼가 있습니다. 숫자 1부터 시작하여 5를 더하거나 3을 곱하면 무한한 수의 숫자를 얻을 수 있습니다. 숫자가 주어졌을 때 덧셈과 곱셈의 순서를 찾는 함수를 어떻게 작성합니까? 그게 특정 숫자로 이어지나요? 예를 들어 숫자 13은 1에 3을 곱한 다음 5를 두 번 더하면 얻을 수 있습니다. 그리고 이 방법으로는 숫자 15를 전혀 얻을 수 없습니다.

재귀적 솔루션:

Function findSolution(target) ( function find(start, History) ( if (start == target) 기록을 반환하고, else if (start > target)는 null을 반환하고, else return find(start + 5, "(" + History + " + 5)") || find(start * 3, "(" + History + " * 3)"); ) return find(1, "1"); ) console.log(findSolution(24)); // → (((1 * 3) + 5) * 3)

이 예는 반드시 가장 짧은 솔루션을 찾는 것은 아닙니다. 어떤 경우에도 만족됩니다. 나는 당신이 프로그램이 어떻게 작동하는지 즉시 이해할 것이라고 기대하지 않습니다. 하지만 재귀적 사고에 대한 이 훌륭한 연습을 이해해 봅시다.

내부 함수 find는 재귀를 수행합니다. 두 개의 인수, 즉 현재 숫자와 이 숫자에 어떻게 도달했는지에 대한 기록이 포함된 문자열을 사용합니다. 그리고 일련의 단계를 보여주는 문자열이나 null을 반환합니다.

이를 위해 함수는 세 가지 작업 중 하나를 수행합니다. 주어진 숫자가 목표와 같으면 현재 스토리가 정확히 목표를 달성하는 방법이므로 반환됩니다. 주어진 숫자가 목표보다 크면 계속해서 곱하고 더해도 의미가 없습니다. 왜냐하면 증가만 할 것이기 때문입니다. 아직 목표에 도달하지 못한 경우 함수는 두 가지를 모두 시도합니다. 가능한 방법, 주어진 숫자로 시작합니다. 그녀는 각 방법마다 한 번씩 자신을 두 번 소환합니다. 첫 번째 호출이 null을 반환하지 않으면 null이 반환됩니다. 다른 경우에는 두 번째 항목이 반환됩니다.

함수가 원하는 효과를 어떻게 달성하는지 더 잘 이해하기 위해 숫자 13에 대한 해를 찾기 위해 수행하는 호출을 살펴보겠습니다.

Find(1, "1") find(6, "(1 + 5)") find(11, "((1 + 5) + 5)") find(16, "(((1 + 5) + 5 ) + 5)") 너무 큰 find(33, "(((1 + 5) + 5) * 3)") 너무 큰 find(18, "((1 + 5) * 3)") 너무 큰 find( 3, "(1 * 3)") find(8, "((1 * 3) + 5)") find(13, "(((1 * 3) + 5) + 5)") 찾았습니다!

들여쓰기는 호출 스택의 깊이를 나타냅니다. 처음으로 find 함수는 (1 + 5) 및 (1 * 3)으로 시작하는 해를 확인하기 위해 자신을 두 번 호출합니다. 첫 번째 호출은 (1 + 5)로 시작하는 해를 찾고 재귀를 사용하여 필요한 숫자보다 작거나 같은 숫자를 생성하는 모든 해를 확인합니다. 찾지 못하고 null을 반환합니다. 그런 다음 연산자 || (1 * 3) 옵션을 검사하는 함수 호출로 이동합니다. 세 번째 재귀 호출에서 13을 얻었기 때문에 운이 좋았습니다. 이 호출은 문자열을 반환하고 각 || 도중에 이 선을 더 높게 통과하여 솔루션이 반환됩니다.

함수 늘리기 프로그램에 함수를 도입하는 다소 자연스러운 방법이 두 가지 있습니다.

첫 번째는 비슷한 코드를 여러 번 작성한다는 것입니다. 이는 피해야 합니다. 코드가 많을수록 오류가 발생할 여지가 더 많아지고 프로그램을 이해하려는 사람들이 읽을 수 있는 자료가 더 많아집니다. 그래서 우리는 반복되는 기능을 가져와서 일치시킵니다. 좋은 이름그리고 그것을 함수에 넣습니다.

두 번째 방법은 별도의 기능에 배치할 가치가 있는 몇 가지 새로운 기능에 대한 필요성을 발견하는 것입니다. 함수 이름으로 시작한 다음 본문을 작성합니다. 함수 자체가 정의되기 전에 함수를 사용하는 코드를 작성하여 시작할 수도 있습니다.

함수 이름을 지정하는 것이 얼마나 어려운지는 해당 기능을 얼마나 잘 이해하고 있는지를 보여줍니다. 예를 들어 보겠습니다. 우리는 농장에 있는 소와 닭의 수라는 두 개의 숫자를 인쇄하고 그 뒤에 "소"와 "닭"이라는 단어를 인쇄하는 프로그램을 작성해야 합니다. 각 숫자가 정확히 세 자리를 차지하도록 앞에 있는 숫자에 0을 추가해야 합니다.

007 소 011 닭

분명히 두 개의 인수를 가진 함수가 필요합니다. 코딩을 시작해 보겠습니다.
// FarmInventory 함수 인쇄 printFarmInventory(cows, Chickens) ( var cowString = String(cows); while (cowString.length< 3) cowString = "0" + cowString; console.log(cowString + " Коров"); var chickenString = String(chickens); while (chickenString.length < 3) chickenString = "0" + chickenString; console.log(chickenString + " Куриц"); } printFarmInventory(7, 11);

문자열에 .length를 추가하면 해당 길이를 얻습니다. 그것은 밝혀졌다 while 루프 3자리 문자열을 얻을 때까지 숫자 앞에 0을 추가합니다.

준비가 된! 하지만 우리가 농부에게 코드를 보내려고 할 때(물론 상당한 금액의 수표와 함께) 농부는 전화를 걸어 자신의 농장에 돼지가 있다고 말했습니다. 프로그램?

물론 가능합니다. 하지만 이 네 줄의 코드를 복사하여 붙여넣기 시작하면 멈추고 생각해야 한다는 것을 깨닫게 됩니다. 더 좋은 방법이 있어야 합니다. 우리는 프로그램을 개선하기 위해 노력하고 있습니다:

// 0과 레이블을 추가하여 출력 function printZeroPendedWithLabel(number, label) ( var numberString = String(number); while (numberString.length< 3) numberString = "0" + numberString; console.log(numberString + " " + label); } // вывестиИнвентаризациюФермы function printFarmInventory(cows, chickens, pigs) { printZeroPaddedWithLabel(cows, "Коров"); printZeroPaddedWithLabel(chickens, "Куриц"); printZeroPaddedWithLabel(pigs, "Свиней"); } printFarmInventory(7, 11, 3);

공장! 그런데 printZeroPendedWithLabel이라는 이름이 좀 이상하네요. 출력, 0 추가, 레이블 세 가지를 하나의 함수로 결합합니다. 전체 반복 조각을 함수에 삽입하는 대신 한 가지 개념을 강조해 보겠습니다.

// Zero 함수 추가 zeroPad(number, width) ( var string = String(number); while (string.length< width) string = "0" + string; return string; } // вывестиИнвентаризациюФермы function printFarmInventory(cows, chickens, pigs) { console.log(zeroPad(cows, 3) + " Коров"); console.log(zeroPad(chickens, 3) + " Куриц"); console.log(zeroPad(pigs, 3) + " Свиней"); } printFarmInventory(7, 16, 3);

멋지고 명확한 이름의 zeroPad를 사용하면 코드를 더 쉽게 이해할 수 있습니다. 그리고 그것은 우리의 경우뿐만 아니라 다양한 상황에서 사용될 수 있습니다. 예를 들어 숫자가 포함된 서식이 지정된 테이블을 표시합니다.

기능은 얼마나 스마트하고 다재다능해야 합니까? 최대 3자리까지 숫자에 0을 채우는 간단한 함수나 정교한 함수를 작성할 수 있습니다. 범용숫자 서식 지정, 분수 지원, 음수 지원, 점 정렬, 다른 문자 채우기 등을 위한 것입니다.

경험상 유용하다고 생각되는 기능만 추가하는 것이 좋습니다. 때로는 모든 작은 요구 사항에 맞는 범용 프레임워크를 만들고 싶은 유혹이 있을 수 있습니다. 그를 저항하십시오. 당신은 결코 작업을 끝내지 못할 것이고, 결국 아무도 사용하지 않을 코드 묶음을 작성하게 될 것입니다.

함수와 부작용 함수는 크게 부작용 때문에 호출되는 함수와 값을 얻기 위해 호출되는 함수로 나눌 수 있습니다. 물론 이러한 속성을 하나의 기능으로 결합하는 것도 가능합니다.

팜 예제의 첫 번째 도우미 함수인 printZeroPaggedWithLabel은 부작용이 있기 때문에 호출됩니다. 즉, 문자열을 인쇄합니다. 두 번째는 반환 값 때문에 zeroPad입니다. 그리고 두 번째 기능이 첫 번째 기능보다 더 자주 유용하다는 것은 우연이 아닙니다. 값을 반환하는 함수는 부작용을 일으키는 함수보다 서로 결합하기가 더 쉽습니다.

순수 함수는 부작용이 없을 뿐만 아니라 나머지 코드의 부작용에 의존하지 않는 특수한 종류의 값 반환 함수입니다. 예를 들어 실수로 발생할 수 있는 전역 변수에서는 작동하지 않습니다. 다른 곳으로 바뀌었어요. 순수 함수는 동일한 인수로 호출되면 동일한 결과를 반환합니다(다른 작업은 수행하지 않음). 이는 매우 훌륭합니다. 그녀는 함께 일하기 쉽습니다. 이러한 함수에 대한 호출은 코드의 의미를 변경하지 않고 해당 작업의 결과로 정신적으로 대체될 수 있습니다. 그러한 함수를 테스트하고 싶을 때 간단히 호출하면 되며, 해당 함수가 주어진 컨텍스트에서 작동한다면 어떤 컨텍스트에서도 작동하는지 확인하면 됩니다. 덜 순수한 함수는 여러 요인에 따라 다른 결과를 반환할 수 있으며 테스트하고 설명하기 어려운 부작용이 있을 수 있습니다.

그러나 완전히 순수하지 않은 함수를 작성하거나 그러한 함수에 대한 신성한 코드 정리를 시작하는 것을 당황스러워해서는 안 됩니다. 부작용이 유익한 경우가 많습니다. console.log 함수의 클린 버전을 작성할 수 있는 방법은 없으며 이 함수는 매우 유용합니다. 일부 작업은 부작용을 사용하여 표현하기가 더 쉽습니다.

요약 이 장에서는 자신만의 함수를 작성하는 방법을 보여주었습니다. function 키워드가 표현식으로 사용되면 함수 호출에 대한 포인터를 반환합니다. 명령어로 사용되는 경우 변수에 함수 호출을 할당하여 변수를 선언할 수 있습니다.

함수를 이해하는 핵심은 로컬 범위입니다. 함수 내부에 선언된 매개변수와 변수는 해당 함수에 대해 로컬이며 호출될 때마다 다시 생성되며 외부에서는 표시되지 않습니다. 다른 함수 내부에 선언된 함수는 해당 범위에 액세스할 수 있습니다.

프로그램이 수행하는 다양한 작업을 기능으로 분리하는 것은 매우 유용합니다. 반복할 필요가 없습니다. 책의 장과 섹션이 일반 텍스트를 구성하는 데 도움이 되는 것처럼 함수를 사용하면 코드를 의미 있는 부분으로 나누어 코드를 더 쉽게 읽을 수 있습니다.

PracticesMinimum 이전 장에서 우리는 가장 작은 인수를 반환하는 Math.min 함수에 대해 언급했습니다. 이제 우리는 그러한 함수를 직접 작성할 수 있습니다. 두 개의 인수를 받아 그 중 최소값을 반환하는 min 함수를 작성하세요.

Console.log(최소(0, 10)); // → 0 console.log(min(0, -10)); // → -10

재귀 우리는 숫자(%2)가 짝수인지 확인하기 위해 %(모듈로) 연산자를 사용할 수 있다는 것을 살펴보았습니다. 이를 정의하는 또 다른 방법은 다음과 같습니다.

0은 짝수입니다.
단위가 이상해요.
모든 숫자 N은 N-2와 동일한 패리티를 갖습니다.

이 규칙에 따라 재귀 함수 isEven을 작성하세요. 숫자를 허용하고 부울 값을 반환해야 합니다.

50과 75에서 테스트해 보세요. -1을 주어 보세요. 그녀는 왜 이런 식으로 행동하는 걸까요? 어떻게 든 고칠 수 있습니까?

50과 75에서 테스트해 보세요. -1에서 어떻게 작동하는지 확인하세요. 왜? 이 문제를 해결할 방법을 생각해 볼 수 있나요?

Console.log(isEven(50)); // → 참 console.log(isEven(75)); // → 거짓 console.log(isEven(-1)); // → ??

콩을 세어보세요.

문자열의 문자 번호 N은 .charAt(N) (“string”.charAt(5))을 추가하여 얻을 수 있습니다. 이는 .length를 사용하여 문자열 길이를 얻는 것과 비슷한 방법입니다. 반환 값은 한 문자로 구성된 문자열(예: "k")입니다. 문자열의 첫 번째 문자의 위치는 0입니다. 이는 마지막 문자의 위치 string.length - 1을 의미합니다. 즉, 두 문자로 구성된 문자열의 길이는 2이고 해당 문자 위치는 0과 1이 됩니다.

문자열을 인수로 취하고 문자열에 포함된 "B" 문자의 수를 반환하는 함수 countBs를 작성하세요.

그런 다음 countBs와 유사하게 작동하지만 두 번째 매개변수, 즉 (단순히 "B" 문자 수를 세는 대신) 문자열에서 찾을 문자인 countChar라는 함수를 작성합니다. 이렇게 하려면 countBs 함수를 재작업하세요.

함수는 JavaScript에서 가장 중요한 코드 구성 요소 중 하나입니다.

기능은 일련의 명령으로 구성되며 일반적으로 하나의 명령을 수행합니다. 특정 작업(예: 숫자 합산, 근 계산 등)

함수에 배치된 코드는 이 함수를 명시적으로 호출한 후에만 실행됩니다.

함수 선언

1. 구문:

//함수 선언 functionFunctionname(ln1, ln2)( Function code) //함수 호출Functionname(ln1,lr2);

2. 구문:

//함수 선언 var function name=function(ln1, ln2)(함수 코드) //함수 호출 function name(ln1,lr2);

functionname은 함수의 이름을 지정합니다. 페이지의 각 함수에는 고유한 이름이 있어야 합니다. 함수 이름은 라틴 문자로 지정해야 하며 숫자로 시작할 수 없습니다.

ln1과 ln2는 함수에 전달할 수 있는 변수 또는 값입니다. 각 함수에는 무제한의 변수를 전달할 수 있습니다.

참고: 함수에 변수가 전달되지 않더라도 함수 이름 뒤에 괄호 "()"를 삽입하는 것을 잊지 마십시오.

JavaScript의 함수 이름은 대소문자를 구분합니다.

예제 JavaScript 함수

아래 예제의 messageWrite() 함수는 버튼을 클릭한 후에만 실행됩니다.

이 예제에서는 onclick 이벤트를 사용합니다. 자바스크립트 이벤트이 교과서의 뒷부분에서 자세히 논의할 것입니다.

// 이 함수는 페이지 함수 messageWrite()에 텍스트를 씁니다. ( document.write("이 텍스트는 JavaScript를 사용하여 페이지에 작성되었습니다!"); )

변수를 함수에 전달하기

함수에 변수를 무제한으로 전달할 수 있습니다.

참고: 함수 내부의 변수를 사용한 모든 조작은 실제로 변수 자체가 아닌 해당 복사본에서 수행되므로 함수 실행 결과로 변수 자체의 내용이 변경되지 않습니다.

/* 전달된 변수에 10을 더하고 그 결과를 페이지에 표시하는 함수를 정의해 보겠습니다. */ function plus(a)( a=a+10; document.write("함수 출력: " + a+"
"); ) var a=25; document.write("함수 호출 전 변수 값: "+a+"
"); // 변수 a를 전달하여 함수를 호출합니다. plus(a); document.write("함수 호출 후 변수의 값: "+a+"
");

퀵뷰

복사본이 아닌 함수에서 전역 변수에 액세스하려면 window.variable_name을 사용하세요.

함수 plus(a)( window.a=a+10; ) var a=25; document.write("함수 호출 전 변수 값: "+a+"
"); plus(a); document.write("함수 호출 후 변수 값: "+a+"
");

퀵뷰

반환 명령

return 명령을 사용하면 함수에서 값을 반환할 수 있습니다.

//sum 함수는 전달된 변수의 합계를 반환합니다. function sum(v1,v2)( return v1+v2; ) document.write("5+6=" + sum(5,6) + "
"); document.write("10+4=" + 합계(10,4) + "
");

퀵뷰

내장된 기능

사용자 정의 함수 외에도 JavaScript에는 내장 함수도 있습니다.

예를 들어, 내장된 isFinite 함수를 사용하면 전달된 값이 유효한 숫자인지 확인할 수 있습니다.

Document.write(isFinite(40)+"
"); document.write(isFinite(-590)+"
"); document.write(isFinite(90.33)+"
"); document.write(isFinite(NaN)+"
"); document.write(isFinite("이것은 문자열입니다.")+"
");

퀵뷰

메모: 전체 목록내장 자바스크립트 함수우리에서 찾을 수 있습니다.

지역 및 전역 변수

함수 내부에서 생성된 변수를 지역변수(Local Variable)라고 합니다. 이러한 변수는 해당 변수가 정의된 함수 내에서만 액세스할 수 있습니다.

함수 코드 실행이 완료된 후 해당 변수는 삭제됩니다. 이는 동일한 이름을 가진 변수가 다른 함수에서 정의될 수 있음을 의미합니다.

함수 코드 외부에서 생성된 변수를 전역 변수라고 하며, 이러한 변수는 코드 내 어디에서나 액세스할 수 있습니다.

함수 내에서 var 없이 변수를 선언하면 전역 변수가 됩니다.

전역 변수는 페이지가 닫힌 후에만 소멸됩니다.

//전역 변수 var1 및 var2 선언 var var1="var1 존재"; var var2; function func1() ( //var2에 함수 func1 내부의 값 할당 var var2="var2 presents"; ) //다른 함수에서 변수 var1 및 var2의 내용을 페이지에 출력 function func2() ( //출력 변수 var1 document.write( var1 + "의 내용
"); //변수 var2의 내용을 출력 document.write(var2); )

퀵뷰

func1은 var2의 로컬 "버전"에서 작동하므로 화면에 인쇄될 때 var2는 빈 값을 갖게 됩니다.

익명 함수 사용

선언 시 이름이 포함되지 않은 함수를 익명이라고 합니다.

익명 함수는 기본적으로 일반 함수처럼 코드에서 후속적으로 호출되지 않고 다른 함수에 매개변수로 전달되도록 선언되어 있습니다.

함수 arrMap(arr,func)( var res=new Array; for (var i=0;i