수색…
소개
JavaScript의 함수는 일련의 작업을 수행하기 위해 체계적이고 재사용 가능한 코드를 제공합니다. 함수는 코딩 프로세스를 단순화하고 중복 논리를 방지하며 코드를 쉽게 따르도록합니다. 이 주제에서는 JavaScript의 함수, 인수, 매개 변수, return 문 및 범위의 선언 및 사용에 대해 설명합니다.
통사론
함수 예제 (x) {return x}
var example = function (x) {return x}
(function () {...}) (); // 즉시 호출 된 함수 식 (IIFE)
var instance = new 예제 (x);
행동 양식
fn.apply (valueForThis [, arrayOfArgs])
fn.bind (valueForThis [, arg1 [, arg2, ...]])
fn.call (valueForThis [, arg1 [, arg2, ...]])
ES2015 + (ES6 +) :
const example = x => {return x}; // 화살표 함수 explicit return
const example = x => x; // 화살표 함수 암시 적 리턴
const example = (x, y, z) => {...} // Arrow는 여러 인자로 작용합니다
(() => {...}) (); // 화살표 함수를 사용하는 IIFE
비고
화살표 기능에 대한 자세한 내용은 Arrow 기능 설명서를 참조하십시오.
변수로서의 기능
일반적인 함수 선언은 다음과 같습니다.
function foo(){
}
이와 같이 정의 된 함수는 컨텍스트 내에서 그 이름으로 액세스 할 수 있습니다. 그러나 때로는 객체 참조와 같은 함수 참조를 처리하는 것이 유용 할 수 있습니다. 예를 들어, 조건 집합을 기반으로 변수에 객체를 할당 한 다음 나중에 하나 또는 다른 객체에서 객체를 검색 할 수 있습니다.
var name = 'Cameron';
var spouse;
if ( name === 'Taylor' ) spouse = { name: 'Jordan' };
else if ( name === 'Cameron' ) spouse = { name: 'Casey' };
var spouseName = spouse.name;
JavaScript에서는 함수를 사용하여 동일한 작업을 수행 할 수 있습니다.
// Example 1
var hashAlgorithm = 'sha1';
var hash;
if ( hashAlgorithm === 'sha1' ) hash = function(value){ /*...*/ };
else if ( hashAlgorithm === 'md5' ) hash = function(value){ /*...*/ };
hash('Fred');
위의 예제에서 hash
는 일반적인 변수입니다. 함수에 대한 참조가 할당 된 후 함수가 참조하는 함수는 일반적인 함수 선언과 마찬가지로 괄호를 사용하여 호출 할 수 있습니다.
위의 예제는 익명 함수 ... 자신의 이름이없는 함수를 참조합니다. 변수를 사용하여 명명 된 함수를 참조 할 수도 있습니다. 위의 예는 다음과 같이 재 작성 될 수 있습니다.
// Example 2
var hashAlgorithm = 'sha1';
var hash;
if ( hashAlgorithm === 'sha1' ) hash = sha1Hash;
else if ( hashAlgorithm === 'md5' ) hash = md5Hash;
hash('Fred');
function md5Hash(value){
// ...
}
function sha1Hash(value){
// ...
}
또는 객체 속성에서 함수 참조를 할당 할 수 있습니다.
// Example 3
var hashAlgorithms = {
sha1: function(value) { /**/ },
md5: function(value) { /**/ }
};
var hashAlgorithm = 'sha1';
var hash;
if ( hashAlgorithm === 'sha1' ) hash = hashAlgorithms.sha1;
else if ( hashAlgorithm === 'md5' ) hash = hashAlgorithms.md5;
hash('Fred');
한 변수가 가지고있는 함수에 대한 참조를 괄호를 생략함으로써 다른 변수에 할당 할 수 있습니다. 이로 인해 함수의 반환 값을 다른 변수에 할당하려고 시도했지만 실수로 함수에 대한 참조를 할당하려고하면 실수를 쉽게 범할 수 있습니다.
// Example 4
var a = getValue;
var b = a; // b is now a reference to getValue.
var c = b(); // b is invoked, so c now holds the value returned by getValue (41)
function getValue(){
return 41;
}
함수에 대한 참조는 다른 값과 같습니다. 앞서 보았 듯이 변수에 참조를 할당 할 수 있으며 그 변수의 참조 값을 다른 변수에 할당 할 수 있습니다. 함수에 대한 참조를 다른 함수의 반환 값으로 전달하는 것을 포함하여 다른 값과 같은 함수에 대한 참조를 전달할 수 있습니다. 예 :
// Example 5
// getHashingFunction returns a function, which is assigned
// to hash for later use:
var hash = getHashingFunction( 'sha1' );
// ...
hash('Fred');
// return the function corresponding to the given algorithmName
function getHashingFunction( algorithmName ){
// return a reference to an anonymous function
if (algorithmName === 'sha1') return function(value){ /**/ };
// return a reference to a declared function
else if (algorithmName === 'md5') return md5;
}
function md5Hash(value){
// ...
}
변수를 호출하기 위해 함수 참조를 변수에 지정할 필요가 없습니다. 예제 5를 구현하는이 예제는 getHashingFunction을 호출 한 다음 반환 된 함수를 즉시 호출하고 반환 값을 hashedValue로 전달합니다.
// Example 6
var hashedValue = getHashingFunction( 'sha1' )( 'Fred' );
권상에 관한주의 사항
일반 함수 선언과는 달리 함수를 참조하는 변수는 "게양되지"않습니다. 예제 2에서 md5Hash
및 sha1Hash
함수는 스크립트의 맨 아래에 정의되어 있지만 모든 곳에서 즉시 사용할 수 있습니다. 어디서 함수를 정의하든 상관없이, 인터프리터는 해당 함수를 범위의 맨 위로 올리면 바로 사용할 수 있습니다. 이것은 변수 정의에 해당 하지 않으므로 다음과 같은 코드가 중단됩니다.
var functionVariable;
hoistedFunction(); // works, because the function is "hoisted" to the top of its scope
functionVariable(); // error: undefined is not a function.
function hoistedFunction(){}
functionVariable = function(){};
익명 기능
익명 함수 정의
함수가 정의되면, 종종 그 이름을 부여한 다음 그 이름을 사용하여 함수를 호출합니다.
foo();
function foo(){
// ...
}
이 방법으로 함수를 정의하면 Javascript 런타임은 함수를 메모리에 저장 한 다음 할당 한 이름을 사용하여 해당 함수에 대한 참조를 만듭니다. 그 이름은 현재 범위 내에서 액세스 할 수 있습니다. 이것은 함수를 만드는 매우 편리한 방법이 될 수 있지만 Javascript에서는 함수에 이름을 지정하지 않아도됩니다. 다음은 또한 완벽하게 합법적입니다 :
function() {
// ...
}
함수가 이름없이 정의되면 익명 함수라고합니다. 함수는 메모리에 저장되지만 런타임은 자동으로 참조를 작성하지 않습니다. 언뜻보기에는 그런 것이 사용되지 않는 것처럼 보일 수 있지만 익명의 기능이 매우 편리한 몇 가지 시나리오가 있습니다.
변수에 익명 함수 지정
익명 함수를 사용하는 가장 일반적인 방법은 변수에 변수를 할당하는 것입니다.
var foo = function(){ /*...*/ };
foo();
익명 함수의 사용에 대해서는 변수 로 함수 에서 자세히 설명 합니다.
매개 변수로 익명 함수를 다른 함수에 제공
일부 함수는 함수에 대한 참조를 매개 변수로 받아 들일 수 있습니다. 이러한 함수는 호출을 함수에 호출 할 수있게 해주므로 "종속성 삽입"또는 "콜백"이라고도하며 호출 된 함수의 동작 방식을 변경할 수있는 기회를 제공합니다. 예를 들어 Array 객체의 map 함수를 사용하면 배열의 각 요소를 반복하고 각 요소에 변형 함수를 적용하여 새 배열을 만들 수 있습니다.
var nums = [0,1,2];
var doubledNums = nums.map( function(element){ return element * 2; } ); // [0,2,4]
지루한, 지저분하고 불필요한 함수를 만들면이 한 곳에서만 필요한 함수로 범위를 복잡하게 만들고 자연스러운 흐름과 코드 읽기를 깨뜨릴 수 있습니다. 동료는이 코드를 사용하여 코드를 찾아야합니다. 무슨 일이 일어나는지 이해하는 기능).
다른 함수에서 익명 함수 반환
때로는 다른 함수의 결과로 함수를 반환하는 것이 유용합니다. 예 :
var hash = getHashFunction( 'sha1' );
var hashValue = hash( 'Secret Value' );
function getHashFunction( algorithm ){
if ( algorithm === 'sha1' ) return function( value ){ /*...*/ };
else if ( algorithm === 'md5' ) return function( value ){ /*...*/ };
}
익명 함수 호출 즉시
다른 많은 언어와 달리 자바 스크립트의 범위 지정은 블록 수준이 아닌 함수 수준입니다. ( 함수 스코핑 참조). 그러나 어떤 경우에는 새 범위를 만들어야합니다. 예를 들어 변수 이름을 전역 범위에서 정의하는 대신 (변수 이름과 충돌하는 다른 스크립트의 위험을 감수하는) <script>
태그를 통해 코드를 추가 할 때 새 범위를 만드는 것이 일반적입니다. 이 상황을 처리하는 일반적인 방법은 새로운 익명 함수를 정의한 다음 즉시 호출하여 익명 함수의 범위 내에서 변수를 안전하게 숨기고 코드가 유출 된 함수 이름을 통해 제 3자가 액세스 할 수있게하지 않는 것입니다. 예 :
<!-- My Script -->
<script>
function initialize(){
// foo is safely hidden within initialize, but...
var foo = '';
}
// ...my initialize function is now accessible from global scope.
// There's a risk someone could call it again, probably by accident.
initialize();
</script>
<script>
// Using an anonymous function, and then immediately
// invoking it, hides my foo variable and guarantees
// no one else can call it a second time.
(function(){
var foo = '';
}()) // <--- the parentheses invokes the function immediately
</script>
자체 참조 익명 함수
때로는 익명 함수가 자신을 참조 할 수 있도록하는 것이 유용합니다. 예를 들어, 함수는 재귀 적으로 자신을 호출하거나 자체에 속성을 추가해야 할 수 있습니다. 함수가 익명 인 경우 함수에 할당 된 변수에 대한 지식이 필요하므로 매우 어려울 수 있습니다. 이것은 이상적인 해결책이 아닙니다.
var foo = function(callAgain){
console.log( 'Whassup?' );
// Less then ideal... we're dependent on a variable reference...
if (callAgain === true) foo(false);
};
foo(true);
// Console Output:
// Whassup?
// Whassup?
// Assign bar to the original function, and assign foo to another function.
var bar = foo;
foo = function(){
console.log('Bad.')
};
bar(true);
// Console Output:
// Whassup?
// Bad.
여기에 익명 함수가 재귀 적으로 자신을 호출하는 의도가 있었지만 foo 값이 변경되면 잠재적으로 버그를 추적하기가 어려워집니다.
대신 익명 함수에 다음과 같이 개인 이름을 지정하여 자체에 대한 참조를 제공 할 수 있습니다.
var foo = function myself(callAgain){
console.log( 'Whassup?' );
// Less then ideal... we're dependent on a variable reference...
if (callAgain === true) myself(false);
};
foo(true);
// Console Output:
// Whassup?
// Whassup?
// Assign bar to the original function, and assign foo to another function.
var bar = foo;
foo = function(){
console.log('Bad.')
};
bar(true);
// Console Output:
// Whassup?
// Whassup?
함수 이름 자체에 적용됩니다. 이름은 바깥 범위로 유출되지 않았습니다.
myself(false); // ReferenceError: myself is not defined
이 기법은 재귀 익명 함수를 콜백 매개 변수로 처리 할 때 특히 유용합니다.
// Calculate the fibonacci value for each number in an array:
var fib = false,
result = [1,2,3,4,5,6,7,8].map(
function fib(n){
return ( n <= 2 ) ? 1 : fib( n - 1 ) + fib( n - 2 );
});
// result = [1, 1, 2, 3, 5, 8, 13, 21]
// fib = false (the anonymous function name did not overwrite our fib variable)
즉시 함수 표현식 호출
때로는 함수를 변수로 액세스 / 저장할 수 없도록하려는 경우가 있습니다. 즉시 호출 된 함수 식 (IIFE)을 만들 수 있습니다. 이것은 본질적으로 자체 실행 익명 기능 입니다. 그들은 주변 범위에 액세스 할 수 있지만 함수 자체와 내부 변수는 외부에서 액세스 할 수 없습니다. IIFE에 대해 중요한 점은 함수의 이름을 지정하더라도 IIFE는 표준 함수처럼 호이스트되지 않으며 선언 된 함수 이름으로 호출 할 수 없다는 것입니다.
(function() {
alert("I've run - but can't be run again because I'm immediately invoked at runtime,
leaving behind only the result I generate");
}());
이것이 IIFE를 작성하는 또 다른 방법입니다. 세미콜론 앞에 닫는 괄호가 이동하여 닫는 둥근 괄호 바로 뒤에 놓입니다.
(function() {
alert("This is IIFE too.");
})();
IIFE에 매개 변수를 쉽게 전달할 수 있습니다.
(function(message) {
alert(message);
}("Hello World!"));
또한 값을 주변 범위로 반환 할 수 있습니다.
var example = (function() {
return 42;
}());
console.log(example); // => 42
필요한 경우 IIFE의 이름을 지정할 수 있습니다. 이 패턴은 재귀에 사용할 수있는 참조를 제공하는 것과 같이 이름이 호출 스택에 포함되어 있으면 디버깅을 더 간단하게 만들 수있는 등 몇 가지 이점이 있습니다.
(function namedIIFE() {
throw error; // We can now see the error thrown in 'namedIIFE()'
}());
괄호 안에 함수를 래핑하는 것은 자바 파서 파서가 표현식을 기대한다는 것을 나타내는 가장 일반적인 방법이지만, 표현식이 이미 예상되는 곳에서는 표기법을 더 간결하게 만들 수 있습니다.
var a = function() { return 42 }();
console.log(a) // => 42
즉시 호출 된 함수의 화살표 버전 :
(() => console.log("Hello!"))(); // => Hello!
함수 스코핑
함수를 정의하면 범위 가 만들어집니다.
함수 내에 정의 된 모든 것은 함수 외부의 코드에서 액세스 할 수 없습니다. 이 범위 내의 코드 만 범위 내부에 정의 된 엔터티를 볼 수 있습니다.
function foo() {
var a = 'hello';
console.log(a); // => 'hello'
}
console.log(a); // reference error
중첩 된 함수는 JavaScript에서 가능하며 동일한 규칙이 적용됩니다.
function foo() {
var a = 'hello';
function bar() {
var b = 'world';
console.log(a); // => 'hello'
console.log(b); // => 'world'
}
console.log(a); // => 'hello'
console.log(b); // reference error
}
console.log(a); // reference error
console.log(b); // reference error
JavaScript가 참조 또는 변수를 분석하려고하면 현재 범위에서 참조 또는 변수를 찾습니다. 현재 범위에서 해당 선언을 찾을 수 없으면 하나의 범위를 찾아서 찾습니다. 이 프로세스는 선언이 발견 될 때까지 반복됩니다. JavaScript 구문 분석기가 전역 범위에 도달해도 참조를 찾을 수없는 경우 참조 오류가 발생합니다.
var a = 'hello';
function foo() {
var b = 'world';
function bar() {
var c = '!!';
console.log(a); // => 'hello'
console.log(b); // => 'world'
console.log(c); // => '!!'
console.log(d); // reference error
}
}
이 등반 동작은 처음 참조 된 이후에 하나의 참조가 외부 범위의 비슷한 이름의 참조에 "그림자"를 나타낼 수도 있음을 의미 할 수도 있습니다.
var a = 'hello';
function foo() {
var a = 'world';
function bar() {
console.log(a); // => 'world'
}
}
JavaScript가 범위를 결정하는 방법은 const
키워드에도 적용됩니다. const
키워드로 변수를 선언하면 값을 재 할당 할 수 없지만 함수에서 선언하면 새 범위가 만들어지고 새 변수가 만들어집니다.
function foo() {
const a = true;
function bar() {
const a = false; // different variable
console.log(a); // false
}
const a = false; // SyntaxError
a = false; // TypeError
console.log(a); // true
}
그러나 함수는 let
또는 const
사용하는 경우 범위를 만드는 유일한 블록이 아닙니다. let
및 const
선언에는 가장 가까운 블록 문 범위가 있습니다. 자세한 설명은 여기 를 참조 하십시오 .
`this`와 인수 바인딩하기
JavaScript에서 메서드 (함수 인 속성)에 대한 참조를 가져 오는 경우 일반적으로 원래 첨부 된 객체를 기억하지 않습니다. 메서드 this
객체를 참조 할 필요가있는 경우 메서드에서이를 호출 할 수 없으며 호출하면 충돌이 발생할 수 있습니다.
함수에 .bind()
메서드를 사용하면 this
값과 여러 개의 선행 인수의 값을 포함하는 래퍼를 만들 수 있습니다.
var monitor = {
threshold: 5,
check: function(value) {
if (value > this.threshold) {
this.display("Value is too high!");
}
},
display(message) {
alert(message);
}
};
monitor.check(7); // The value of `this` is implied by the method call syntax.
var badCheck = monitor.check;
badCheck(15); // The value of `this` is window object and this.threshold is undefined, so value > this.threshold is false
var check = monitor.check.bind(monitor);
check(15); // This value of `this` was explicitly bound, the function works.
var check8 = monitor.check.bind(monitor, 8);
check8(); // We also bound the argument to `8` here. It can't be re-specified.
하지 엄격 모드에서, 함수는 전역 객체 (사용하는 경우 window
으로 브라우저를) this
함수가하는 방법으로 불리는 결합, 또는 메소드 호출되지 않는 한, .call
구문.
window.x = 12;
function example() {
return this.x;
}
console.log(example()); // 12
엄격 모드에서는 this
되어 undefined
기본적으로
window.x = 12;
function example() {
"use strict";
return this.x;
}
console.log(example()); // Uncaught TypeError: Cannot read property 'x' of undefined(…)
바인드 연산자
이중 콜론 바인드 연산자 는 위에서 설명한 개념의 단축 구문으로 사용할 수 있습니다.
var log = console.log.bind(console); // long version
const log = ::console.log; // short version
foo.bar.call(foo); // long version
foo::bar(); // short version
foo.bar.call(foo, arg1, arg2, arg3); // long version
foo::bar(arg1, arg2, arg3); // short version
foo.bar.apply(foo, args); // long version
foo::bar(...args); // short version
이 구문은 바인딩에 대한 걱정없이, 당신은 일반적으로 쓸 수있는 this
모든 곳.
콘솔 함수를 변수에 바인딩
var log = console.log.bind(console);
용법:
log('one', '2', 3, [4], {5: 5});
산출:
one 2 3 [4] Object {5: 5}
왜 그걸 할거야?
한 가지 유스 케이스는 사용자 정의 로거가 있고 사용할 런타임을 결정할 때입니다.
var logger = require('appLogger');
var log = logToServer ? logger.log : console.log.bind(console);
함수 인수, "arguments"객체, rest 및 spread 매개 변수
함수는 자신의 범위 내에서 사용 및 할당 할 수있는 변수 형식의 입력을 사용할 수 있습니다. 다음 함수는 두 개의 숫자 값을 사용하고 그 합을 반환합니다.
function addition (argument1, argument2){
return argument1 + argument2;
}
console.log(addition(2, 3)); // -> 5
arguments
객체
arguments
객체는 기본값 이 아닌 모든 함수의 매개 변수를 포함 합니다 . 매개 변수가 명시 적으로 선언되지 않은 경우에도 사용할 수 있습니다.
(function() { console.log(arguments) })(0,'str', [2,{3}]) // -> [0, "str", Array[2]]
arguments
를 인쇄 할 때 출력이 Array와 비슷하지만 실제로는 객체입니다.
(function() { console.log(typeof arguments) })(); // -> object
나머지 매개 변수 : function (...parm) {}
ES6에서 ...
구문은 함수의 매개 변수 선언에 사용될 때 선언 된 변수 뒤에 제공된 나머지 모든 매개 변수를 포함하는 단일 객체로 변수를 오른쪽으로 변환합니다. 이렇게하면이 변수의 일부가 될 수있는 무제한의 인수로 함수를 호출 할 수 있습니다.
(function(a, ...b){console.log(typeof b+': '+b[0]+b[1]+b[2]) })(0,1,'2',[3],{i:4});
// -> object: 123
확산 매개 변수 : function_name(...varb);
ES6에서 ...
구문은 객체 / 변수를 오른쪽으로 배치하여 함수를 호출 할 때도 사용할 수 있습니다. 이렇게하면 해당 객체의 요소가 단일 객체로 해당 함수로 전달됩니다.
let nums = [2,42,-1];
console.log(...['a','b','c'], Math.max(...nums)); // -> a b c 42
명명 된 함수
함수의 이름을 지정하거나 이름을 지정하지 않을 수 있습니다 ( 익명 함수 ).
var namedSum = function sum (a, b) { // named
return a + b;
}
var anonSum = function (a, b) { // anonymous
return a + b;
}
namedSum(1, 3);
anonSum(1, 3);
4
4
그러나 그들의 이름은 그들 자신의 범위에서 사적이다.
var sumTwoNumbers = function sum (a, b) {
return a + b;
}
sum(1, 3);
잡히지 않은 ReferenceError : 합계가 정의되지 않았습니다.
명명 된 함수는 여러 시나리오에서 익명 함수와 다릅니다.
- 디버깅 할 때 함수의 이름이 오류 / 스택 추적에 나타납니다.
- 명명 된 함수는 익명 함수가 아닌 동안 호이스트 됩니다.
- 명명 된 함수와 익명 함수는 재귀를 처리 할 때 다르게 작동합니다.
- ECMAScript 버전에 따라 명명 된 익명 함수는 함수
name
속성을 다르게 처리 할 수 있습니다
명명 된 함수는 게양됩니다.
익명 함수를 사용할 때 함수는 선언 행 다음에 호출 될 수 있지만 명명 된 함수는 선언 전에 호출 될 수 있습니다. 중히 여기다
foo();
var foo = function () { // using an anonymous function
console.log('bar');
}
잡히지 않는 TypeError : foo가 함수가 아닙니다.
foo();
function foo () { // using a named function
console.log('bar');
}
바
재귀 시나리오에서 명명 된 함수
재귀 함수는 다음과 같이 정의 할 수 있습니다.
var say = function (times) {
if (times > 0) {
console.log('Hello!');
say(times - 1);
}
}
//you could call 'say' directly,
//but this way just illustrates the example
var sayHelloTimes = say;
sayHelloTimes(2);
여보세요!
여보세요!
코드의 어딘가에서 원래 함수 바인딩이 재정의되면 어떨까요?
var say = function (times) {
if (times > 0) {
console.log('Hello!');
say(times - 1);
}
}
var sayHelloTimes = say;
say = "oops";
sayHelloTimes(2);
여보세요!
잡히지 않은 TypeError : 말은 함수가 아닙니다.
이것은 명명 된 함수를 사용하여 해결할 수 있습니다.
// The outer variable can even have the same name as the function
// as they are contained in different scopes
var say = function say (times) {
if (times > 0) {
console.log('Hello!');
// this time, 'say' doesn't use the outer variable
// it uses the named function
say(times - 1);
}
}
var sayHelloTimes = say;
say = "oops";
sayHelloTimes(2);
여보세요!
여보세요!
보너스로, 내부에서조차도 명명 된 함수를 undefined
로 설정할 수 없습니다.
var say = function say (times) {
// this does nothing
say = undefined;
if (times > 0) {
console.log('Hello!');
// this time, 'say' doesn't use the outer variable
// it's using the named function
say(times - 1);
}
}
var sayHelloTimes = say;
say = "oops";
sayHelloTimes(2);
여보세요!
여보세요!
함수의 name
속성
ES6 이전에는 명명 된 함수의 name
속성이 함수 이름으로 설정되었고 익명 함수의 name
속성은 빈 문자열로 설정되었습니다.
var foo = function () {}
console.log(foo.name); // outputs ''
function foo () {}
console.log(foo.name); // outputs 'foo'
Post ES6, 명명 된 함수와 명명되지 않은 함수는 둘 다 name
속성을 설정합니다.
var foo = function () {}
console.log(foo.name); // outputs 'foo'
function foo () {}
console.log(foo.name); // outputs 'foo'
var foo = function bar () {}
console.log(foo.name); // outputs 'bar'
재귀 함수
재귀 함수는 단순히 자체 함수를 호출하는 함수입니다.
function factorial (n) {
if (n <= 1) {
return 1;
}
return n * factorial(n - 1);
}
위의 함수는 계승을 반환하는 재귀 함수를 수행하는 방법에 대한 기본 예제를 보여줍니다.
또 다른 예는 배열에서 짝수의 합을 검색하는 것입니다.
function countEvenNumbers (arr) {
// Sentinel value. Recursion stops on empty array.
if (arr.length < 1) {
return 0;
}
// The shift() method removes the first element from an array
// and returns that element. This method changes the length of the array.
var value = arr.shift();
// `value % 2 === 0` tests if the number is even or odd
// If it's even we add one to the result of counting the remainder of
// the array. If it's odd, we add zero to it.
return ((value % 2 === 0) ? 1 : 0) + countEvens(arr);
}
그러한 함수가 무한 루프를 피하기 위해 센티널 값 체크의 일종을 만드는 것이 중요합니다. 위의 첫 번째 예에서 n
이 1보다 작거나 같으면 재귀가 중지되고 각 호출의 결과가 호출 스택에 백업됩니다.
커링
currying 은 하나의 인수 만 취하는 n
함수의 순서로 n
n
인수 또는 인수의 함수를 변환하는 것입니다.
사용 사례 : 일부 인수의 값을 다른 인수보다 먼저 사용할 수있는 경우 currying을 사용하여 각 값이 도착할 때 단계별로 작업을 완료하는 일련의 함수로 함수를 분해 할 수 있습니다. 유용 할 수 있습니다.
- 인수의 값이 거의 변하지 않을 때 (예 : 변환 요소), 값을 하드 코딩하는 대신 상수로 설정하는 유연성을 유지해야합니다.
- 다른 카레 기능이 실행되기 전에 카 트리 기능의 결과가 유용한 경우.
- 특정 순서로 함수의 도착을 확인합니다.
예를 들어 직각 프리즘의 부피는 길이 ( l
), 폭 ( w
) 및 높이 ( h
)의 세 가지 요소의 함수로 설명 할 수 있습니다.
var prism = function(l, w, h) {
return l * w * h;
}
이 함수의 카레 된 버전은 다음과 같습니다.
function prism(l) {
return function(w) {
return function(h) {
return l * w * h;
}
}
}
// alternatively, with concise ECMAScript 6+ syntax:
var prism = l => w => h => l * w * h;
이 함수 시퀀스는 prism(2)(3)(5)
호출 할 수 있습니다.이 값은 30으로 계산됩니다.
라이브러리와 같은 추가 기계를 추가하지 않으면 자바 스크립트 (ES 5/6)의 문법적 유연성이 제한됩니다 (자리 표시 자 값이 부족하기 때문에). 따라서 var a = prism(2)(3)
을 사용하여 부분적으로 적용된 함수 를 만들 수는 있지만 prism()(3)(5)
사용할 수 없습니다.
Return 문 사용
return 문은 함수 출력을 만드는 유용한 방법이 될 수 있습니다. return 문은 함수가 아직 사용될 문맥을 모른다면 특히 유용합니다.
//An example function that will take a string as input and return
//the first character of the string.
function firstChar (stringIn){
return stringIn.charAt(0);
}
이제이 함수를 사용하려면 코드의 다른 위치에 변수를 넣어야합니다.
함수 결과를 다른 함수의 인수로 사용 :
console.log(firstChar("Hello world"));
콘솔 출력은 다음과 같습니다.
> H
return 문은 함수를 종료합니다.
처음에 함수를 수정하면 return 문이 함수를 끝내는 것을 보여줄 수 있습니다.
function firstChar (stringIn){
console.log("The first action of the first char function");
return stringIn.charAt(0);
console.log("The last action of the first char function");
}
이 함수를 이렇게 실행하면 다음과 같이됩니다.
console.log(firstChar("JS"));
콘솔 출력 :
> The first action of the first char function
> J
함수가 이제 끝났기 때문에 return 문 다음에 메시지를 인쇄하지 않습니다.
여러 줄에 걸쳐있는 return 문 :
JavaScript에서는 일반적으로 가독성을 위해 코드 줄을 여러 줄로 나눌 수 있습니다. 유효한 JavaScript입니다.
var
name = "bob",
age = 18;
JavaScript가 var
와 같은 불완전한 문장을 보게되면, 다음 줄을보고 그 문장을 완성합니다. 그러나 return
문과 동일한 실수를하면 예상 한 결과를 얻을 수 없습니다.
return
"Hi, my name is "+ name + ". " +
"I'm "+ age + " years old.";
이 코드는 자체적으로 return
이 Javascript의 완전한 문장이기 때문에 undefined
return
할 것이므로 다음 줄로 넘어 가면 완료되지 않을 것입니다. return
문을 여러 줄로 나눌 필요가있는 경우에는 분할하기 전에 return 옆에 값을 입력하십시오.
return "Hi, my name is " + name + ". " +
"I'm " + age + " years old.";
인수를 참조 또는 값으로 전달
자바 스크립트에서 모든 인수는 값으로 전달됩니다. 함수가 인수 변수에 새 값을 할당하면 해당 변경 내용이 호출자에게 표시되지 않습니다.
var obj = {a: 2};
function myfunc(arg){
arg = {a: 5}; // Note the assignment is to the parameter variable itself
}
myfunc(obj);
console.log(obj.a); // 2
그러나 이러한 인수 의 중첩 된 속성에 대한 변경 사항은 호출자에게 표시됩니다.
var obj = {a: 2};
function myfunc(arg){
arg.a = 5; // assignment to a property of the argument
}
myfunc(obj);
console.log(obj.a); // 5
이를 참조하여 전화로 볼 수 있습니다 : 함수가에 새 값을 할당하여 발신자의 객체를 변경할 수 있지만, 그것은 호출자의 개체 변이 수 있습니다.
숫자 나 문자열과 같은 원시적 인 값을 갖는 인수는 불변이므로 함수가 변형시킬 수있는 방법은 없습니다.
var s = 'say';
function myfunc(arg){
arg += ' hello'; // assignment to the parameter variable itself
}
myfunc(s);
console.log(s); // 'say'
함수가 인수로 전달 된 객체를 변경하려고하지만 호출자의 객체를 실제로 변경하려고하지 않을 경우 인수 변수를 다시 할당해야합니다.
var obj = {a: 2, b: 3};
function myfunc(arg){
arg = Object.assign({}, arg); // assignment to argument variable, shallow copy
arg.a = 5;
}
myfunc(obj);
console.log(obj.a); // 2
인수의 내부 변형에 대한 대안으로 함수는 인수를 기반으로 새로운 값을 생성하고이를 반환 할 수 있습니다. 그런 다음 호출자는 인수로 전달 된 원래 변수에도 할당 할 수 있습니다.
var a = 2;
function myfunc(arg){
arg++;
return arg;
}
a = myfunc(a);
console.log(obj.a); // 3
전화 및 신청
함수에는 프로그래머가 인수 this
변수를 다르게 제공 할 수있는 두 가지 기본 제공 메서드가 apply
. call
및 apply
입니다.
이는 하나의 객체 (속성 인 객체)에서 작동하는 함수가 다른 호환 객체에서 작동하도록 용도 변경 될 수 있기 때문에 유용합니다. 또한 인수는 ES6에서 spread ( ...
) 연산자와 비슷한 배열로 한 번에 제공 될 수 있습니다.
let obj = {
a: 1,
b: 2,
set: function (a, b) {
this.a = a;
this.b = b;
}
};
obj.set(3, 7); // normal syntax
obj.set.call(obj, 3, 7); // equivalent to the above
obj.set.apply(obj, [3, 7]); // equivalent to the above; note that an array is used
console.log(obj); // prints { a: 3, b: 5 }
let myObj = {};
myObj.set(5, 4); // fails; myObj has no `set` property
obj.set.call(myObj, 5, 4); // success; `this` in set() is re-routed to myObj instead of obj
obj.set.apply(myObj, [5, 4]); // same as above; note the array
console.log(myObj); // prints { a: 3, b: 5 }
ECMAScript 5는 call()
과 apply()
외에도 bind()
라는 또 다른 메소드를 도입하여 함수 this
값을 명시 적으로 특정 객체에 설정합니다.
그것은 다른 두 가지와 아주 다른 방식으로 행동합니다. bind()
의 첫 번째 인수는 새 함수에 대한 this
값입니다. 다른 모든 인수는 새 함수에 영구적으로 설정해야하는 명명 된 매개 변수를 나타냅니다.
function showName(label) {
console.log(label + ":" + this.name);
}
var student1 = {
name: "Ravi"
};
var student2 = {
name: "Vinod"
};
// create a function just for student1
var showNameStudent1 = showName.bind(student1);
showNameStudent1("student1"); // outputs "student1:Ravi"
// create a function just for student2
var showNameStudent2 = showName.bind(student2, "student2");
showNameStudent2(); // outputs "student2:Vinod"
// attaching a method to an object doesn't change `this` value of that method.
student2.sayName = showNameStudent1;
student2.sayName("student2"); // outputs "student2:Ravi"
기본 매개 변수
ECMAScript 2015 (ES6) 이전에는 매개 변수의 기본값을 다음과 같은 방식으로 지정할 수있었습니다.
function printMsg(msg) {
msg = typeof msg !== 'undefined' ? // if a value was provided
msg : // then, use that value in the reassignemnt
'Default value for msg.'; // else, assign a default value
console.log(msg);
}
ES6은 위에 묘사 된 조건과 재 할당이 더 이상 필요하지 않은 새로운 구문을 제공했습니다.
function printMsg(msg='Default value for msg.') {
console.log(msg);
}
printMsg(); // -> "Default value for msg."
printMsg(undefined); // -> "Default value for msg."
printMsg('Now my msg in different!'); // -> "Now my msg in different!"
또한 함수가 호출 될 때 매개 변수가 누락 된 경우 해당 값은 undefined
로 유지됩니다 ( 화살표 함수를 사용하여 다음 예제에서 명시 적으로 제공함으로써 확인할 수 있음).
let param_check = (p = 'str') => console.log(p + ' is of type: ' + typeof p);
param_check(); // -> "str is of type: string"
param_check(undefined); // -> "str is of type: string"
param_check(1); // -> "1 is of type: number"
param_check(this); // -> "[object Window] is of type: object"
함수 / 변수를 기본값으로 사용하고 매개 변수를 재사용합니다.
기본 매개 변수의 값은 숫자, 문자열 또는 단순한 개체로 제한되지 않습니다. 함수를 기본값으로 설정할 수도 있습니다. callback = function(){}
:
function foo(callback = function(){ console.log('default'); }) {
callback();
}
foo(function (){
console.log('custom');
});
// custom
foo();
//default
기본값을 통해 수행 할 수있는 작업의 특정 특성은 다음과 같습니다.
- 이전에 선언 된 매개 변수는 다음 매개 변수의 값에 대한 기본값으로 재사용 할 수 있습니다.
- 인라인 조작은 매개 변수에 기본값을 지정할 때 허용됩니다.
- 선언되는 함수의 동일한 범위에있는 변수는 기본값으로 사용될 수 있습니다.
- 반환 값을 기본값으로 제공하기 위해 함수를 호출 할 수 있습니다.
let zero = 0;
function multiply(x) { return x * 2;}
function add(a = 1 + zero, b = a, c = b + a, d = multiply(c)) {
console.log((a + b + c), d);
}
add(1); // 4, 4
add(3); // 12, 12
add(2, 7); // 18, 18
add(1, 2, 5); // 8, 10
add(1, 2, 5, 10); // 8, 20
새 호출의 기본값에서 함수의 리턴 값 재사용 :
let array = [1]; // meaningless: this will be overshadowed in the function's scope
function add(value, array = []) {
array.push(value);
return array;
}
add(5); // [5]
add(6); // [6], not [5, 6]
add(6, add(5)); // [5, 6]
호출시 매개 변수가 없을 때의 arguments
값 및 길이
arguments
배열 객체 는 값이 기본값이 아닌 매개 변수, 즉 함수가 호출 될 때 명시 적으로 제공되는 매개 변수 만 보유합니다.
function foo(a = 1, b = a + 1) {
console.info(arguments.length, arguments);
console.log(a,b);
}
foo(); // info: 0 >> [] | log: 1, 2
foo(4); // info: 1 >> [4] | log: 4, 5
foo(5, 6); // info: 2 >> [5, 6] | log: 5, 6
알 수없는 인수 개수의 함수 (가변 함수)
결정되지 않은 수의 인수를 허용하는 함수를 작성하려면 사용자 환경에 따라 두 가지 f}이 있습니다.
함수가 호출 될 때마다 함수에 전달 된 모든 인수를 포함하는 범위와 같은 arguments 객체를가집니다. 이것에 색인을 붙이거나 반복하면 인수에 대한 액세스가 제공됩니다 (예 :
function logSomeThings() {
for (var i = 0; i < arguments.length; ++i) {
console.log(arguments[i]);
}
}
logSomeThings('hello', 'world');
// logs "hello"
// logs "world"
필요한 경우 arguments
를 실제 Array로 변환 할 수 있습니다. 배열과 같은 객체를 배열로 변환하기
ES6에서 나머지 연산자 ( ...
)를 사용하여 마지막 매개 변수로 함수를 선언 할 수 있습니다. 그 시점부터 인수를 보유하는 Array를 만듭니다.
function personLogsSomeThings(person, ...msg) {
msg.forEach(arg => {
console.log(person, 'says', arg);
});
}
personLogsSomeThings('John', 'hello', 'world');
// logs "John says hello"
// logs "John says world"
기능도 비슷한 방식의 호출 할 수 있습니다 확산 구문
const logArguments = (...args) => console.log(args)
const list = [1, 2, 3]
logArguments('a', 'b', 'c', ...list)
// output: Array [ "a", "b", "c", 1, 2, 3 ]
이 구문은 임의의 수의 인수를 임의의 위치에 삽입하는 데 사용할 수 있으며 모든 반복 가능 매개 변수와 함께 사용할 수 있습니다 ( apply
는 배열과 유사한 객체 만 허용 함).
const logArguments = (...args) => console.log(args)
function* generateNumbers() {
yield 6
yield 5
yield 4
}
logArguments('a', ...generateNumbers(), ...'pqr', 'b')
// output: Array [ "a", 6, 5, 4, "p", "q", "r", "b" ]
함수 객체의 이름을 가져옵니다.
ES5 :
함수에 대한 참조가있는 경우 다음을 수행 할 수 있습니다.
function functionName( func )
{
// Match:
// - ^ the beginning of the string
// - function the word 'function'
// - \s+ at least some white space
// - ([\w\$]+) capture one or more valid JavaScript identifier characters
// - \( followed by an opening brace
//
var result = /^function\s+([\w\$]+)\(/.exec( func.toString() )
return result ? result[1] : ''
}
부분 신청
currying과 마찬가지로 부분 애플리케이션은 함수에 전달 된 인수의 수를 줄이는 데 사용됩니다. 카레와 달리 번호는 하나씩 내려갈 필요가 없습니다.
예:
이 기능은 ...
function multiplyThenAdd(a, b, c) {
return a * b + c;
}
... 항상 2를 곱한 다음 전달 된 값에 10을 더하는 다른 함수를 만드는 데 사용할 수 있습니다.
function reversedMultiplyThenAdd(c, b, a) {
return a * b + c;
}
function factory(b, c) {
return reversedMultiplyThenAdd.bind(null, c, b);
}
var multiplyTwoThenAddTen = factory(2, 10);
multiplyTwoThenAddTen(10); // 30
부분 적용의 "적용"부분은 단순히 기능의 매개 변수를 고정하는 것을 의미합니다.
기능 구성
여러 함수를 하나로 합성하는 것은 함수형 프로그래밍의 일반적인 관행입니다.
컴포지션은 우리의 데이터가 전달되고 기능 구성에 대한 작업을 수정하는 파이프 라인을 만듭니다 (트랙 조각을 함께 스냅하는 것처럼) ...
당신은 하나의 책임 함수를 가지고 시작합니다 :
const capitalize = x => x.replace(/^\w/, m => m.toUpperCase());
const sign = x => x + ',\nmade with love';
변환 트랙을 쉽게 만들 수 있습니다.
const formatText = compose(capitalize, sign);
formatText('this is an example')
//This is an example,
//made with love
주 :이 예에서와 같이 일반적으로 compose
이라고하는 유틸리티 기능을 통해 구성이 이루어집니다.
compose
구현은 많은 JavaScript 유틸리티 라이브러리 ( lodash , rambda 등)에 있지만, 다음과 같은 간단한 구현으로 시작할 수도 있습니다.
const compose = (...funs) =>
x =>
funs.reduce((ac, f) => f(ac), x);