JavaScript'te singleton uygulamak için en basit / en temiz yolu?


300

JavaScript'te singleton desenini uygulamanın en basit / en temiz yolu nedir?


15
Kabul edilen cevabın tek başına olmaması için aşağı oy verin. Bu sadece küresel bir değişken.
mlibby

5
Bu bir ton bilgi, ancak farklı JS tasarım desenleri arasındaki farkları gerçekten ortaya koyuyor. Bana çok yardımcı oldu: addyosmani.com/resources/essentialjsdesignpatterns/book
Justin

Yanıtlar:


315

Bence en kolay yol basit bir nesne değişmezi bildirmektir:

var myInstance = {
  method1: function () {
    // ...
  },
  method2: function () {
    // ...
  }
};

Singleton örneğinizde özel üyeler istiyorsanız, şöyle bir şey yapabilirsiniz:

var myInstance = (function() {
  var privateVar = '';

  function privateMethod () {
    // ...
  }

  return { // public interface
    publicMethod1: function () {
      // all private members are accessible here
    },
    publicMethod2: function () {
    }
  };
})();

Bu modül deseni olarak adlandırılmıştır , temel olarak kapakların kullanımından yararlanarak özel üyeleri bir nesne üzerinde kapsüllemenizi sağlar .

GÜNCELLEME: Singleton nesnesinin değiştirilmesini önlemek istiyorsanız , ES5 yöntemini kullanarak bunu dondurabileceğinizi eklemek isterim Object.freeze.

Bu, nesneyi değiştirilemez hale getirecek, yapısında ve değerlerinde herhangi bir değişiklik yapılmasını önleyecektir.

Ek olarak, ES6 kullanıyorsanız, ES Modüllerini kullanarak bir singletonu kolayca temsil edebileceğinizi ve modül kapsamındaki değişkenleri bildirerek özel durumu bile tutabileceğinizi belirtmek isterim :

// my-singleton.js
const somePrivateState = []

function privateFn () {
  // ...
}

export default {
  method1() {
    // ...
  },
  method2() {
    // ...
  }
}

Ardından, tek nesneyi kullanmak için içe aktarabilirsiniz:

import myInstance from './my-singleton.js'
// ...

46
+1 Global değişkenlere sahip bir dilde "Singleton kalıbı" aramak biraz garip değil mi ???
Victor

4
Modül modelini kullanarak, bir genel üye başka bir genel üyeye nasıl erişebilir? Yani, nasıl publicMethod1arayabilirsin publicMethod2?
typeof

4
@Tom, evet, desen sınıf tabanlı OOP dillerinde doğdu -Statik bir getInstanceyöntem ve özel bir yapıcı içeren birçok uygulamayı hatırlıyorum- ancak IMO, bu tek bir nesne oluşturmak için en "basit" yoldur Javascript'te ve sonunda aynı amaca ulaşır - tek bir nesne, tekrar başlatamazsınız (yapıcı yok, sadece bir nesne) -. Bağlı kodu hakkında, bazı sorunları var takas ave bdeğişken bildirimlerini ve testi a === window. Şerefe.
CMS

15
@Victor - Bu dilde "singleton kalıbı" aramak garip değil. Birçok Nesne yönelimli dilde global değişkenler kullanılır ve hala tek tonlar kullanılmaktadır. Singleton sadece belirli bir sınıfın tek bir nesnesinin olacağını garanti etmez. Singleton'un birkaç özelliği daha vardır: 1) ilk kullanımda başlatılmalıdır (bu sadece gecikmeli başlatma anlamına gelmez, aynı zamanda nesnenin gerçekten kullanıma hazır olduğunu garanti eder) 2) iplik korumalı olmalıdır. Modül deseni tekli desen için değiştirilebilir, ancak yalnızca tarayıcıda (ve her zaman değil).
skalee

55
Bu kabul edilen cevap olmamalıdır. Bu hiç bir singleton değil! Bu sadece küresel bir değişkendir. İkisi arasında bir fark dünyası var.
mlibby

172

Bence en temiz yaklaşım şudur:

var SingletonFactory = (function(){
    function SingletonClass() {
        //do stuff
    }
    var instance;
    return {
        getInstance: function(){
            if (instance == null) {
                instance = new SingletonClass();
                // Hide the constructor so the returned object can't be new'd...
                instance.constructor = null;
            }
            return instance;
        }
   };
})();

Daha sonra, işlevi şu şekilde çağırabilirsiniz:

var test = SingletonFactory.getInstance();

4
Not: Orijinal kurucu aşağıdakileri kullanarak tekrar okunabilir delete instance.constructor:x = SingletonClass.getInstance();delete x.constructor;new x.constructor;
Rob W

var test = SingletonClass.getInstance () - çok temiz veya JS gibi görünmüyor. A = new Foo () ile sonuçlanan diğer ruhlar; b = yeni Foo (); a === b // doğru
Matthias

3
Bütün "getInstance" kısmı ile bana fabrika gibi kokuyor.
Lajos Meszaros

