Forcing the context - javascript

I have this class where I have a private property and a public method for access:
Person = function () {
this.Name = "asd";
var _public = new Object();
_public.Name = function (value) {
if (value == undefined) { //Get
return this.Name
} else {
this.Name = value; //Set
}
};
return _public;
};
I want to force the context in _public.Name for access a this.Name.
I know the technique of closure, but I want to see if I can force a context.
I found a technique to do it, extend object Function:
Function.prototype.setScope = function (scope) {
var f = this;
return function () {
f().apply(scope);
}
}
And my class becomes:
Person = function () {
this.Name = "asd";
var _public = new Object();
_public.Name = function (value) {
if (value == undefined) {
return this.Name
} else {
this.Name = value;
}
}.setScope(this);
return _public;
};
So I can force correctly the context, but I can not pass value and can not, however, return this.Name.

Not
f().apply(scope);
just
f.apply(scope);
(No () after f.) You want to use the apply function on the function f object, not call the function f and access apply on its return value.
To also pass on the arguments that your function in setScope receives, add this:
f.apply(scope, arguments);
arguments is an implicit argument to all functions, which is a pseudo-array of the actual arguments passed to the function at runtime. apply accepts any array-like thing as its second parameter to specify the arguments to use when calling the underlying function.
I'd also have it return the return value:
return f.apply(scope, arguments);
So setScope becomes:
Function.prototype.setScope = function (scope) {
var f = this;
return function () {
return f.apply(scope, arguments);
}
}
Live example
Note that the usual name for this function, and the name it has in the new ECMAScript5 standard, is bind (Section 15.3.4.5; ECMAScript5's bind also lets you curry arguments, which isn't done by this implementation). setScope is a particularly unfortunate name, because it doesn't set the scope, it sets the context.
Having said all that, there's no reason you need setScope in your Person constructor. You can just do this:
Person = function () {
var self = this;
this.Name = "asd";
var _public = new Object();
_public.Name = function (value) {
if (value == undefined) {
return self.Name;
} else {
self.Name = value;
}
};
return _public;
};
Live example
But using bind (aka setScope) can be useful in places where you don't want a new closure over the context in which you're doing it.
Off-topic: The way you're specifying Person will break certain things people might expect to work, such as:
var p = new Person();
alert(p instanceof Person); // Expect "true", but in your case will be "false"
...because you're replacing the object new created for you, but returning a different object out of your constructor (which overrides the default).
Rather than creating a new object and returning that in your constructor, allow the object constructed for you by new to be the object (and thus the Person relationship is maintained), but you can still get truly private variables and use accessors:
function Person() {
// Private variable
var name = "asd";
// Accessor function
this.Name = function(value) {
if (typeof value === "undefined") {
return name;
}
name = value;
};
}
Live example
As you can see, this is dramatically simpler, and it preserves the instanceof relationship. Note that we're not qualifying our references to name within Name at all, and so we're using the local variable in the constructor call in which our Name function, which closes over it, was created.
I've also taken the liberty there of giving the constructor function a name, because I'm not a fan of anonymous functions. I should have given the accessor a name as well:
function Person() {
// Private variable
var name = "asd";
// Accessor function
this.Name = Person_Name;
function Person_Name(value) {
if (typeof value === "undefined") {
return name;
}
name = value;
}
}
Off-topic 2: The overwhelming convention in JavaScript code is to use initial caps on function names only for constructor functions (like Person), and not on other kinds of functions (like Name). You're free to do whatever you like, of course, but I thought I'd mention the convention, as it makes it easier for other people to read your code.
Worth noting: All of these techniques result in every single Person object having its own copy of the accessor function. If there are going to be a lot of these objects, that could be a memory issue. If there are only going to be a few, that's fine.

