Cara termudah / terbersih untuk menerapkan singleton dalam JavaScript?

300

Apa cara paling sederhana / paling bersih untuk menerapkan pola singleton dalam JavaScript?

Jakub Arnold
sumber
15
Turunkan suara untuk jawaban yang diterima bukan sama sekali. Itu hanya variabel global.
mlibby
5
Ini adalah satu ton informasi, tetapi benar-benar menjabarkan perbedaan di antara pola desain JS yang berbeda. Itu banyak membantu saya: addyosmani.com/resources/essentialjsdesignpatterns/book
Justin

Jawaban:

315

Saya pikir cara termudah adalah dengan mendeklarasikan objek literal sederhana:

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

Jika Anda ingin anggota pribadi menggunakan instance tunggal Anda, Anda dapat melakukan sesuatu seperti ini:

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

  function privateMethod () {
    // ...
  }

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

Ini telah disebut dengan pola modul , pada dasarnya memungkinkan Anda untuk merangkum anggota pribadi pada objek, dengan mengambil keuntungan dari penggunaan penutupan .

UPDATE: Saya ingin menambahkan bahwa jika Anda ingin mencegah modifikasi objek singleton, Anda dapat membekukannya , menggunakan Object.freezemetode ES5 .

Itu akan membuat objek tidak berubah, mencegah modifikasi pada struktur dan nilainya.

Selain itu saya ingin menyebutkan bahwa jika Anda menggunakan ES6, Anda dapat mewakili singleton menggunakan Modul ES dengan sangat mudah, dan Anda bahkan dapat memegang status privat dengan mendeklarasikan variabel pada cakupan modul :

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

function privateFn () {
  // ...
}

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

Kemudian Anda bisa mengimpor objek singleton untuk menggunakannya:

import myInstance from './my-singleton.js'
// ...
CMS
sumber
46
+1 Bukankah agak aneh mencari "pola Singleton" dalam bahasa dengan variabel global ???
Victor
4
Dengan menggunakan pola modul, bagaimana anggota publik mengakses anggota publik lainnya? Yaitu, bagaimana publicMethod1menelepon publicMethod2?
typeof
4
@ Tom, yeah, pola ini lahir dari bahasa OOP berbasis kelas -Aku ingat banyak implementasi yang melibatkan getInstancemetode statis , dan konstruktor pribadi-, tapi IMO, ini adalah cara paling "sederhana" untuk membangun objek singleton dalam Javascript, dan pada akhirnya memenuhi tujuan yang sama-objek tunggal, yang Anda tidak dapat menginisialisasi lagi (tidak ada konstruktor, itu hanya sebuah objek) -. Tentang kode yang Anda tautkan, ada beberapa masalah, tukar adan bdeklarasi variabel dan pengujian a === window. Bersulang.
CMS
15
@ Viktor - Ini tidak aneh untuk mencari "pola tunggal" dalam bahasa tersebut. banyak bahasa berorientasi objek menggunakan variabel global dan masih lajang yang digunakan. Singleton tidak hanya menjamin bahwa hanya akan ada satu objek dari kelas yang diberikan. Singleton memiliki beberapa fitur lagi: 1) harus diinisialisasi pada penggunaan pertama (yang tidak hanya berarti inisialisasi tertunda, tetapi juga menjamin bahwa objek benar-benar siap untuk digunakan) 2) itu harus thread-safe. Pola modul dapat menjadi pengganti untuk pola tunggal tetapi hanya di browser (dan tidak selalu).
skalee
55
Ini seharusnya bukan jawaban yang diterima. Ini bukan singleton sama sekali! Ini hanya variabel global. Ada dunia perbedaan di antara keduanya.
mlibby
172

Saya pikir pendekatan terbersih adalah sesuatu seperti:

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;
        }
   };
})();

Setelah itu, Anda dapat memanggil fungsi sebagai

