[javascript] 자바 스크립트에서 함수 오버로드-모범 사례

Javascript에서 함수 과부하를 가짜로 만드는 가장 좋은 방법은 무엇입니까?

다른 언어와 마찬가지로 Javascript에서 함수를 오버로드 할 수 없다는 것을 알고 있습니다. 두 가지 용도로 기능이 필요 하고 가장 foo(x)좋고 foo(x,y,z)선호되는 방법 인 경우 :

  1. 처음에 다른 이름 사용
  2. 다음과 같은 선택적 인수 사용 y = y || 'default'
  3. 다수의 인수 사용
  4. 인수 유형 확인
  5. 아니면 어떻게?


답변

매개 변수로 함수 오버로딩을 수행하는 가장 좋은 방법은 인수 길이 또는 유형을 확인하지 않는 것입니다. 유형을 확인하면 코드가 느려지고 Arrays, nulls, Objects 등이 재미 있습니다.

대부분의 개발자가하는 것은 객체의 메서드에 대한 마지막 인수로 객체를 고정하는 것입니다. 이 객체는 무엇이든 담을 수 있습니다.

function foo(a, b, opts) {
  // ...
  if (opts['test']) { } //if test param exists, do something.. 
}


foo(1, 2, {"method":"add"});
foo(3, 4, {"test":"equals", "bar":"tree"});

그런 다음 어쨌든 원하는 방식으로 처리 할 수 ​​있습니다. [스위치, 그렇지 않은 경우 등]


답변

나는 종종 이것을한다 :

씨#:

public string CatStrings(string p1)                  {return p1;}
public string CatStrings(string p1, int p2)          {return p1+p2.ToString();}
public string CatStrings(string p1, int p2, bool p3) {return p1+p2.ToString()+p3.ToString();}

CatStrings("one");        // result = one
CatStrings("one",2);      // result = one2
CatStrings("one",2,true); // result = one2true

동등한 JavaScript :

function CatStrings(p1, p2, p3)
{
  var s = p1;
  if(typeof p2 !== "undefined") {s += p2;}
  if(typeof p3 !== "undefined") {s += p3;}
  return s;
};

CatStrings("one");        // result = one
CatStrings("one",2);      // result = one2
CatStrings("one",2,true); // result = one2true

이 특정 예제는 실제로 C #보다 자바 스크립트에서 더 우아합니다. 지정되지 않은 매개 변수는 javascript에서 ‘정의되지 않음’이며 if 문에서 false로 평가됩니다. 그러나 함수 정의는 p2 및 p3이 선택적이라는 정보를 전달하지 않습니다. 많은 오버로드가 필요한 경우 jQuery는 객체를 매개 변수로 사용하기로 결정했습니다 (예 : jQuery.ajax (options)). 나는 이것이 과부하에 대한 가장 강력하고 명확하게 문서화 가능한 접근 방법이라는 것에 동의하지만, 하나 또는 두 개 이상의 빠른 옵션 매개 변수가 거의 필요하지 않습니다.

편집 : 이안의 제안에 따라 IF 테스트 변경


답변

모든 유형의 매개 변수를 전달할 수 있으므로 JavaScript에는 실제 함수 오버로드가 없습니다. 당신은 많은 방법 함수 내에서 확인해야 인수가 전달 된 것과 그들이 입력합니다.


답변

정답은 JAVASCRIPT에 과부하가 없다는 것입니다.

기능 내부 점검 / 전환이 과부하가 아닙니다.

오버로딩 개념 : 일부 프로그래밍 언어에서 함수 오버로딩 또는 메서드 오버로딩은 구현이 다른 동일한 이름의 여러 메서드를 만들 수있는 기능입니다. 오버로드 된 함수에 대한 호출은 호출의 컨텍스트에 적합한 해당 기능의 특정 구현을 실행하여 하나의 함수 호출이 컨텍스트에 따라 다른 작업을 수행 할 수 있도록합니다.

예를 들어 doTask () 및 doTask (object O)는 오버로드 된 메서드입니다. 후자를 호출하려면 객체를 매개 변수로 전달해야하지만 전자는 매개 변수를 요구하지 않으며 빈 매개 변수 필드로 호출됩니다. 일반적인 오류는 두 번째 방법에서 객체에 기본값을 할당하는 것인데, 컴파일러는 사용할 두 가지 방법 중 어느 것을 알지 못하기 때문에 모호한 호출 오류가 발생합니다.

https://en.wikipedia.org/wiki/Function_overloading

제안 된 모든 구현은 훌륭하지만 사실은 JavaScript의 기본 구현은 없습니다.


답변

더 잘 접근 할 수있는 두 가지 방법이 있습니다.

  1. 많은 유연성을 유지하려면 사전 (연관 배열)을 전달하십시오.

  2. 객체를 인수로 사용하고 프로토 타입 기반 상속을 사용하여 유연성을 추가하십시오.


답변

다음은 매개 변수 유형을 사용하여 실제 메소드 오버로드를 허용하는 접근법입니다.

Func(new Point());
Func(new Dimension());
Func(new Dimension(), new Point());
Func(0, 0, 0, 0);

편집 (2018) : 2011 년에 작성된 이래로 직접 메서드 호출 속도는 크게 증가했지만 오버로드 된 메서드 속도는 증가하지 않았습니다.