1
Bu bir singleton değildir çünkü Object.create ile birden çok örneği oluşturabilirsiniz.
AndroidDev

Fiddle bozuldu
HoffZ

103

Tek bir kalıbın yerine kullanılan modül kalıbına katıldığımdan emin değilim. Çoğunlukla gereksiz oldukları yerlerde kullanılan ve kötüye kullanılan singletonları sık sık gördüm ve modül deseninin programcıların aksi takdirde singleton kullanacağı birçok boşluğu doldurduğundan eminim, ancak modül deseni singleton değildir .

modül modeli:

var foo = (function () {
    "use strict";
    function aPrivateFunction() {}
    return { aPublicFunction: function () {...}, ... };
}());

Modül şablonunda başlatılan her şey Foobildirildiğinde gerçekleşir. Ek olarak modül modeli, daha sonra birçok kez başlatılabilen bir yapıcıyı başlatmak için kullanılabilir. Modül deseni birçok iş için doğru araç olsa da, tek bir tona eşdeğer değildir.

singleton desen:

kısa form
var Foo = function () {
    "use strict";
    if (Foo._instance) {
        //this allows the constructor to be called multiple times
        //and refer to the same instance. Another option is to
        //throw an error.
        return Foo._instance;
    }
    Foo._instance = this;
    //Foo initialization code
};
Foo.getInstance = function () {
    "use strict";
    return Foo._instance || new Foo();
}
uzun biçim, modül modeli kullanarak
var Foo = (function () {
    "use strict";
    var instance; //prevent modification of "instance" variable
    function Singleton() {
        if (instance) {
            return instance;
        }
        instance = this;
        //Singleton initialization code
    }
    //instance accessor
    Singleton.getInstance = function () {
        return instance || new Singleton();
    }
    return Singleton;
}());

Sağladığım Singleton deseninin her iki sürümünde de yapıcı kendisi erişimci olarak kullanılabilir:

var a,
    b;
a = new Foo(); //constructor initialization happens here
b = new Foo();
console.log(a === b); //true

Yapıcıyı bu şekilde kullanmakta kendinizi rahat hissetmiyorsanız, if (instance)ifadeye bir hata atabilir ve uzun formu kullanmaya devam edebilirsiniz:

var a,
    b;
a = Foo.getInstance(); //constructor initialization happens here
b = Foo.getInstance();
console.log(a === b); //true

Ayrıca singleton desen örtük yapıcı işlev desen iyi uyuyor belirtmek gerekir:

function Foo() {
    if (Foo._instance) {
        return Foo._instance;
    }
    //if the function wasn't called as a constructor,
    //call it as a constructor and return the result
    if (!(this instanceof Foo)) {
        return new Foo();
    }
    Foo._instance = this;
}
var f = new Foo(); //calls Foo as a constructor
-or-
var f = Foo(); //also calls Foo as a constructor

4
Tek başına kötü ya da iyi bir fikir olduğu hakkında hiçbir şey söylemedim. Singleton uygulamanızın olması gerekenden çok daha karmaşık olduğunu söyledim çünkü Java'nın sınırlamalarını kalıpla hiç anlamıyormuşsunuz gibi karıştırıyorsunuz. Javascript'te bunun için anonim işlevler kullanabildiğinizde yapıcı işlevlerini ve yöntemlerini yaparak strateji modelini uygulamak gibidir.
Esailija

11
@Esailija, bana singleton desenini anlamadığın gibi geliyor. Tekton kalıbı, bir sınıfın Örneklemesini bir nesneye kısıtlayan bir tasarım kalıbıdır. var singleton = {}bu tanıma uymuyor.
zzzzBov

9
Bu sadece sınırlamaları nedeniyle Java gibi diller için geçerlidir. var singleton = {}Javascript ile singleton uygulama şeklidir .
Esailija

2
@Esailija, "Sınıfların değil nesnelerin kullanıldığı prototip tabanlı bir programlama dilinde ..." JavaScript sınıf kavramına sahiptir, bu yüzden geçerli değildir.
zzzzBov


18

İçinde es6:

class Singleton {
  constructor () {
    if (!Singleton.instance) {
      Singleton.instance = this
    }
    // Initialize object
    return Singleton.instance
  }
  // Properties & Methods
}

const instance = new Singleton()
Object.freeze(instance)

export default instance

1
Donma, Singleton başka bir sınıfın etrafına sarıcı ve sadece instancealana sahip olsaydı mantıklı olurdu . Halen (olarak instanceayarlandığı gibi this) bu sınıfın başka alanları da olabilir ve donma mantıklı değildir.
thisismydesign

10

V6 düğümünde aşağıdaki işler

class Foo {
  constructor(msg) {

    if (Foo.singleton) {
      return Foo.singleton;
    }

    this.msg = msg;
    Foo.singleton = this;
    return Foo.singleton;
  }
}

Test ediyoruz:

const f = new Foo('blah');
const d = new Foo('nope');
console.log(f); // => Foo { msg: 'blah' }
console.log(d); // => Foo { msg: 'blah' }