var test = SingletonFactory.getInstance();
sebarmeli
sumber
4
Catatan: Konstruktor asli dapat dibaca lagi menggunakan delete instance.constructor:x = SingletonClass.getInstance();delete x.constructor;new x.constructor;
Rob W
var test = SingletonClass.getInstance () - tidak terlihat sangat bersih atau seperti JS. Soulions lain yang berakhir dengan = new Foo (); b = Foo baru (); a === b // true
Matthias
3
Baunya seperti pabrik bagiku dengan seluruh bagian "getInstance".
Lajos Meszaros
1
Ini bukan singleton karena Anda dapat membuat beberapa instance dengan Object.create.
AndroidDev
Fiddle rusak
HoffZ
103

Saya tidak yakin saya setuju dengan pola modul yang digunakan sebagai pengganti pola tunggal. Saya sering melihat lajang digunakan dan dilecehkan di tempat-tempat di mana mereka sama sekali tidak perlu, dan saya yakin pola modul mengisi banyak celah di mana programmer akan menggunakan singleton, namun pola modul bukan singleton.

pola modul:

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

Segala sesuatu yang diinisialisasi dalam pola modul terjadi ketika Foodideklarasikan. Selain itu, pola modul dapat digunakan untuk menginisialisasi konstruktor, yang kemudian dapat dipakai beberapa kali. Sementara pola modul adalah alat yang tepat untuk banyak pekerjaan, itu tidak setara dengan singleton.

pola singleton:

bentuk pendek
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();
}
bentuk panjang, menggunakan pola modul
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;
}());

Di kedua versi pola Singleton yang saya berikan, konstruktor itu sendiri dapat digunakan sebagai accessor:

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

Jika Anda merasa tidak nyaman menggunakan konstruktor seperti ini, Anda bisa melempar kesalahan dalam if (instance)pernyataan, dan tetap menggunakan form panjang:

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

Saya juga harus menyebutkan bahwa pola singleton cocok dengan pola fungsi konstruktor implisit:

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
zzzzBov
sumber
4
Saya tidak pernah mengatakan apa pun tentang lajang sebagai ide yang buruk atau baik. Saya mengatakan bahwa implementasi singleton Anda jauh lebih rumit daripada yang seharusnya karena Anda mengacaukan keterbatasan Java dengan pola seolah-olah Anda tidak memahaminya sama sekali. Ini seperti menerapkan pola strategi dengan membuat fungsi dan metode konstruktor ketika Anda cukup menggunakan fungsi anonim untuk itu dalam Javascript.
Esailija
11
@ Eailija, bagi saya sepertinya Anda tidak mengerti pola singleton. Pola singleton adalah pola desain yang membatasi Instansiasi kelas ke satu objek. var singleton = {}tidak sesuai dengan definisi itu.
zzzzBov
9
Itu hanya berlaku untuk bahasa seperti Jawa karena keterbatasannya. var singleton = {}adalah bagaimana Anda menerapkan singleton dalam Javascript .
Esailija
2
@Esailija, "Dalam bahasa pemrograman berbasis prototipe, di mana objek tetapi bukan kelas digunakan ..." JavaScript memiliki konsep kelas, sehingga tidak berlaku.
zzzzBov
18

Dalam 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
Xaqron
sumber
1
Membekukan akan masuk akal jika Singleton akan menjadi pembungkus kelas lain dan hanya memiliki instancebidang. Seperti saat ini ( instancediatur ke this) kelas ini mungkin memiliki bidang lain juga dan pembekuan tidak masuk akal.
desain ini
10

Berikut ini berfungsi di simpul v6