이 방법을 권장하지는 않지만 이러한 유형의 문제를 해결하는 방법에 대해 생각하는 것이 좋습니다.


https://jsperf.com/function-overloading- 다양한 접근 방식의 벤치 마크입니다 . 그것은 그 기능 (계정으로 유형을 복용) 과부하 주위에있을 수 있습니다 보여줍니다 13 배 느린 구글에서 크롬의 V8 기준으로 16.0 (베타) .

객체 (즉 {x: 0, y: 0}) 를 전달할뿐만 아니라 적절한 경우 메소드의 이름을 지정하여 C 접근법을 취할 수도 있습니다. 예를 들어 Vector.AddVector (vector), Vector.AddIntegers (x, y, z, …) 및 Vector.AddArray (integerArray)입니다. 영감을주는 OpenGL과 같은 C 라이브러리를 볼 수 있습니다.

편집 : 나는 개체를 전달하고 모두를 사용하여 객체에 대한 테스트를위한 벤치 마크를 추가 한 'param' in argarg.hasOwnProperty('param') , 함수 오버로드는 훨씬 더 빨리 (적어도이 벤치 마크에서) 속성에 대한 대상 및 검사를 통과보다.

설계 관점에서 함수 오버로딩은 오버로드 된 매개 변수가 동일한 조치에 해당하는 경우에만 유효하거나 논리적입니다. 따라서 특정 세부 사항에만 관련된 기본 방법이 있어야하며 그렇지 않은 경우 부적절한 디자인 선택을 나타낼 수 있습니다. 따라서 데이터를 개별 객체로 변환하여 함수 오버로드 사용을 해결할 수도 있습니다. 물론 이름을 인쇄하려는 의도가 있다면 정교한 디자인을 만들 필요가 없기 때문에 문제의 범위를 고려해야하지만 프레임 워크와 라이브러리의 디자인에는 그러한 생각이 정당합니다.

내 예제는 Rectangle 구현에서 온 것이므로 Dimension 및 Point에 대한 언급입니다. 아마도 Rectangle이 및 프로토 타입에 GetRectangle()메소드를 추가 한 다음 함수 오버로드 문제가 정렬 될 수 있습니다. 프리미티브는 어떻습니까? 자, 우리는 인자 길이를 가지고 있는데, 이것은 객체에 메소드 가 있기 때문에 이제 유효한 테스트 입니다.DimensionPointGetRectangle()

function Dimension() {}
function Point() {}

var Util = {};

Util.Redirect = function (args, func) {
  'use strict';
  var REDIRECT_ARGUMENT_COUNT = 2;

  if(arguments.length - REDIRECT_ARGUMENT_COUNT !== args.length) {
    return null;
  }

  for(var i = REDIRECT_ARGUMENT_COUNT; i < arguments.length; ++i) {
    var argsIndex = i-REDIRECT_ARGUMENT_COUNT;
    var currentArgument = args[argsIndex];
    var currentType = arguments[i];
    if(typeof(currentType) === 'object') {
      currentType = currentType.constructor;
    }
    if(typeof(currentType) === 'number') {
      currentType = 'number';
    }
    if(typeof(currentType) === 'string' && currentType === '') {
      currentType = 'string';
    }
    if(typeof(currentType) === 'function') {
      if(!(currentArgument instanceof currentType)) {
        return null;
      }
    } else {
      if(typeof(currentArgument) !== currentType) {
        return null;
      }
    }
  }
  return [func.apply(this, args)];
}

function FuncPoint(point) {}
function FuncDimension(dimension) {}
function FuncDimensionPoint(dimension, point) {}
function FuncXYWidthHeight(x, y, width, height) { }

function Func() {
  Util.Redirect(arguments, FuncPoint, Point);
  Util.Redirect(arguments, FuncDimension, Dimension);
  Util.Redirect(arguments, FuncDimensionPoint, Dimension, Point);
  Util.Redirect(arguments, FuncXYWidthHeight, 0, 0, 0, 0);
}

Func(new Point());
Func(new Dimension());
Func(new Dimension(), new Point());
Func(0, 0, 0, 0);


답변

가장 좋은 방법은 실제로 함수와 인수에 따라 다릅니다. 각 상황마다 다른 옵션을 사용하는 것이 좋습니다. 나는 일반적으로 다음 중 하나가 작동 할 때까지 다음 순서로 시도합니다.

  1. y = y ||와 같은 선택적 인수 사용 ‘기본’. 이것은 가능하다면 편리하지만, 실제로는 작동하지 않을 수도 있습니다. 예를 들어 0 / null / undefined가 유효한 인수 일 때.

  2. 다수의 인수 사용 마지막 옵션과 유사하지만 # 1이 작동하지 않을 때 작동 할 수 있습니다.

  3. 인수 유형 확인 이는 인수 수가 동일한 일부 경우에 작동 할 수 있습니다. 확실하게 유형을 결정할 수 없으면 다른 이름을 사용해야 할 수도 있습니다.

  4. 처음에는 다른 이름을 사용합니다. 다른 옵션이 작동하지 않거나 실용적이지 않거나 다른 관련 기능과의 일관성을 유지하려면이 작업을 수행해야합니다.