8

ES6'da bunu yapmanın doğru yolu:

class MyClass {
  constructor() {
    if (MyClass._instance) {
      throw new Error("Singleton classes can't be instantiated more than once.")
    }
    MyClass._instance = this;

    // ... your rest of the constructor code goes after this
  }
}

var instanceOne = new MyClass() // Executes succesfully 
var instanceTwo = new MyClass() // Throws error

Veya, ikinci örnek oluşturmada bir hatanın atılmasını istemiyorsanız, yalnızca aşağıdaki örneği döndürebilirsiniz:

class MyClass {
  constructor() {
    if (MyClass._instance) {
      return MyClass._instance
    }
    MyClass._instance = this;

    // ... your rest of the constructor code goes after this
  }
}

var instanceOne = new MyClass()
var instanceTwo = new MyClass()

console.log(instanceOne === instanceTwo) // logs "true"


Merhaba ben örnek ve kod çalışma değildi gibi _instance ve örnek arasındaki farkı bilmek bana yardımcı olabilir
Abhinav bhardwaj

instanceVe arasında teknik bir fark yoktur _instance. Programlama dillerinde sadece alt çizgi ile eklenmiş özel değişkenleri adlandırdığımız bir adlandırma kuralıdır . Kodunuzun çalışmamasının sebebinin this.instancebunun yerine kullandığınızdan MyClass.instance
şüpheleniyorum

7

Bir kedinin derisini atmanın birden fazla yolu vardır :) Zevkinize veya özel ihtiyacınıza bağlı olarak önerilen çözümlerden herhangi birini uygulayabilirsiniz. Şahsen CMS'nin ilk çözümünü mümkün olduğunda (gizliliğe ihtiyacınız olmadığında) kullanıyorum. Soru en basit ve en temiz hakkında olduğundan, kazanan bu. Ya da:

var myInstance = {}; // done!

Bu (blogumdan alıntı) ...

var SingletonClass = new function() { 
    this.myFunction() { 
        //do stuff 
    } 
    this.instance = 1; 
}

çok mantıklı değil (blog örneğim de öyle değil) çünkü herhangi bir özel değişkene ihtiyaç duymaz, bu yüzden hemen hemen aynıdır:

var SingletonClass = { 
    myFunction: function () { 
        //do stuff 
    },
    instance: 1 
}

Kod pasajı 2 bir sözdizimi hatası içerir. Sen yazamazsınızthis.f(){}
xoxox

7

Cevabımı reddediyorum, diğerini görüyorum .

Genellikle tekli desen DEĞİL olan modül modeli (bkz. CMS cevabı) yeterince iyidir. Bununla birlikte, singleton'un özelliklerinden biri, nesneye ihtiyaç duyulana kadar başlatılmasının gecikmesidir. Modül deseninde bu özellik yoktur.

Benim önerim (CoffeeScript):

window.singleton = (initializer) ->
  instance = undefined
  () ->
    return instance unless instance is undefined
    instance = initializer()

JavaScript'te bunu derleyen:

window.singleton = function(initializer) {
    var instance;
    instance = void 0;
    return function() {
        if (instance !== void 0) {
            return instance;
        }
        return instance = initializer();
    };
};

Sonra aşağıdakileri yapabilirim:

window.iAmSingleton = singleton(function() {
    /* This function should create and initialize singleton. */
    alert("creating");
    return {property1: 'value1', property2: 'value2'};
});


alert(window.iAmSingleton().property2); // "creating" will pop up; then "value2" will pop up
alert(window.iAmSingleton().property2); // "value2" will pop up but "creating" will not
window.iAmSingleton().property2 = 'new value';
alert(window.iAmSingleton().property2); // "new value" will pop up

Gerekmiyorsa modülü neden yüklersiniz? Ve modülü yüklemeniz gerektiğinde, modülü yüklersiniz ve başlatılır.
Esailija

6

Kısa cevap:

JavaScript'in engellenmeyen doğası nedeniyle, JavaScript'teki Singletons gerçekten çirkin. Global değişkenler, tüm bu geri çağrılar olmadan da tüm uygulama boyunca size bir örnek verecektir, modül kalıbı arayüzün arkasındaki içleri nazikçe gizler. @CMS cevabına bakınız.

Ama, bir singleton istediğin için ...

var singleton = function(initializer) {

  var state = 'initial';
  var instance;
  var queue = [];

  var instanceReady = function(createdInstance) {
    state = 'ready';
    instance = createdInstance;
    while (callback = queue.shift()) {
      callback(instance);
    }
  };

  return function(callback) {
    if (state === 'initial') {
      state = 'waiting';
      queue.push(callback);
      initializer(instanceReady);
    } else if (state === 'waiting') {
      queue.push(callback);
    } else {
      callback(instance);
    }
  };

};

Kullanımı:

var singletonInitializer = function(instanceReady) {
  var preparedObject = {property: 'value'};
  // calling instanceReady notifies singleton that instance is ready to use
  instanceReady(preparedObject);
}
var s = singleton(singletonInitializer);