class Foo {
  constructor(msg) {

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

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

Kami menguji:

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

Dalam ES6 cara yang tepat untuk melakukan ini adalah:

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

Atau, jika Anda tidak ingin kesalahan dilemparkan pada pembuatan instance kedua, Anda bisa mengembalikan instance terakhir, seperti:

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"

UtkarshPramodGupta
sumber
Hai, bisakah Anda membantu saya untuk mengetahui perbedaan antara _instance dan instance karena saya menggunakan instance dan kode tidak berfungsi
Abhinav bhardwaj
Tidak ada perbedaan teknis dalam instancedan _instance. Itu hanya konvensi penamaan dalam bahasa pemrograman yang kami beri nama variabel pribadi yang diawali dengan garis bawah. Saya menduga alasan kode Anda untuk tidak berfungsi adalah karena Anda menggunakan this.instancealih-alihMyClass.instance
UtkarshPramodGupta
7

Ada lebih dari satu cara untuk menguliti kucing :) Tergantung pada selera atau kebutuhan spesifik Anda, Anda dapat menerapkan salah satu solusi yang diusulkan. Saya pribadi mencari solusi pertama CMS bila memungkinkan (ketika Anda tidak membutuhkan privasi). Karena pertanyaannya adalah yang paling sederhana dan paling bersih, itulah pemenangnya. Atau bahkan:

var myInstance = {}; // done!

Ini (kutipan dari blog saya) ...

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

tidak masuk akal (contoh blog saya juga tidak) karena tidak memerlukan vars pribadi, jadi hampir sama dengan:

var SingletonClass = { 
    myFunction: function () { 
        //do stuff 
    },
    instance: 1 
}
Stoyan
sumber
Cuplikan kode 2 berisi kesalahan sintaksis. Anda tidak dapat menulisthis.f(){}
xoxox
7

Saya mencela jawaban saya, melihat jawaban saya yang lain .

Biasanya pola modul (lihat jawaban CMS) yang BUKAN pola tunggal cukup baik. Namun salah satu fitur singleton adalah inisialisasi tertunda hingga objek diperlukan. Pola modul tidak memiliki fitur ini.

Proposisi saya (CoffeeScript):

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

Yang dikompilasi dalam JavaScript ini:

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

Maka saya bisa melakukan hal berikut:

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
skalee
sumber
Mengapa Anda memuat modul jika tidak diperlukan? Dan ketika Anda perlu memuat modul, maka Anda memuat modul, dan menginisialisasi.
Esailija
6

Jawaban singkat:

Karena sifat non-pemblokiran JavaScript, Singletons dalam JavaScript benar-benar jelek digunakan. Variabel global akan memberi Anda satu contoh melalui seluruh aplikasi juga tanpa semua panggilan balik ini, pola modul dengan lembut menyembunyikan internal di belakang antarmuka. Lihat jawaban @CMS.

Tapi, karena Anda menginginkan seorang singleton ...

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);
    }
  };

};

Pemakaian:

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();
});

Penjelasan:

Lajang memberi Anda lebih dari satu contoh melalui seluruh aplikasi: inisialisasi mereka tertunda hingga penggunaan pertama. Ini adalah hal yang sangat besar ketika Anda berurusan dengan objek yang inisialisasi mahal. Mahal biasanya berarti I / O dan dalam JavaScript I / O selalu berarti panggilan balik.

Jangan percayai jawaban yang memberi Anda antarmuka instance = singleton.getInstance(), mereka semua kehilangan intinya.

Jika mereka tidak menerima panggilan balik untuk dijalankan ketika instance sudah siap, maka mereka tidak akan berfungsi ketika initializer melakukan I / O.

Ya, panggilan balik selalu terlihat lebih buruk daripada panggilan fungsi yang segera mengembalikan contoh objek. Tetapi sekali lagi: ketika Anda melakukan I / O, callback wajib. Jika Anda tidak ingin melakukan I / O, maka instantiation cukup murah untuk melakukannya pada awal program.

Contoh 1, penginisialisasi murah:

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);
});

Contoh 2, inisialisasi dengan I / O:

