[JS 디자인 모드]: 단일 모드 (1)

19749 단어

단일 모드 소개


이른바 단례란 하나의 유형에 하나의 실례만 있는 것이다. 실현하는 방법은 일반적으로 실례가 존재하는지 여부를 먼저 판단하고 존재하면 바로 되돌아오고 존재하지 않으면 만들고 다시 되돌아오는 것이다.이렇게 하면 하나의 클래스가 하나의 실례 대상만 확보할 수 있다.
실현된 단례는 여러 가지 방식이 있는데 가장 간단한 방식은 대상의 글씨체를 재는 방법이다. 그 글씨체에는 대량의 속성과 방법이 포함될 수 있다.
var mySingleton = {
    property1: "something",
    property2: "something else",
    method1: function () {
        console.log('hello world');
    }
};

이 대상을 확장하려면 패키지를 닫는 방식으로 내부에 개인 속성과 방법을 만들려면 리턴이 노출하고 싶은 공유 속성과 방법을 노출시키면 됩니다. 코드는 다음과 같습니다.
var mySingleton = function () {
    /*   */
    var privateVariable = 'something private';
    function showPrivate() {
        console.log(privateVariable);
    }

    /*  ( ) */
    return {
        publicMethod: function () {
            showPrivate();
        },
        publicVar: 'the public can see this!'
    };
};

var single = mySingleton();
single.publicMethod();  //   'something private'
console.log(single.publicVar); //   'the public can see this!'

자원을 절약하기 위해서 어떻게 사용할 때 초기화합니까?이 코드는 다음과 같이 다른 구조 함수에서 초기화할 수 있습니다.
var Singleton = (function () {
    var instantiated;
    function init() {
        /* */
        return {
            publicMethod: function () {
                console.log('hello world');
            },
            publicProperty: 'test'
        };
    }

    return {
        getInstance: function () {
            if (!instantiated) {
                instantiated = init();
            }
            return instantiated;
        }
    };
})();

/* :*/
Singleton.getInstance().publicMethod();

단례가 어떻게 실현되었는지 알았지만, 단례는 어떤 장면에 쓰면 좋을까요?사실 하나의 예는 일반적으로 시스템 간의 각종 모델의 통신 조율에 사용되는데 아래의 코드는 하나의 예에 대한 가장 좋은 실천이다.
var SingletonTester = (function () {
    //
    function Singleton(args) {
        // args ( )
        var args = args || {};
        // name 
        this.name = 'SingletonTester';
        // pointX 
        this.pointX = args.pointX || 6; //
        // pointY 
        this.pointY = args.pointY || 10;

    }

    // 
    var instance;

    var _static = {
        name: 'SingletonTester',
        // 
        // Singleton 
        getInstance: function (args) {
            if (instance === undefined) {
                instance = new Singleton(args);
            }
            return instance;
        }
    };
    return _static;
})();

var singletonTest = SingletonTester.getInstance({ pointX: 5 });
console.log(singletonTest.pointX); //   5 

기타 실현 방식


방법1

function Universe() {
    //  
    if (typeof Universe.instance === 'object') {
        return Universe.instance;
    }

    //  
    this.start_time = 0;
    this.bang = "Big";

    //  
    Universe.instance = this;

    //  this
}

//  
var uni = new Universe();
var uni2 = new Universe();
console.log(uni === uni2); // true

방법2

function Universe() {
    //  
    var instance = this;

    //  
    this.start_time = 0;
    this.bang = "Big";

    //  
    Universe = function () {
        return instance;
    };
}

//  
var uni = new Universe();
var uni2 = new Universe();
uni.bang = "123";
console.log(uni === uni2); // true
console.log(uni2.bang); // 123

방법3

function Universe() {
    //  
    var instance;
    //  
    Universe = function Universe() {
        return instance;
    };
    //  
    Universe.prototype = this;
    //  
    instance = new Universe();
    //  
    instance.constructor = Universe;
    //  
    instance.start_time = 0;
    instance.bang = "Big";

    return instance;
}


//  
var uni = new Universe();
var uni2 = new Universe();
console.log(uni === uni2); // true

//  
Universe.prototype.nothing = true;

var uni = new Universe();

Universe.prototype.everything = true;