First thing, I think the correct way to go about this is the "closure" method, as the syntax is easier and simpler to understand and makes more sense and most object oriented code written in Javascript is written that way. Another thing to note is that in your method, the "private" member can be accessed from outside by accessing Person.Name (instead of (new Person()).Name).
That being said, it seems that you want something like Prototype.JS's bind method, which allows you to bind a function reference as a method call to a specific object, and also passes all the arguments correctly (including allowing preloaded arguments).
Look at Prototype.JS source for the complete implementation, but a simple implementation of this semantic might look like this:
Function.prototype.bind = function(context) {
var callee = this;
var args = Array.prototype.slice.call(arguments,1);
return function() {
var newargs = args.concat(Array.prototype.slice.call(arguments,0));
return callee.apply(context, newargs);
};
};

It is difficult to understand what you are trying to achieve. But if I guess that you are trying to create a Person class with a name method to get/set the person's name, here is my suggestion:
function Person() {
this._name = undefined; // not required but is better than assigning a fake name
return this;
}
Person.prototype.name = function( _name ) {
if ( _name === undefined ) return this._name; // get
return this._name = _name; // set
}
Note that I have defined the name function with a lower case first letter. This is standard practice in JavaScript where only constructors are usually capitalized. To use this class you do:
person = new Person();
person.name( "Ermes Enea Colella" );
alert( person.name ); // displays "Ermes Enea Colella"
There is no need to bind any context with this method, so you may be looking for something else. If you can clarify your need, I'll be happy to edit my answer.
I hope this helps.

Related

Can I bind a constructor's prototype methods to constructed instances while keeping concerns separated?