// get instance and use it
s(function(instance) {
  instance.doSomething();
});

Açıklama:

Teklitonlar tüm uygulama boyunca size birden fazla örnek verir: ilk kullanıma kadar başlatılmaları ertelenir. Başlangıcı pahalı olan nesnelerle uğraşırken bu gerçekten büyük bir şey. Pahalı genellikle G / Ç anlamına gelir ve JavaScript G / Ç her zaman geri arama anlamına gelir.

Size arayüz gibi cevaplar güvenmiyorum instance = singleton.getInstance(), hepsi noktası özledim.

Örnek hazır olduğunda çalıştırılmak üzere geri çağrı almazlarsa, başlatıcı G / Ç yaptığında çalışmazlar.

Evet, geri çağrılar her zaman nesne örneğini hemen döndüren işlev çağrısından daha çirkin görünür. Ama tekrar: I / O yaptığınızda geri aramalar zorunludur. Herhangi bir G / Ç yapmak istemiyorsanız, başlatma işlemi program başlangıcında yapacak kadar ucuzdur.

Örnek 1, ucuz başlatıcı:

var simpleInitializer = function(instanceReady) {
  console.log("Initializer started");
  instanceReady({property: "initial value"});
}

var simple = singleton(simpleInitializer);

console.log("Tests started. Singleton instance should not be initalized yet.");

simple(function(inst) {
  console.log("Access 1");
  console.log("Current property value: " + inst.property);
  console.log("Let's reassign this property");
  inst.property = "new value";
});
simple(function(inst) {
  console.log("Access 2");
  console.log("Current property value: " + inst.property);
});

Örnek 2, G / Ç ile başlatma:

Bu örnekte setTimeoutbazı pahalı G / Ç işlemleri yapılıyor. Bu, JavaScript'teki singletonların neden gerçekten geri arama gerektirdiğini gösterir.

var heavyInitializer = function(instanceReady) {
  console.log("Initializer started");
  var onTimeout = function() {
    console.log("Initializer did his heavy work");
    instanceReady({property: "initial value"});
  };
  setTimeout(onTimeout, 500);
};

var heavy = singleton(heavyInitializer);

console.log("In this example we will be trying");
console.log("to access singleton twice before it finishes initialization.");

heavy(function(inst) {
  console.log("Access 1");
  console.log("Current property value: " + inst.property);
  console.log("Let's reassign this property");
  inst.property = "new value";
});

heavy(function(inst) {
  console.log("Access 2. You can see callbacks order is preserved.");
  console.log("Current property value: " + inst.property);
});

console.log("We made it to the end of the file. Instance is not ready yet.");

Kesmeyen diğer singleton cevapları ile yapılan denemeler ve sıkıntılarla, sonuçta buna benzer şekilde benzer kodlara indim.
mheyman

Bir nedenden ötürü, bu benim için anlamlı olan tek cevap. Diğer cevaplar bana, üç erkeğin, birbirlerinin omuzlarına tekrar tekrar tırmanarak, dört kişinin bir duvara tırmanmaya çalıştığı goon şov bölümünü hatırlatıyor.
Tim Ogilvy

Calback istifleme gerçekten ihtiyacım olan şey! Teşekkürler!!
Tim Ogilvy

Bu yaklaşım size hiçbir zaman bir singleton vermez: singleton (singletonInitializer)! == singleton (singletonInitializer) iki farklı örnektir. Döndürdüğünüz sonuç işlevi, örneğe daha fazla geri arama eklemek için kullanılabilir, ancak bu türden yalnızca bir örneğin oluşturulabileceğini kesin olarak belirtmez. Bir singletonun bütün noktası budur.
Owen

6

Bu örneği JavaScript Kalıplarından aldım Kodlama ve Tasarım Kalıpları ile Daha İyi Uygulamalar Oluşturun Stoyan Stefanov'un kitabına göre, singltone nesnesi gibi basit bir uygulama sınıfına ihtiyacınız olması durumunda hemen aşağıdaki işlevi kullanabilirsiniz:

var ClassName;

(function() {
    var instance;
    ClassName = function ClassName() {
        //If private instance variable already initialized return reference
        if(instance) {
            return instance;   
        }
        //If instance does not created save pointer of original reference
        //to private instance variable. 
        instance = this;

        //All constructor initialization will be here
        // i.e.: 
        this.someProperty = 0;
        this.someMethod = function() {
            //Some action here
        };
    };
}());

Ve bu örneği aşağıdaki test durumunu kullanarak kontrol edebilirsiniz:

//Extending defined class like Singltone object using new prototype property
ClassName.prototype.nothing = true;
var obj_1 = new ClassName();
//Extending defined class like Singltone object using new prototype property
ClassName.prototype.everything = true; 
var obj_2 = new ClassName();

//Testing does this two object pointing to same instance
console.log(obj_1 === obj_2); //Result is true, it points to same instance object

//All prototype properites work
//no matter when they were defined
console.log(obj_1.nothing && obj_1.everything 
            && obj_2.nothing && obj_2.everything); //Result true