var uni2 = new Universe();

console.log(uni.nothing); // true
console.log(uni2.nothing); // true
console.log(uni.everything); // true
console.log(uni2.everything); // true
console.log(uni.constructor === Universe); // true

방식

var Universe;
(function () {
    var instance;
    Universe = function Universe() {
        if (instance) {
            return instance;
        }
        instance = this;
        //  
        this.start_time = 0;
        this.bang = "Big";
    };
} ());

// 
var a = new Universe();
var b = new Universe();
console.log(a === b); // true
a.bang = "123";
console.log(b.bang); // 123

인스턴스


예를 들어 이런 흔히 볼 수 있는 요구가 있는데 어떤 단추를 눌렀을 때 페이지에 커버층을 팝업해야 한다.
코드는 다음과 같습니다.
var createMask = function(){
   return document.body.appendChild(  document.createElement(div)  );
}
$( 'button' ).click( function(){
   Var mask  = createMask();
   mask.show();
})

문제는 이 마스크 층이 전역적으로 유일한 것이기 때문에createMask를 호출할 때마다 새div를 만들 수 있습니다. 마스크 층을 숨기고remove할 수 있지만.그러나 분명히 이렇게 하는 것은 불합리하다.
두 번째 방안을 보십시오. 페이지의 처음부터 이div를 만들고 변수로 인용하십시오.
var mask = document.body.appendChild( document.createElement( ''div' ) );

$( ''button' ).click( function(){
   mask.show();
} )

이렇게 하면 페이지에 하나의 커버층div만 만들 수 있지만 다른 문제가 뒤따른다. 아마도 우리는 이 커버층을 영원히 필요로 하지 않을 것이다. 그러면 또한div를 낭비하고dom 노드의 어떠한 조작도 매우 인색해야 한다.
변수 하나를 빌릴 수 있다면.div가 만들어졌는지 아닌지를 판단해 볼까요?
var mask;
var createMask = function(){
  if ( mask ) return mask;
  else{
    mask = document,body.appendChild(  document.createElement(div)  );
    return mask;
  }
}

보기에 괜찮은데, 여기에서 확실히 단열 대상을 만드는 함수를 완성했다.우리는 이 코드가 무엇이 타당하지 않은지 다시 자세히 보았다.
우선 이 함수는 일정한 부작용이 존재한다. 함수 체내에 외부 변수 mask의 인용이 바뀌었고 여러 사람이 협업하는 프로젝트에서createMask는 안전하지 않은 함수이다.다른 한편,mask라는 전역 변수는 필요하지 않으면 안 되는 것이 아니다.다시 한 번 개선해 봅시다.
var createMask = function(){
  var mask;
  return function(){
      return mask || ( mask = document.body.appendChild( document.createElement('div') ) )
  }
}()

앞의 그 단례는 여전히 결점이 있다.마스크 레이어를 생성하는 데만 사용할 수 있습니다.만약 내가 유일한 xhr 대상을 만드는 데 사용할 함수를 또 써야 한다면?통용되는singleton 포장기를 찾을 수 있습니까?
js에서 함수는 제1형으로 함수도 매개 변수로 전달할 수 있음을 의미한다.최종 코드를 보세요.
var singleton = function( fn ){
    var result;
    return function(){
        return result || ( result = fn .apply( this, arguments ) );
    }
}
 
var createMask = singleton( function(){
    return document.body.appendChild( document.createElement('div') );
 })

첫 번째 되돌림 값을 변수로 저장합니다. 만약 변수가 이미 부여되었다면, 다음 호출에서 이 변수를 우선적으로 되돌려줍니다.진정으로 커버층을 만드는 코드는 리셋 함수를 통해singleton 패키지에 전송됩니다.이런 방식을 사실 브리지 모드라고 부른다.
그러나singleton 함수도 완벽하지 않습니다.div의 인용을 저장하기 위해 변수result가 필요합니다.유감스럽게도 js의 함수식 특성은 성명과 문장을 완전히 제거하기에는 부족하다.

참고 자료

  • JavaScript 시리즈 깊이 이해(25): 디자인 모델의 단례 모델
  • [Javascript 디자인 모델 1] - 단일 모델
  • 좋은 웹페이지 즐겨찾기