Say I have an object constructor and a prototype method, like:
function Human(name) {
this.name = name;
}
Human.prototype.sayName = function(){
console.log('my name' + this.name);
};
Elsewhere in my code, I've defined an instance of human:
let jeff = new Human('jeff');
and lastly I want to pass jeff.sayName as a callback to some other function, like (for a particularly trivial example)
function callFunction(callback) {
callback();
}
callFunction(jeff.sayName);
When I call callFunction(jeff.sayName) above, the context needs to be bound to jeff itself, like
callFunction(jeff.sayName.bind(jeff)). But this is clunky, and I'd rather not have to worry about this sort of logic every time I use this method as a callback.
An alternative would be to replace Human.prototype.sayName with something like
Human.prototype.createSayName = function(context){
return function() {
console.log(context.name);
};
};
and then define the function with
jeff.sayName = jeff.createSayName(jeff)
but this is a bit awkward, and I'd like to keep jeff agnostic to the methods it inherits from Human.prototype.
So ideally I'd like to handle this logic on Human.prototype itself, something like
Human.prototype.sayName.bind(WhateverObjectHoldsThisMethod)
but I'm not aware javascript has a way of doing this.
TL;DR I would like a way of binding an object's prototype method to whatever object inherits it, without having to do so every time I pass that method as an argument or every time I define a new object. Sorry if this makes little sense. Thanks!
Due to the way lexical environments, scope resolution, prototypal inheritance, and environment records work in JavaScript, what you're asking for is not possible without modifying the function which calls the callback function.
However, you could—instead of passing the Human#sayName reference as the call back—use an arrow function that in turn calls the Human#sayName reference you wish to call.
It's not perfect, but it's simple, clean, and readable.
function Human(name) {
this.name = name;
}
Human.prototype.sayName = function(){
console.log('my name' + this.name);
};
let jeff = new Human('jeff');
function callFunction(callback) {
callback();
}
callFunction(_ => jeff.sayName());
For a better understanding of those fancy words I referenced earlier, and how they work in JavaScript, I would recommend reading section 8.1 of the ECMAScript 2017 Language Specification. Subsection 8.1.1.3 has the specific information you're looking for, but the rest of the section up to that point is necessary to understand that subsection.
Basically, when you pass Human#sayName to callFunction, you're passing the reference to the original sayName function, so you might as well be doing this: (pardon the pun)
function callFunction(callback) {
callback();
}
callFunction(function(){
console.log('my name' + this.name);
});
The content of the function is not evaluated until it is executed, which means by the time it is executed, the value of this has already changed. To add to the debacle, the original function has no knowledge of which instance you requested it through. It never actually exists on the jeff object. It exists in the prototype of the the function object, and when you perform the object property look up, the JavaScript engine searches the prototype chain to find that function.
You very well could get the behavior you're asking for, but not under the constraints you have laid out. For example, if the function does not have to exist on the prototype chain, and can instead exist on the instance (keep in mind that this creates a new function object for each instance, so it will increase cost), you could define the function in the constructor, then store a reference to the correct this using an identifier that will not be overwritten:
function Human(name) {
const _this = this;
this.name = name;
this.sayName = function(){
console.log('my name' + _this.name);
};
}
let jeff = new Human('jeff');
function callFunction(callback) {
const _this = { name: 'hello' }; // does not affect output
callback();
callback.call(_this); // does not affect output
}
callFunction(jeff.sayName);
This would be a safer option, because you know that _this will always refer to the object you're expecting it to refer to within the context of the constructor, all function objects defined within that function object will inherit the identifiers of their parent scope, and those identifiers will not be affected by the calling context.
Or, you could go one step further, and not rely on the value of this at all:
function Human(name) {
const sayName = function(){
console.log('my name' + name);
};
Object.assign(this, { name, sayName });
}
let jeff = new Human('jeff');
function callFunction(callback) {
const name = 'hello'; // does not affect output
callback();
callback.call({ name: 'world' }); // does not affect output
}
callFunction(jeff.sayName);
This has the advantages of:
Being easier to read,
Less code,
Allowing you explicit about the properties and methods being exposed through the object, and
Never having to worry about what the value of this will be.
I suppose you may want to achieve this
function Human(name) {
this.name = name;
}
Human.prototype.sayName = function() {
console.log('my name' + this.name);
};
let jeff = new Human('jeff');
function callFunction(callback) {
callback();
}
callFunction(function() {
jeff.sayName()
});
another guess, a prototype bound to an instance, it works but has anti-patten
function Human(name) {
this.name = name;
}
const jeff = new Human('jeff');
Human.prototype.sayName = function() {
console.log('my name' + jeff.name);
};
function callFunction(callback) {
callback();
}
callFunction(jeff.sayName);
another guess, relection
function Human(name) {
this.name = name;
}
Human.prototype.sayName = function() {
console.log('my name' + this.name);
};
Human.prototype.reflectName = function(item) {
this.sayName = () => item.sayName()
};
const jeff = new Human('jeff');
const tod = new Human('tod');
tod.reflectName(jeff)
tod.sayName()
Expanding on TinyGiant answer, you can use an arrow function, but if you combine it with a getter, you can define it as a method of the prototype and not bother with defining your callback as a arrow function, which may be more flexible depending on your needs. Like this:
function Human(name) {
this.name = name;
}
Object.defineProperty(Human.prototype, "sayName", {
get: function() {
return () => {
console.log("my name is", this.name);
}
}
});
function callfunction(callback) {
callback();
}
let jeff = new Human('jeff');
callfunction(jeff.sayName);
// just to show it works even as a regular function
jeff.sayName();
// in fact it overrides every context you bind
jeff.sayName.bind(window)()

Javascript: Prototype on a function which accepts an argument

I'm having trouble achieving something in Javascript, and also having trouble explaining it. I'm writing an API and I want the developer to be able to write the following code:
dashboard('name1').createPanel('name2');
The problem is I can't figure out a way to create a function called "dashboard" (which accepts an argument 'name1') while also providing a prototype called createPanel.
You have functions and object. An example:
// A normal function
function dashboard(name) {
}
dashboard("name1");
You can also prototype this function if you do a new you will have to object of class dashboard. So the example:
function dashboard( name ) {
// As class
this.name = name;
}
dashboard.Prototype.createPanel = function(name) {
this.name = name;
return this; // return the reference
}
var x = new dashboard("name1"); // create object
x.createPanel( "Name2" );
// x.name will be "Name2"
What you want is chaining functions. All you need to do is return the object where you want to call the next function from. If you return this every time you can chain functions of that object like:
// extending the class with addProperty for chainging example
dashboard.Prototype.addProperty = function(key, value){
this[key] = value;
return this; // To enable chaining, return reference
}
var x = new dashboard("name1");
x.createPanel("Niels").addProperty("A", "B").addProperty("B", "C");
We can chain on and on. All you need to do is return the reference where you want to continue chaining from (normally the this object). But can be every object you want.

