JS 객체를 정의하는이 방법에는 어떤 목적이 있습니까?


87

일부 레거시 코드를 유지하고 있는데 객체를 정의하는 데 다음 패턴이 사용되는 것을 발견했습니다.

var MyObject = {};

(function (root) {

    root.myFunction = function (foo) {
        //do something
    };

})(MyObject);

이것에 어떤 목적이 있습니까? 다음을 수행하는 것과 동일합니까?

var MyObject = {

    myFunction : function (foo) {
        //do something
    };

};

나는 전체 코드베이스를 내 취향에 맞게 리팩토링하는 신성한 탐구에 착수하지 않지만 객체를 정의하는 로터리 방식의 이유를 정말로 이해하고 싶습니다.

감사!


1
귀하의 정확한 예에는 차이가 없습니다. 확장하면 차이가있을 수 있지만 다른 접근 방식도 적용됩니다.
Travis J

차이가 없습니다. 객체는 말하자면 참조의 복사본으로 전달되므로 IIFE 내부에서 myFunction을 정의 할 때도 외부에서 액세스 할 수 있습니다.
adeneo 2014

1
@adeneo이 예제에서는 그렇지 않습니다. by myFunction는 외부에서 액세스 할 수없는 자체 외부에서 정의 된 일부 변수를 사용할 수 있습니다. 내 대답을 참조하십시오
후안 멘데스

2
이 JavaScript 패턴무엇이며 왜 사용됩니까? (닫아야하는지 확실하지 않음). JavaScript 네임 스페이스 선언 또는 이것도 참조하십시오 .
Bergi 2014

답변:


116

모듈 패턴 http://toddmotto.com/mastering-the-module-pattern/ 이라고합니다.

주된 이유는 진정한 개인 메서드와 변수를 만드는 것입니다. 귀하의 경우에는 구현 세부 정보를 숨기지 않기 때문에 의미가 없습니다.

다음은 모듈 패턴을 사용하는 것이 합당한 예입니다.

var MyNameSpace = {};

(function(ns){
    // The value variable is hidden from the outside world
    var value = 0;

    // So is this function
    function adder(num) {
       return num + 1;
    }

    ns.getNext = function () {
       return value = adder(value);
    }
})(MyNameSpace);

var id = MyNameSpace.getNext(); // 1
var otherId = MyNameSpace.getNext(); // 2
var otherId = MyNameSpace.getNext(); // 3

당신은 그냥 직선 객체를 사용하는 경우 반면 addervalue공공 될 것

var MyNameSpace = {
    value: 0,
    adder: function(num) {
       return num + 1;
    },
    getNext: function() {
       return this.value = this.adder(this.value);
    }
}

그리고 당신은 다음과 같은 일을함으로써 그것을 부술 수 있습니다.

MyNameSpace.getNext(); // 1
MyNameSpace.value = 0;
MyNameSpace.getNext(); // 1 again
delete MyNameSpace.adder;
MyNameSpace.getNext(); // error undefined is not a function

하지만 모듈 버전으로

MyNameSpace.getNext(); // 1
 // Is not affecting the internal value, it's creating a new property
MyNameSpace.value = 0;
MyNameSpace.getNext(); // 2, yessss
// Is not deleting anything
delete MyNameSpace.adder;
MyNameSpace.getNext(); // no problemo, outputs 3

2
이것은 두 대안의 차이점이 무엇인지에 대한 질문에 실제로 대답하지 않습니다.

20
@torazaburo OP의 예제는 좋은 예제가 아니 었습니다. 모듈 패턴을 사용할 때를 보여주는 실제 예제를 제공했습니다.
Juan Mendes 2014

이것은 ns.getNext: function () {컴파일되지 않습니다.
punund 2011

내가 그것을 고치는 방법을 확신한다면 나는 그랬을 것입니다. 방지 할 구조가 있다고 생각했습니다 delete MyNameSpace.getNext.
punund 2014

2
@punund JS에는 인터프리터가있는 컴파일러가 없습니다.:)
frogatto

22

목적은 다른 스크립트 가 코드를 실행하는 것을 방지하기 위해 클로저 내에서 함수의 접근성 을 제한 하는 것입니다. 을 주위에 포장하여 폐쇄 하면 다시 정의하는 범위 내 모든 코드 실행을 폐쇄 하고 효과적으로 개인 범위를 생성. 자세한 내용은이 문서를 참조하십시오.

http://lupomontero.com/using-javascript-closures-to-create-private-scopes/

기사에서 :

JavaScript에서 가장 잘 알려진 문제 중 하나는 전역 범위에 대한 의존성입니다. 이는 기본적으로 함수 외부에서 선언하는 모든 변수가 동일한 이름 공간, 즉 불길한 창 개체에 있음을 의미합니다. 웹 페이지의 특성으로 인해 서로 다른 소스의 많은 스크립트가 공통 전역 범위를 공유하는 동일한 페이지에서 실행될 수 있고 실행될 수 있으며 이름 충돌 (동일한 이름의 변수 덮어 쓰기) 및 보안 문제. 문제를 최소화하기 위해 JavaScript의 강력한 클로저를 사용하여 변수가 페이지의 다른 스크립트에 보이지 않는지 확인할 수있는 개인 범위를 만들 수 있습니다.



암호:

var MyObject = {};