Dalam contoh ini setTimeoutmemalsukan beberapa operasi I / O yang mahal. Ini menggambarkan mengapa lajang di JavaScript benar-benar membutuhkan panggilan balik.

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.");
skalee
sumber
Melalui cobaan dan kesengsaraan dengan jawaban tunggal lainnya yang tidak memotongnya, saya mendapatkan kode yang dihasilkan sangat mirip dengan ini.
mheyman
Karena satu dan lain alasan, ini adalah satu-satunya jawaban yang masuk akal bagi saya. Jawaban yang lain semua mengingatkan saya pada episode goon show di mana tiga orang mencoba memanjat tembok setinggi empat orang, dengan memanjat satu sama lain secara rekursif.
Tim Ogilvy
Penumpukan calback adalah hal yang sangat saya butuhkan! Terima kasih!!
Tim Ogilvy
Pendekatan ini tidak pernah benar-benar memberi Anda singleton sebagai: singleton (singletonInitializer)! == singleton (singletonInitializer) mereka adalah dua contoh yang berbeda. Fungsi yang Anda kembalikan dapat digunakan untuk melampirkan lebih banyak panggilan balik ke instance, tetapi tidak secara tegas menentukan bahwa hanya satu instance dari tipe ini yang dapat dibuat. Yang merupakan inti dari singleton.
Owen
6

Saya mendapatkan contoh ini dari Pola JavaScript Membangun Aplikasi yang Lebih Baik dengan Pola Pengodean dan Desain Oleh Stoyan Stefanov buku jika Anda memerlukan beberapa kelas implementasi sederhana seperti objek singltone Anda dapat menggunakan fungsi langsung sebagai berikut:

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
        };
    };
}());

Dan Anda dapat memeriksa contoh ini dengan mengikuti test case:

//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 

Pendekatan ini melewati semua kasus uji sementara implementasi statis pribadi akan gagal ketika ekstensi prototipe digunakan (bisa diperbaiki tetapi tidak akan sederhana) dan implementasi statis publik kurang disarankan karena misalnya terpapar ke publik.

Demo jsFiddly.

Khamidulla
sumber
5

Saya pikir saya telah menemukan cara paling bersih untuk memprogram dalam JavaScript, tetapi Anda akan memerlukan imajinasi. Saya mendapat ide ini dari teknik kerja di buku "javascript bagian yang baik".

Alih-alih menggunakan kata kunci baru, Anda dapat membuat kelas seperti ini:

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;
}

Anda dapat instantiate objek di atas dengan mengatakan:

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

Sekarang dengan metode kerja ini dalam pikiran Anda dapat membuat singleton seperti ini:

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 };

}();

Sekarang Anda bisa mendapatkan contoh Anda dengan menelepon

var obj = ClassSingleton.getInstance();

Saya pikir ini adalah cara yang paling rapi karena "Kelas" yang lengkap bahkan tidak dapat diakses.

David
sumber
Tetapi dengan teknik ini Anda bisa memiliki lebih dari satu contoh. Itu tidak benar.
nicolascolman
1
Saya tidak akan berpikir begitu, Anda bahkan tidak dapat mengakses kelas tanpa melalui getInstance. Bisakah Anda menguraikan?
David
David Maes Maaf tapi saya tidak melihat validasi dalam contoh kedua. Saya minta maaf.
nicolascolman
4

@CMS dan @zzzzBov sama-sama memberikan jawaban yang bagus, tetapi hanya untuk menambahkan interpretasi saya sendiri berdasarkan saya telah pindah ke pengembangan node.js yang berat dari PHP / Zend Framework di mana pola singleton adalah umum.

Kode yang didokumentasikan komentar berikut ini didasarkan pada persyaratan berikut:

  • satu dan hanya satu instance dari objek fungsi yang dapat dipakai
  • instance tidak tersedia untuk umum dan hanya dapat diakses melalui metode publik
  • konstruktor tidak tersedia untuk umum dan hanya dapat dipakai jika ada belum ada contoh tersedia
  • deklarasi konstruktor harus memungkinkan rantai prototipe untuk dimodifikasi. Ini akan memungkinkan konstruktor untuk mewarisi dari prototipe lain, dan menawarkan metode "publik" sebagai contoh

Kode saya sangat mirip dengan @ zzzzBov, kecuali saya sudah menambahkan rantai prototipe ke konstruktor dan lebih banyak komentar yang akan membantu mereka yang berasal dari PHP atau bahasa serupa menerjemahkan OOP tradisional ke sifat prototipe Javascripts. Mungkin bukan yang "paling sederhana" tapi saya percaya itu yang paling tepat.