JavaScript: function returning an object

I'm taking some JavaScript/jQuery lessons at codecademy.com. Normally the lessons provide answers or hints, but for this one it doesn't give any help and I'm a little confused by the instructions.
It says to make the function makeGamePlayer return an object with three keys.
//First, the object creator
function makeGamePlayer(name,totalScore,gamesPlayed) {
//should return an object with three keys:
// name
// totalScore
// gamesPlayed
}
I'm not sure if i should be doing this
//First, the object creator
function makeGamePlayer(name,totalScore,gamesPlayed) {
//should return an object with three keys:
// name
// totalScore
// gamesPlayed
this.name = name;
this.totalScore = totalScore;
this.gamesPlayed = gamesPlayed;
}
or something like this
//First, the object creator
function makeGamePlayer(name,totalScore,gamesPlayed) {
//should return an object with three keys:
// name
// totalScore
// gamesPlayed
var obj = {
this.name = name;
this.totalScore = totalScore;
this.gamesPlayed = gamesPlayed;
}
}
I have to be able to modify the properties of the object after its created.
In JavaScript, most functions are both callable and instantiable: they have both a [[Call]] and [[Construct]] internal methods.
As callable objects, you can use parentheses to call them, optionally passing some arguments. As a result of the call, the function can return a value.
var player = makeGamePlayer("John Smith", 15, 3);
The code above calls function makeGamePlayer and stores the returned value in the variable player. In this case, you may want to define the function like this:
function makeGamePlayer(name, totalScore, gamesPlayed) {
// Define desired object
var obj = {
name: name,
totalScore: totalScore,
gamesPlayed: gamesPlayed
};
// Return it
return obj;
}
Additionally, when you call a function you are also passing an additional argument under the hood, which determines the value of this inside the function. In the case above, since makeGamePlayer is not called as a method, the this value will be the global object in sloppy mode, or undefined in strict mode.
As constructors, you can use the new operator to instantiate them. This operator uses the [[Construct]] internal method (only available in constructors), which does something like this:
Creates a new object which inherits from the .prototype of the constructor
Calls the constructor passing this object as the this value
It returns the value returned by the constructor if it's an object, or the object created at step 1 otherwise.
var player = new GamePlayer("John Smith", 15, 3);
The code above creates an instance of GamePlayer and stores the returned value in the variable player. In this case, you may want to define the function like this:
function GamePlayer(name,totalScore,gamesPlayed) {
// `this` is the instance which is currently being created
this.name = name;
this.totalScore = totalScore;
this.gamesPlayed = gamesPlayed;
// No need to return, but you can use `return this;` if you want
}
By convention, constructor names begin with an uppercase letter.
The advantage of using constructors is that the instances inherit from GamePlayer.prototype. Then, you can define properties there and make them available in all instances
You can simply do it like this with an object literal:
function makeGamePlayer(name,totalScore,gamesPlayed) {
return {
name: name,
totalscore: totalScore,
gamesPlayed: gamesPlayed
};
}
The latest way to do this with ES2016 JavaScript
let makeGamePlayer = (name, totalScore, gamesPlayed) => ({
name,
totalScore,
gamesPlayed
})
Both styles, with a touch of tweaking, would work.
The first method uses a Javascript Constructor, which like most things has pros and cons.
// By convention, constructors start with an upper case letter
function MakePerson(name,age) {
// The magic variable 'this' is set by the Javascript engine and points to a newly created object that is ours.
this.name = name;
this.age = age;
this.occupation = "Hobo";
}
var jeremy = new MakePerson("Jeremy", 800);
On the other hand, your other method is called the 'Revealing Closure Pattern' if I recall correctly.
function makePerson(name2, age2) {
var name = name2;
var age = age2;
return {
name: name,
age: age
};
}
I would take those directions to mean:
function makeGamePlayer(name,totalScore,gamesPlayed) {
//should return an object with three keys:
// name
// totalScore
// gamesPlayed
var obj = { //note you don't use = in an object definition
"name": name,
"totalScore": totalScore,
"gamesPlayed": gamesPlayed
}
return obj;
}