(function (root) {
    function myPrivateFunction() {
       return "I can only be called from within the closure";
    }

    root.myFunction = function (foo) {
        //do something
    };    

    myPrivateFunction(); // returns "I can only be called from within the closure"

})(MyObject);


myPrivateFunction(); // throws error - undefined is not a function

1
myFunction두 번째 버전의 전역 범위에 없습니다. 목적은 실제로 내부 보조 기능을 정의 할 수있는 범위를 제공하는 것입니다.
Barmar 2014

myFunction전역 개체 내에 정의되어 있기 때문에 전역 범위에 myObject있습니다. 두 번째 버전에서는 응용 프로그램의 다른 코드를 실행할 수 myFunction있습니다. 첫 번째 버전에서 폐쇄 내에서만 코드에 액세스 할 수 있습니다myFunction
조나단 크로우

아니요, 첫 번째 버전과 동일한 myFunction로만 실행할 수 있습니다 MyObject.myFunction().
Barmar 2011

@JonathanCrowe OP의 예는 좋은 예가 아니며 모듈 내부의 모든 것을 노출하므로 외부에서 액세스 할 수 있습니다. 유용한 모듈 케이스에 대한 내 대답을 참조하십시오
후안 멘데스

@JuanMendes 좋은 점, 영업 이익의 예는 모듈 패턴의 잘 사용하지 않습니다
조나단 크로우

6

장점 :

  1. 개인 범위에서 변수를 유지합니다.

  2. 기존 개체의 기능을 확장 할 수 있습니다.

  3. 성능이 향상됩니다.

위의 세 가지 간단한 요점은 그 규칙을 따르기에 충분하다고 생각합니다. 그리고 그것을 단순하게 유지하려면 내부 함수를 작성하는 것뿐입니다.


6

당신이 보여주는 특별한 경우에는 기능이나 가시성 측면에서 의미있는 차이가 없습니다.

원래 코더는이 접근 방식을 일종의 템플릿으로 채택하여 다음과 같은 정의에 사용할 수있는 개인 변수를 정의 할 수 있습니다 myFunction.

var MyObject = {};
(function(root) {
    var seconds_per_day = 24 * 60 * 60;   // <-- private variable
    root.myFunction = function(foo) {
        return seconds_per_day;
    };
})(MyObject);

이렇게하면 seconds_per_day함수가 호출 될 때마다 계산을 피하고 전역 범위를 오염시키지 않습니다.

그러나 본질적으로 그와 다른 것은 없습니다.

var MyObject = function() {
    var seconds_per_day = 24 * 60 * 60;
    return {
        myFunction: function(foo) {
            return seconds_per_day;
        }
    };
}();

원래 코더는 root.myFunction = function의 개체 / 속성 구문 대신 의 선언적 구문을 사용하여 개체에 함수를 추가 할 수있는 것을 선호했을 수 있습니다 myFunction: function. 그러나 그 차이는 주로 선호도의 문제입니다.

그러나 원래 코더가 취한 구조는 속성 / 메소드를 코드의 다른 곳에 쉽게 추가 할 수 있다는 이점이 있습니다.

var MyObject = {};
(function(root) {
    var seconds_per_day = 24 * 60 * 60;
    root.myFunction = function(foo) {
        return seconds_per_day;
    };
})(MyObject);

(function(root) {
    var another_private_variable = Math.pi;
    root.myFunction2 = function(bar) { };
})(MyObject);

요컨대, 필요하지 않은 경우이 접근 방식을 채택 할 필요가 없지만 완벽하게 잘 작동하고 실제로 몇 가지 장점이 있기 때문에 변경할 필요도 없습니다.


6
  1. 첫 번째 패턴은 개체를 가져와 일부 수정을 통해 해당 개체를 반환하는 모듈로 사용할 수 있습니다. 즉, 이러한 모듈을 다음과 같이 정의 할 수 있습니다.

    var module = function (root) {
        root.myFunction = function (foo) {
            //do something
        };
    }
    

    그리고 다음과 같이 사용하십시오.

    var obj = {};
    module(obj);
    

    따라서 나중에 사용하기 위해이 모듈을 재사용 할 수 있다는 장점이 있습니다.


  1. 첫 번째 패턴에서는 개인 속성 및 메서드와 같은 개인 정보를 저장할 개인 범위 를 정의 할 수 있습니다 . 예를 들어 다음 스 니펫을 고려하십시오.

    (function (root) {
    
        // A private property
        var factor = 3;
    
        root.multiply = function (foo) {
            return foo * factor;
        };
    })(MyObject);
    

  1. 이 패턴은 배열, 개체 리터럴, 함수와 같은 모든 유형의 개체에 메서드 또는 속성을 추가하는 데 사용할 수 있습니다.

    function sum(a, b) {
        return a + b;
    }
    
    (function (root) {
        // A private property
        var factor = 3;
        root.multiply = function (foo) {
            return foo * factor;
        };
    })(sum);
    
    console.log(sum(1, 2)); // 3
    console.log(sum.multiply(4)); // 12
    

내 생각에 주요 이점은 두 번째 (개인 범위 생성) 일 수 있습니다.


5

이 패턴은 전역 범위에 표시되지 않는 도우미 함수를 정의 할 수있는 범위를 제공합니다.

(function (root) {

    function doFoo() { ... };

    root.myFunction = function (foo) {
        //do something
        doFoo();
        //do something else
    };

})(MyObject);

doFoo 익명 함수에 로컬이므로 외부에서 참조 할 수 없습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.