// 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'

Perhatikan bahwa secara teknis, fungsi anonim yang dijalankan sendiri itu sendiri adalah Singleton sebagaimana ditunjukkan dengan baik dalam kode yang disediakan oleh @CMS. Satu-satunya tangkapan di sini adalah bahwa tidak mungkin untuk mengubah rantai prototipe konstruktor ketika konstruktor itu sendiri anonim.

Perlu diingat bahwa untuk Javascript, konsep "publik" dan "pribadi" tidak berlaku seperti di PHP atau Java. Tapi kami telah mencapai efek yang sama dengan memanfaatkan aturan Javascript tentang ketersediaan ruang lingkup fungsional.

robot berbakat
sumber
Beberapa instance dapat dibuat dari kode Anda:var a = Singleton.getInstance('foo'); var b = new a.constructor('bar');
zzzzBov
@zzzzBov: Saya hanya mendapatkan kesalahan saat mencoba itu di Fiddle: jsfiddle.net/rxMu8
cincodenada
4

Tidak yakin mengapa tidak ada yang mengemukakan ini, tetapi Anda bisa melakukannya:

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

  this.foo = function() {
    // whatever
  }
})()
Derek Chiang
sumber
Ini tampaknya menjadi cara yang rapi untuk melewati metode getInstance dan mendapatkan solusi yang lebih sederhana. Tetapi perlu diingat bahwa singleton akan mengeksekusi segera setelah file diuraikan, artinya pendengar DOM harus dibungkus dengan $ (dokumen).
Sudah
4

Jawaban paling jelas harus yang ini dari buku Belajar Pola Desain JavaScript oleh Addy Osmani.

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;
    }
 
  };
 
})();

令狐 葱
sumber
3

Saya percaya ini adalah cara paling sederhana / paling bersih dan paling intuitif meskipun membutuhkan ES7:

export default class Singleton {

  static instance;

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

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

}

Kode sumbernya dari: adam-bien.com

Alt Eisen
sumber
Ini sepenuhnya salah dan akan membuat kesalahan saat memanggilnew Singleton()
UtkarshPramodGupta
2

Ada apa dengan ini?

function Klass() {
   var instance = this;
   Klass = function () { return instance; }
}
Manav
sumber
Test = Klass; t1 = new Test(); t2 = new Test();- tidak ada kesempatan untuk mengubah nama kelas atau memilih namespace yang berbeda.
zzzzBov
2

dapatkah saya menaruh 5 koin saya. Saya memiliki fungsi konstruktor, mis.

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

Yang perlu saya lakukan hanyalah setiap objek yang dibuat oleh CF ini akan sama.

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

uji

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

Saya telah menemukan yang berikut ini sebagai pola Singleton termudah, karena menggunakan operator baru membuat ini segera tersedia dalam fungsi, menghilangkan kebutuhan untuk mengembalikan objek literal:

var singleton = new (function () {

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

singleton.printSomething();

Menandai
sumber
2

Berikut adalah contoh sederhana untuk menjelaskan pola tunggal dalam javascript.

 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();
Sheo Dayal Singh
sumber
1

Saya membutuhkan beberapa lajang dengan:

  • inisialisasi malas
  • parameter awal

dan inilah yang saya pikirkan:

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;
}
  • args harus Array agar ini berfungsi sehingga jika Anda memiliki variabel kosong, cukup masukkan []

  • Saya menggunakan objek jendela dalam fungsi tetapi saya bisa melewati parameter untuk membuat ruang lingkup saya sendiri

  • parameter nama dan konstruk hanya String agar window [] berfungsi tetapi dengan beberapa pengecekan tipe sederhana, window.name dan window.construct juga dimungkinkan.

fred
sumber
1

Bagaimana dengan cara ini, hanya memastikan kelas tidak bisa baru lagi.

Dengan ini, Anda dapat menggunakan instanceofop, juga, Anda dapat menggunakan rantai prototipe untuk mewarisi kelas, ini adalah kelas reguler, tetapi tidak bisa baru itu, jika Anda ingin mendapatkan contoh cukup gunakangetInstance

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();

Jika Anda tidak ingin mengekspos instanceanggota tersebut, tutup saja.

Wener
sumber
1

Berikut ini adalah cuplikan dari jalan saya untuk menerapkan pola tunggal. Ini terjadi pada saya selama proses wawancara dan saya merasa bahwa saya harus menangkap ini di suatu tempat.

/*************************************************
   *     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
  *******************************************************************/

hal yang sama dapat ditemukan di halaman intisari saya

curioussam
sumber
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
Paul Sweatte
sumber
1

Bukankah ini juga singleton?

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();
Nawal
sumber
1

Anda dapat melakukannya dengan dekorator seperti dalam contoh di bawah ini untuk TypeScript:

class YourClass {

    @Singleton static singleton() {}

}

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

Maka Anda menggunakan singleton Anda seperti ini:

var myInstance = YourClass.singleton();

Pada tulisan ini, dekorator tidak tersedia di mesin JavaScript. Anda perlu memastikan runtime JavaScript Anda memiliki dekorator yang benar-benar diaktifkan atau menggunakan kompiler seperti Babel dan TypeScript.

Juga perhatikan bahwa instance singleton dibuat "malas", yaitu, dibuat hanya ketika Anda menggunakannya untuk pertama kali.

Vad
sumber
1

Pola modul: dalam "gaya yang lebih mudah dibaca". Anda dapat dengan mudah melihat metode mana yang publik dan mana yang privat

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");

sekarang Anda dapat menggunakan metode publik seperti

module.method2 (); // -> Saya memanggil metode pribadi melalui peringatan metode publik ("Hai, metode pribadi")

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

ncubica
sumber
1

Singleton:

Pastikan kelas hanya memiliki satu instance dan memberikan titik akses global untuk itu.

Pola Singleton membatasi jumlah instance objek tertentu menjadi hanya satu. Contoh tunggal ini disebut singleton.

  • mendefinisikan getInstance () yang mengembalikan instance unik.
  • bertanggung jawab untuk membuat dan mengelola objek instan.

Objek Singleton diimplementasikan sebagai fungsi anonim langsung. Fungsi dijalankan segera dengan membungkusnya dalam tanda kurung diikuti oleh dua tanda kurung tambahan. Itu disebut anonim karena tidak memiliki nama.

Program Sampel,

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()

Mohideen bin Mohammed
sumber
1

Simplest / Cleanest bagi saya berarti juga hanya untuk memahami dan tidak ada lonceng & peluit seperti yang banyak dibahas dalam diskusi versi Java:

Apa cara yang efisien untuk menerapkan pola tunggal di Jawa?

Jawaban yang paling cocok / paling bersih di sana dari sudut pandang saya adalah:

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

Dan itu hanya sebagian dapat diterjemahkan ke JavaScript. Beberapa perbedaan dalam Javascript adalah:

  • konstruktor tidak boleh bersifat pribadi
  • Kelas tidak boleh memiliki bidang yang dideklarasikan

Tetapi mengingat sintaks ECMA terbaru adalah mungkin untuk mendekati:

Pola singleton sebagai contoh kelas JavaScript

 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;
  }
}

Contoh Penggunaan

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

Contoh Hasil

DefaultField1
DefaultField2
Wolfgang Fahl
sumber
1
function Once() {
    return this.constructor.instance || (this.constructor.instance = this);
}

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

    app.name = name;

    return app;
}

Jika Anda masuk kelas:

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

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

        this.name = name;
    }
}

Uji:

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
frasq
sumber
1

Jika Anda ingin menggunakan kelas:

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);

Output untuk yang di atas adalah:

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

Cara lain menulis Singleton menggunakan fungsi

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);

Output untuk yang di atas adalah:

console.log(a.name,a.age,b.name,b.age)// s 1 s 1
sudhee
sumber