Why "function" keyword is necessary before object name ?All objects are function in real?

When we make an object like this
function myObject(){
Properties and methods here----
};
We write “function” keyword before name of object is it necessary? All objects are functions in real? Can we not write direct object name like this?
myObject(){
Properties and methods here----
};
No, not all objects are functions. (All functions are objects, though.)
Here, obj isn't a function:
var obj = {
foo: "bar"
};
Nor dt here:
var dt = new Date();
The function keyword is necessary in order to say "what follows is a function declaration or function expression." It's just part of the basic syntax of JavaScript.
in the first case, the function can be used as the constructor for an object. So you can have:
function Person(name) {
this.name = name
}
Person.prototype = {
// methods can go in here
}
person1 = new Person("bob");
alert(person1.name) // alerts "bob"
It is also true that you can use a function as an object. For example:
function myObject() {
return myObject.test;
}
myObject.test = "bob";
alert(myObject()) // would alert "bob"
but all objects are not functions.
var someObject = {
name: "bob",
moody: "sad"
}
alert(someObject.name); // alerts "bob"
try {
someObject();
} catch (er) {
alert(er); // alerts "TypeError: object is not a function"
}
I'd suggest you take a look at https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function
One reason is obviously disambiguity;
function foo()
{
alert("cake")
}
foo()
{
alert("burb");
}
foo();
alerts cake, burb, cake as the 2nd foo() {...} is just a regular function call followed by a regular compound statement enclosed in {}.
function declares a function. Because of the way JavaScript works, a function can be used as a class, to make objects.
But if you really just want an object, use squiggly braces, like this:
var myObject = {
x : 30, // a property
getX : function() { // a method
return this.x;
}
}
But your understanding of JavaScript needs a lot of work: read a few books about it.
In Javascript we can create objects in various ways:
1) Literals
let employee = {"name": "tyrion","age":34}
2) Constructor functions(functions having this)
function employee(name, age) {
this.name = name;
this.age = age;
}
let specificEmployee = new employee("tyrion",34);
Constructor function always need to have a new operator to create a object
3) Using Object constructor
let employee = Object.create(null);
employee.name = "tyrion";
employee.age = 34
In javascript every thing other than primitive type is an instance inherited from Object constructor.
No it's not required. You can also have:
var myObject = {
Prop1: "Value1",
Prop2: "Value2",
Method1: function() {
alert("hello");
}
};
Live test case: http://jsfiddle.net/rKunx/
You can write:
myObject = {
Properties and methods here----
}
If you want to avoid the function keyword as much as possible in Java you could use classes:
class Person {
name;
setName(name) {
this.name = name;
this.doStuff();
}
doStuff() {
//...
}
}
The obvious disadvantage to using classes though is that any property or function has to be accessed with this. An advantage of this keyword is that it is clear to know that you are referring to a class property or function and not a local one within the function.
Some people use a var or let in the top:
setName(name) {
let t = this;
t.name = name;
t.doStuff();
}
Still, many prefer to use a function to define some kind of class instead since that does not need this in order to reach the properties which are just variables in the scope of the function. Put inside a module you will still be able to contain these in much the same way you would a class.
If I could make a wish for the future of Javascript it would be to find some way that this is implicitly referring to the class in some way to have a smaller code style with less tokens and easier readability.

javascript singleton question