//Values of properties which is defined inside of constructor
console.log(obj_1.someProperty);// output 0
console.log(obj_2.someProperty);// output 0 
//Changing property value 
obj_1.someProperty = 1;

console.log(obj_1.someProperty);// output 1
console.log(obj_2.someProperty);// output 1

console.log(obj_1.constructor === ClassName); //Output true 

Prototip uzantısı kullanıldığında (sabit olabilir ancak basit olmayacak) özel statik uygulama başarısız olurken ve örnek nedeniyle halka daha az tavsiye edilen genel statik uygulama başarısız olurken, bu yaklaşımlar tüm test durumlarını geçer.

jsFiddly demo.


5

JavaScript'te programlamanın en temiz yolunu bulduğumu düşünüyorum, ancak biraz hayal gücüne ihtiyacınız olacak. Bu fikri "iyi parçaları javascript" kitabındaki bir çalışma tekniğinden aldım.

Yeni anahtar kelimeyi kullanmak yerine, aşağıdaki gibi bir sınıf oluşturabilirsiniz:

function Class()
{
    var obj = {}; // Could also be used for inheritence if you don't start with an empty object.

    var privateVar;
    obj.publicVar;

    obj.publicMethod= publicMethod;
    function publicMethod(){} 

    function privateMethod(){} 

    return obj;
}

Yukarıdaki nesneyi şunu söyleyerek başlatabilirsiniz:

var objInst = Class(); // !!! NO NEW KEYWORD

Şimdi bu çalışma yöntemini göz önünde bulundurarak şöyle bir tekton oluşturabilirsiniz:

ClassSingleton = function()
{
    var instance= null;

    function Class() // This is the class like the above one
    {
        var obj = {};
        return obj;
    }

    function getInstance()
    {
        if( !instance )
            instance = Class(); // Again no new keyword;

        return instance;
    }   

    return { getInstance : getInstance };

}();

Şimdi örneğinizi arayarak alabilirsiniz

var obj = ClassSingleton.getInstance();

Tam "Sınıf" bile erişilebilir değil çünkü bu en güzel yolu olduğunu düşünüyorum.


Ancak bu teknikle birden fazla örneğiniz olabilir. Bu doğru değil.
nicolascolman

1
Ben öyle düşünmezdim, getInstance geçmeden sınıfa bile erişemezsiniz. Açıklayabilir misiniz?
David

David Maes Maalesef ikinci örnekte doğrulamayı fark etmedim. Özür dilerim.
nicolascolman

4

@CMS ve @zzzzBov harika cevaplar verdiler, ancak sadece tekil kalıpların yaygın olduğu PHP / Zend Framework'ten ağır node.js geliştirmeye taşındığımı temel alarak kendi yorumumu eklemek için.

Aşağıdaki, dokümante edilmiş kod aşağıdaki gereksinimlere dayanmaktadır:

  • fonksiyon nesnesinin bir ve sadece bir örneği somutlaştırılabilir
  • örnek herkese açık değil ve yalnızca herkese açık bir yöntemle erişilebilir
  • kurucu herkese açık değildir ve yalnızca halihazırda kullanılabilir bir örnek yoksa somutlaştırılabilir
  • kurucunun beyanı, prototip zincirinin değiştirilmesine izin vermelidir. Bu, kurucunun diğer prototiplerden devralmasını ve örnek için "genel" yöntemler sunmasını sağlar.

Kodum, yapıcıya bir prototip zinciri ve PHP veya benzer bir dilden gelenlerin geleneksel OOP'yi Javascripts prototipik doğasına çevirmesine yardımcı olacak daha fazla yorum eklediğim için @ zzzzBov'unkine çok benziyor. "En basit" olmayabilir ama en uygun olduğuna inanıyorum.

// declare 'Singleton' as the returned value of a self-executing anonymous function
var Singleton = (function () {
    "use strict";
    // 'instance' and 'constructor' should not be availble in a "public" scope
    // here they are "private", thus available only within 
    // the scope of the self-executing anonymous function
    var _instance=null;
    var _constructor = function (name) {
        this.name = name || 'default';
    }

    // prototypes will be "public" methods available from the instance
    _constructor.prototype.getName = function () {
        return this.name;
    }

    // using the module pattern, return a static object
    // which essentially is a list of "public static" methods
    return {
        // because getInstance is defined within the same scope
        // it can access the "private" 'instance' and 'constructor' vars
        getInstance:function (name) {
            if (!_instance) {
                console.log('creating'); // this should only happen once
                _instance = new _constructor(name);
            }
            console.log('returning');
            return _instance;
        }
    }

})(); // self execute

// ensure 'instance' and 'constructor' are unavailable 
// outside the scope in which they were defined
// thus making them "private" and not "public"
console.log(typeof _instance); // undefined
console.log(typeof _constructor); // undefined

// assign instance to two different variables
var a = Singleton.getInstance('first');
var b = Singleton.getInstance('second'); // passing a name here does nothing because the single instance was already instantiated

// ensure 'a' and 'b' are truly equal
console.log(a === b); // true

console.log(a.getName()); // "first"
console.log(b.getName()); // also returns "first" because it's the same instance as 'a'

Teknik olarak, kendi kendini yürüten anonim işlevin, @CMS tarafından sağlanan kodda güzel bir şekilde gösterildiği gibi bir Singleton olduğunu unutmayın. Buradaki tek yakalama, kurucunun anonim olması durumunda kurucunun prototip zincirini değiştirmenin mümkün olmamasıdır.

Javascript için, “public” ve “private” kavramlarının PHP veya Java'da olduğu gibi geçerli olmadığını unutmayın. Ancak Javascript'in işlevsel kapsam kullanılabilirliği kurallarından yararlanarak aynı etkiyi elde ettik.


Kodunuzdan birden fazla örnek oluşturulabilir:var a = Singleton.getInstance('foo'); var b = new a.constructor('bar');
zzzzBov

@zzzzBov: Sadece Fiddle'ımda bunu denerken hatalar alıyorum: jsfiddle.net/rxMu8
cincodenada

4

Kimsenin bunu neden büyütmediğinden emin değilim, ancak şunları yapabilirsiniz:

var singleton = new (function() {
  var bar = 123

  this.foo = function() {
    // whatever
  }
})()

Bu getInstance yöntemini atlamak ve daha basit bir çözüm elde etmek için temiz bir yol gibi görünüyor. Ancak singleton'un dosya ayrıştırılır
ayrılmaz

4

En açık cevap Addy Osmani'nin JavaScript Tasarım Desenlerini Öğrenmek kitabından bu olmalıdır.

var mySingleton = (function () {
 
  // Instance stores a reference to the Singleton
  var instance;
 
  function init() {
 
    // Singleton
 
    // Private methods and variables
    function privateMethod(){
        console.log( "I am private" );
    }
 
    var privateVariable = "Im also private";
 
    var privateRandomNumber = Math.random();
 
    return {
 
      // Public methods and variables
      publicMethod: function () {
        console.log( "The public can see me!" );
      },
 
      publicProperty: "I am also public",
 
      getRandomNumber: function() {
        return privateRandomNumber;
      }
 
    };
 
  };
 
  return {
 
    // Get the Singleton instance if one exists
    // or create one if it doesn't
    getInstance: function () {
 
      if ( !instance ) {
        instance = init();
      }
 
      return instance;
    }
 
  };
 
})();


3

ES7 gerektirmesine rağmen bunun en basit / en temiz ve en sezgisel yol olduğuna inanıyorum:

export default class Singleton {

  static instance;

  constructor(){
    if(instance){
      return instance;
    }

    this.state = "duke";
    this.instance = this;
  }

}

Kaynak kodu: adam-bien.com


Bu tamamen yanlış ve arama hata verirnew Singleton()
UtkarshPramodGupta

2

Bunun nesi var?

function Klass() {
   var instance = this;
   Klass = function () { return instance; }
}

Test = Klass; t1 = new Test(); t2 = new Test();- sınıfı yeniden adlandırma veya farklı bir ad alanı seçme imkanı yok.
zzzzBov

2

5 paramı koyabilir miyim. Bir yapıcı işlevi var, ex.

var A = function(arg1){
  this.arg1 = arg1  
};

Yapmam gereken sadece bu CF tarafından oluşturulan her nesnenin aynı olacağı.

var X = function(){
  var instance = {};
  return function(){ return instance; }
}();

Ölçek

var x1 = new X();
var x2 = new X();
console.log(x1 === x2)

2

Kullanarak, çünkü en kolay Singleton deseni olmak için aşağıdaki buldum yeni operatörünü yapar bu bir nesne değişmezi dönmek için ihtiyacı ortadan kaldırarak, işlev içinde hemen kullanılabilir:

var singleton = new (function () {

  var private = "A private value";
  
  this.printSomething = function() {
      console.log(private);
  }
})();

singleton.printSomething();


2

Javascript tekil desen açıklamak için basit bir örnek.

 var Singleton=(function(){
      var instance;
      var init=function(){
           return {
             display:function(){
             alert("This is a Singleton patern demo");
              }
            };
           }; 
            return {
              getInstance:function(){
                   if(!instance){
                     alert("Singleton check");
                      instance=init();
                       }
               return instance;
             }
         };

    })();

   // In this call first display alert("Singleton check")
  // and then alert("This is a Singleton patern demo");
  // It means one object is created

    var inst=Singleton.getInstance();
    inst.display();

    // In this call only display alert("This is a Singleton patern demo")
   //  it means second time new object is not created, 
   //  it uses the already created object 

    var inst1=Singleton.getInstance();
    inst1.display();

1

Ben ile birkaç singleton gerekli:

  • tembel başlatma
  • başlangıç ​​parametreleri

ve işte ben de bunu buldum:

createSingleton ('a', 'add', [1, 2]);
console.log(a);