I just read a few threads on the discussion of singleton design in javascript. I'm 100% new to the Design Pattern stuff but as I see since a Singleton by definition won't have the need to be instantiated, conceptually if it's not to be instantiated, in my opinion it doesn't have to be treated like conventional objects which are created from a blueprint(classes). So my wonder is why not just think of a singleton just as something statically available that is wrapped in some sort of scope and that should be all.
From the threads I saw, most of them make a singleton though traditional javascript
new function(){}
followed by making a pseudo constructor.
Well I just think an object literal is enough enough:
var singleton = {
dothis: function(){},
dothat: function(){}
}
right? Or anybody got better insights?
[update] : Again my point is why don't people just use a simpler way to make singletons in javascript as I showed in the second snippet, if there's an absolute reason please tell me. I'm usually afraid of this kind of situation that I simplify things to much :D
I agree with you, the simplest way is to use a object literal, but if you want private members, you could implement taking advantage of closures:
var myInstance = (function() {
var privateVar;
function privateMethod () {
// ...
}
return { // public interface
publicMethod1: function () {
// private members can be accessed here
},
publicMethod2: function () {
// ...
}
};
})();
About the new function(){} construct, it will simply use an anonymous function as a constructor function, the context inside that function will be a new object that will be returned.
Edit: In response to the #J5's comment, that is simple to do, actually I think that this can be a nice example for using a Lazy Function Definition pattern:
function singleton() {
var instance = (function() {
var privateVar;
function privateMethod () {
// ...
}
return { // public interface
publicMethod1: function () {
// private members can be accessed here
},
publicMethod2: function () {
// ...
}
};
})();
singleton = function () { // re-define the function for subsequent calls
return instance;
};
return singleton(); // call the new function
}
When the function is called the first time, I make the object instance, and reassign singleton to a new function which has that object instance in it's closure.
Before the end of the first time call I execute the re-defined singleton function that will return the created instance.
Following calls to the singleton function will simply return the instance that is stored in it's closure, because the new function is the one that will be executed.
You can prove that by comparing the object returned:
singleton() == singleton(); // true
The == operator for objects will return true only if the object reference of both operands is the same, it will return false even if the objects are identical but they are two different instances:
({}) == ({}); // false
new Object() == new Object(); // false
I have used the second version (var singleton = {};) for everything from Firefox extensions to websites, and it works really well. One good idea is to not define things inside the curly brackets, but outside it using the name of the object, like so:
var singleton = {};
singleton.dothis = function(){
};
singleton.someVariable = 5;
The ES5 spec lets us use Object.create():
var SingletonClass = (function() {
var instance;
function SingletonClass() {
if (instance == null) {
instance = Object.create(SingletonClass.prototype);
}
return instance;
}
return {
getInstance: function() {
return new SingletonClass();
}
};
})();
var x = SingletonClass.getInstance();
var y = SingletonClass.getInstance();
var z = new x.constructor();
This is nice, since we don't have to worry about our constructor leaking, we still always end up with the same instance.
This structure also has the advantage that our Singleton doesn't construct itself until it is required. Additionally, using the closure as we do here prevents external code from using our "instance" variable, accidentally or otherwise. We can build more private variables in the same place and we can define anything we care to export publically on our class prototype.
The singleton pattern is implemented by creating a class with a method that creates a new instance of the class if one does not exist. If an instance already exists, it simply returns a reference to that object. 1
(function (global) {
var singleton;
function Singleton () {
// singleton does have a constructor that should only be used once
this.foo = "bar";
delete Singleton; // disappear the constructor if you want
}
global.singleton = function () {
return singleton || (singleton = new Singleton());
};
})(window);
var s = singleton();
console.log(s.foo);
var y = singleton();
y.foo = "foo";
console.log(s.foo);
You don't just declare the singleton as an object because that instantiates it, it doesn't declare it. It also doesn't provide a mechanism for code that doesn't know about a previous reference to the singleton to retrieve it. The singleton is not the object/class that is returned by the singleton, it's a structure. This is similar to how closured variables are not closures, the function scope providing the closure is the closure.
I am just posting this answer for people who are looking for a reliable source.
according to patterns.dev by Lydia Hallie, Addy Osmani
Singletons are actually considered an anti-pattern, and can (or.. should) be avoided in JavaScript.
In many programming languages, such as Java or C++, it's not possible to directly create objects the way we can in JavaScript. In those object-oriented programming languages, we need to create a class, which creates an object. That created object has the value of the instance of the class, just like the value of instance in the JavaScript example.
Since we can directly create objects in JavaScript, we can simply use
a regular object to achieve the exact same result.
I've wondered about this too, but just defining an object with functions in it seems reasonable to me. No sense creating a constructor that nobody's ever supposed to call, to create an object with no prototype, when you can just define the object directly.
On the other hand, if you want your singleton to be an instance of some existing "class" -- that is, you want it to have some other object as its prototype -- then you do need to use a constructor function, so that you can set its prototype property before calling it.
The latter code box shows what I've seen JS devs call their version of OO design in Javascript.
Singetons are meant to be singular objects that can't be constructed (except, I suppose, in the initial definition. You have one, global instance of a singleton.
The point of using the "pseudo constructor" is that it creates a new variable scope. You can declare local variables inside the function that are available inside any nested functions but not from the global scope.
There are actually two ways of doing it. You can call the function with new like in your example, or just call the function directly. There are slight differences in how you would write the code, but they are essentially equivalent.
Your second example could be written like this:
var singleton = new function () {
var privateVariable = 42; // This can be accessed by dothis and dothat
this.dothis = function () {
return privateVariable;
};
this.dothat = function () {};
}; // Parentheses are allowed, but not necessary unless you are passing parameters
or
var singleton = (function () {
var privateVariable = 42; // This can be accessed by dothis and dothat
return {
dothis: function () {
return privateVariable;
},
dothat: function () {}
};
})(); // Parentheses are required here since we are calling the function
You could also pass arguments to either function (you would need to add parentheses to the first example).
Crockford (seems to) agree that the object literal is all you need for a singleton in JavaScript:
http://webcache.googleusercontent.com/search?q=cache:-j5RwC92YU8J:www.crockford.com/codecamp/The%2520Good%2520Parts%2520ppt/5%2520functional.ppt+singleton+site:www.crockford.com&cd=1&hl=en&ct=clnk
How about this:
function Singleton() {
// ---------------
// Singleton part.
// ---------------
var _className = null;
var _globalScope = null;
if ( !(this instanceof arguments.callee) ) {
throw new Error("Constructor called as a function.");
}
if ( !(_className = arguments.callee.name) ) {
throw new Error("Unable to determine class name.")
}
_globalScope = (function(){return this;}).call(null);
if ( !_globalScope.singletons ) {
_globalScope.singletons = [];
}
if ( _globalScope.singletons[_className] ) {
return _globalScope.singletons[_className];
} else {
_globalScope.singletons[_className] = this;
}
// ------------
// Normal part.
// ------------
var _x = null;
this.setx = function(val) {
_x = val;
}; // setx()
this.getx = function() {
return _x;
}; // getx()
function _init() {
_x = 0; // Whatever initialisation here.
} // _init()
_init();
} // Singleton()
var p = new Singleton;
var q = new Singleton;
p.setx(15);
q.getx(); // returns 15
I stole this from CMS / CMS' answer, and changed it so it can be invoked as:
MySingleton.getInstance().publicMethod1();
With the slight alternation:
var MySingleton = { // These two lines
getInstance: function() { // These two lines
var instance = (function() {
var privateVar;
function privateMethod () {
// ...
console.log( "b" );
}
return { // public interface
publicMethod1: function () {
// private members can be accessed here
console.log( "a" );
},
publicMethod2: function () {
// ...
privateMethod();
}
};
})();
singleton = function () { // re-define the function for subsequent calls
return instance;
};
return singleton(); // call the new function
}
}

Categories

Resources