function createSingleton (name, construct, args) {
    window[name] = {};
    window[construct].apply(window[name], args);
    window[construct] = null;
}

function add (a, b) {
    this.a = a;
    this.b = b;
    this.sum = a + b;
}
  • Boş değişkenleriniz varsa, bunun çalışması için argümanlar Array olmalıdır. []

  • İşlevde pencere nesnesi kullandım, ancak kendi kapsamımı oluşturmak için bir parametrede geçebilirdim

  • name ve construct parametreleri yalnızca [] penceresinin çalışması için Dize'dir, ancak bazı basit tip denetimi ile window.name ve window.construct da mümkündür.


1

Bu şekilde, sadece sınıf tekrar yeni olamaz emin olun.

Bu sayede instanceofop'u kullanabilirsiniz , ayrıca sınıfı devralmak için prototip zincirini kullanabilirsiniz, bu normal bir sınıftır, ancak yeni bir şey olamaz, eğer örneği almak istiyorsanızgetInstance

function CA()
{
    if(CA.instance)
    {
        throw new Error('can not new this class');
    }else{
        CA.instance = this;
    }

}
/**
 * @protected
 * @static
 * @type {CA}
 */
CA.instance = null;
/** @static */
CA.getInstance = function()
{
    return CA.instance;
}

CA.prototype = 
/** @lends CA#*/
{
    func: function(){console.log('the func');}
}
// initilize the instance
new CA();

// test here
var c = CA.getInstance()
c.func();
console.assert(c instanceof CA)
// this will failed
var b = new CA();

Eğer instanceüyeyi ifşa etmek istemiyorsanız, üyeyi kapatmanız yeterlidir.


1

Aşağıda, tek bir desen uygulamak için yürüdüğüm pasaj var. Bu bir röportaj sürecinde bana geldi ve bunu bir yerde yakalamam gerektiğini hissettim.

/*************************************************
   *     SINGLETON PATTERN IMPLEMENTATION          *
   *************************************************/

  //since there are no classes in javascript, every object is technically a singleton
  //if you don't inherit from it or copy from it.
  var single = {};
  //Singleton Implementations
  //Declaring as a Global Object...you are being judged!


  var Logger = function() {
    //global_log is/will be defined in GLOBAL scope here
    if(typeof global_log === 'undefined'){
      global_log = this;
    }
    return global_log;
  };


  //the below 'fix' solves the GLOABL variable problem but
  //the log_instance is publicly available and thus can be 

  //tampered with.
  function Logger() {
    if(typeof Logger.log_instance === 'undefined'){
      Logger.log_instance = this;
    }


    return Logger.log_instance;
   };


  //the correct way to do it to give it a closure!


  function logFactory() {
    var log_instance; //private instance
    var _initLog = function() { //private init method
      log_instance = 'initialized';
      console.log("logger initialized!")
    }
    return {
      getLog : function(){ //the 'privileged' method 
        if(typeof log_instance === 'undefined'){
          _initLog();
        }
        return log_instance;
      }
    };
  }

  /***** TEST CODE ************************************************
  //using the Logger singleton
  var logger = logFactory();//did i just gave LogFactory a closure?
  //create an instance of the logger
  var a = logger.getLog();
  //do some work
  //get another instance of the logger
  var b = logger.getLog();


  //check if the two logger instances are same?
  console.log(a === b); //true
  *******************************************************************/

aynısını gist sayfamda da bulabilirsiniz


1
function Unicode()
  {
  var i = 0, unicode = {}, zero_padding = "0000", max = 9999;
  //Loop through code points
  while (i < max) {
    //Convert decimal to hex value, find the character, then pad zeroes to the codepoint
    unicode[String.fromCharCode(parseInt(i, 16))] = ("u" + zero_padding + i).substr(-4);
    i = i + 1;
    }

  //Replace this function with the resulting lookup table
  Unicode = unicode;
  }

//Usage
Unicode();
//Lookup
Unicode["%"]; //returns 0025

1

Bu da bir singleton değil mi?

function Singleton() {
    var i = 0;
    var self = this;

    this.doStuff = function () {
        i = i + 1;
        console.log( 'do stuff',i );
    };

    Singleton = function () { return self };
    return this;
}

s = Singleton();
s.doStuff();

1

TypeScript için aşağıdaki örnekte olduğu gibi dekoratörlerle yapabilirsiniz:

class YourClass {

    @Singleton static singleton() {}

}

function Singleton(target, name, descriptor) {
    var instance;
    descriptor.value = () => {
        if(!instance) instance = new target;
        return instance;
    };
}

Sonra singletonunuzu şöyle kullanın:

var myInstance = YourClass.singleton();

Bu yazı itibariyle, dekoratörler JavaScript motorlarında mevcut değildir. JavaScript çalışma zamanınızın dekoratörlerinin gerçekten etkinleştirildiğinden emin olmanız veya Babel ve TypeScript gibi derleyiciler kullanmanız gerekir.

Ayrıca singleton örneğinin "tembel" olarak oluşturulduğunu, yani yalnızca ilk kez kullandığınızda oluşturulduğunu unutmayın.


1

Modül düzeni: "daha okunabilir tarzda". Hangi yöntemlerin kamu ve hangilerinin özel olduğunu kolayca görebilirsiniz

var module = (function(_name){
   /*Local Methods & Values*/
   var _local = {
      name : _name,
      flags : {
        init : false
      }
   }

   function init(){
     _local.flags.init = true;
   }

   function imaprivatemethod(){
     alert("hi im a private method");
   }

   /*Public Methods & variables*/

   var $r = {}; //this object will hold all public methods.

   $r.methdo1 = function(){
       console.log("method1 call it");
   }

   $r.method2 = function(){
      imaprivatemethod(); //calling private method
   }

   $r.init = function(){
      inti(); //making init public in case you want to init manually and not automatically
   }

   init(); //automatically calling init method

   return $r; //returning all publics methods

})("module");

şimdi gibi halka açık yöntemleri kullanabilirsiniz

module.method2 (); // -> Genel yöntem uyarısı üzerinden özel bir yöntem arıyorum ("hi im a private method")

http://jsfiddle.net/ncubica/xMwS9/


1

Singleton:

Bir sınıfın yalnızca bir örneğinin bulunduğundan emin olun ve ona bir genel erişim noktası sağlayın.

Tek Ton Deseni, belirli bir nesnenin örnek sayısını yalnızca biriyle sınırlar. Bu tek örneğe singleton denir.

  • benzersiz örneği döndüren getInstance () yöntemini tanımlar.
  • örnek nesnesini oluşturmak ve yönetmekle sorumludur.

Singleton nesnesi, anonim bir işlev olarak uygulanır. İşlev hemen parantez içine alınır ve ardından iki ek parantez eklenir. Anonim olarak adlandırılır çünkü bir adı yoktur.

Örnek Program,

var Singleton = (function () {
    var instance;
 
    function createInstance() {
        var object = new Object("I am the instance");
        return object;
    }
 
    return {
        getInstance: function () {
            if (!instance) {
                instance = createInstance();
            }
            return instance;
        }
    };
})();
 
function run() {
 
    var instance1 = Singleton.getInstance();
    var instance2 = Singleton.getInstance();
 
    alert("Same instance? " + (instance1 === instance2));  
}

run()


1

Benim için En Basit / En Temiz, tartışmanın Java sürümünde çok tartışıldığı gibi sadece anlamak ve çan ve ıslık olmaması anlamına gelir:

Java'da tek tonlu bir desen uygulamanın etkili bir yolu nedir?

Benim açımdan orada en basit / en temiz en uygun cevap:

https://stackoverflow.com/a/70824/1497139

Ve sadece kısmen JavaScript'e çevrilebilir. Javascript'teki farklardan bazıları:

  • inşaatçılar özel olamaz
  • Sınıfların bildirilen alanları olamaz

Ancak en son ECMA sözdizimi verildiğinde aşağıdakilere yaklaşmak mümkündür:

JavaScript sınıfı örneği olarak singleton kalıbı

 class Singleton {

  constructor(field1,field2) {
    this.field1=field1;
    this.field2=field2;
    Singleton.instance=this;
  }

  static getInstance() {
    if (!Singleton.instance) {
      Singleton.instance=new Singleton('DefaultField1','DefaultField2');
    }
    return Singleton.instance;
  }
}

Örnek Kullanım

console.log(Singleton.getInstance().field1);
console.log(Singleton.getInstance().field2);

Örnek Sonuç

DefaultField1
DefaultField2

1
function Once() {
    return this.constructor.instance || (this.constructor.instance = this);
}

function Application(name) {
    let app = Once.call(this);

    app.name = name;

    return app;
}

Sınıflara giriyorsanız:

class Once {
    constructor() {
        return this.constructor.instance || (this.constructor.instance = this);
    }
}

class Application extends Once {
    constructor(name) {
        super();

        this.name = name;
    }
}

Ölçek:

console.log(new Once() === new Once());

let app1 = new Application('Foobar');
let app2 = new Application('Barfoo');

console.log(app1 === app2);
console.log(app1.name); // Barfoo

1

Sınıfları kullanmak istiyorsanız:

class Singleton {
  constructor(name, age) {
    this.name = name;
    this.age = age;
    if(this.constructor.instance)
      return this.constructor.instance;
    this.constructor.instance = this;
  }
}
let x = new Singleton('s',1);
let y = new Singleton('k',2);

Yukarıdakiler için çıktı:

console.log(x.name,x.age,y.name,y.age) // s 1 s 1

Singleton işlevini kullanarak yazmanın başka bir yolu

function AnotherSingleton (name,age) {
  this.name = name;
  this.age = age;
  if(this.constructor.instance)
    return this.constructor.instance;
  this.constructor.instance = this;
}

let a = new AnotherSingleton('s',1);
let b = new AnotherSingleton('k',2);

Yukarıdakiler için çıktı:

console.log(a.name,a.age,b.name,b.age)// s 1 s 1
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.