Why am I getting undefined on this module pattern in javascript? - javascript

Why am I getting undefined on the x.test()? It's an anonymous function.
var Calculator = function () {
// private stuff
var x = 55;
return {
// public members
y: x,
test: function () {
console.log(x);
}
};
};
var x = new Calculator();
console.log(x.y);
console.log(x.test());

You're logging the return value of x.test which is implicitly undefined:
console.log(x.y); // Logs 55
var x = x.test(); // Logs 55 (because of the console.log call in x.test)
console.log(x); // Logs undefined (because that's what x.test returned)
Did you mean to return the "private" x from the test method?
// ...
return {
y: x,
test: function () {
return x;
}
}

Because you are printing (console.log) the return of a function that doesn't return anything.
Just return the x value in your test function:
var Calculator = function () {
// private stuff
var x = 55;
return {
// public members
y: x,
test: function () {
return x;
}
};
};

Related

Javascript accessing inner function from outside

I have the following json object
{
....
....
data: function() {
var x = 10;
function isBig() {
return x>6;
}
return x;
}
}
I want the isBig to be a function inside data.
When I call data.isBig I am getting undefined and data.isBig() gives me an error saying isBig is not a function.
First of all, that is not JSON. It is an object.
The way your object is structured currently, isBig is only accessible from inside data. If you want to access it outside data, the simplest way is to make it a property of the outer object:
{
data: function()
{
var x = 10;
return x;
}
isBig: function(x)
{
return x > 6;
}
}
If you don't want to do that, then an alternative would be this:
{
data: function()
{
var x = 10;
this.isBig = function(x)
{
return x > 6;
}
return x;
}
}
Calling data() works normally (returns 10), whereas calling new data() returns an object with a property isBig which corresponds to the function. This allows you to do this:
new myObj.data().isBig()
obj = {
data: function(){
var x = 10;
return this.isBig(x);
},
isBig: function(x){
return x > 6;
}
};
And if you want to reproduce the function but useally your better off with an contructor add that point.
f = {
isSmall: function(){},
isBig: function(x){
return x > 6;
}
};
obj = {
data: function(){
var x = 10;
return this.isBig(x);
},
isBig: f.isBig
};
obj.data();
obj.isBig(2);
f.isBig(2);

Is there something wrong with this following singleton pattern?

I come across singleton pattern, it's quite tricky to understand how to implement it, and I know some people would suggest to avoid it most of the time, so below is specific singleton variation that I find it easy to understand, but somehow I feel that this is not the best implementation of this pattern, can you guys suggest better form of this pattern.
var Foo = (function () {
var instance;
var _priVar = 2;
var log = function() {
console.log("Hello");
};
function Singleton(x, y) {
if (instance) {
return instance;
}
this.name = x;
this.age = y + _priVar;
this.log = log;
instance = this;
}
Singleton.getInstance = function () {
return instance || new Singleton();
}
return Singleton;
}());
and my goal is that when we do following
var a = new Foo("Bob", 24);
var b = new Foo();
var c = Foo();
var d = Foo.getInstance();
we will still get
a == b // true
a == c // true
a == d // true
a.name // 'Bob'
b.age // 26
c.log // 'Hello'
d.name // 'Bob'
The simplest singleton, also known as module pattern, consists of an object literal:
var foo = (function () {
var x = "Bob",
y = 24,
_priVar = 2;
function log() {
console.log("Hello");
}
return {
name: x,
age: y + _priVar,
log: log
};
}());
If you want to introduce lazy initialisation, you can use an extra getInstance function like in your implementation:
var getFoo = (function () {
var instance = null;
return function getFooInstance() {
if (instance) return instance;
var x = "Bob",
y = 24,
_priVar = 2;
function log() {
console.log("Hello");
}
return instance = {
name: x,
age: y + _priVar,
log: log
};
};
}());
A singleton should never use a constructor like in your code, that's just unnecessary. If you feel a need to pass arguments for initialisation, don't make it a singleton.

execution context and (( this object ))

// I don't understand why this is not working
y = 'window';
var x = {
y : 'x',
func : function(){
return function(){
return this.y
}
}
};
x.func()();
// when I execute x.func()() I understand why it should return y
// x.func() would return a function in the global context and then execute it ' should return 'window' '
y = 'window'
var x = {
y : 'x',
func : function(){
return function(){
return this.y
}()
}
};
x.func();
why would this code also return 'window' it is executed inside of the x object
The call x.func()() calls the function x.func using x as a context, then calls the value it returned using no context. Where the function was defined doesn’t matter; only how it was called does.
To avoid this, you can bind the function to a particular context before returning that:
var x = {
y: 'x',
func: function() {
return function() {
return this.y;
}.bind(this);
}
};
ES6 arrow functions also use a lexical this, equivalent to bind:
var x = {
y: 'x',
func: function() {
return () => this.y;
}
};

defining getters/setters in an object literal with a self-invoking function javascript

When defining an object literal its possible to use a self-invoking function so the function has access to private variables,
obj={
value:(function(){
var private;
return function(){
return true;
}
}())
};
But is it possible to do the same thing with a getter/setter in an object literal?
obj={
get value(){
return value;
},
set value(v) {
value=v;
}
};
[edit 2022]
A pretty old answer.
More actual: you can create a factory function. In the snippet the factory creates an object with (get and set) access (through the closure) to a private variable.
const obj1 = objFactory(`Hello`);
const obj2 = objFactory(`World`);
console.log(`${obj1.privateThing} ${obj2.privateThing}`);
obj1.privateThing = `Goodbye`;
console.log(`${obj1.privateThing} ${obj2.privateThing}`);
function objFactory(somethingPrivate) {
return {
get privateThing() { return somethingPrivate; },
set privateThing(value) { somethingPrivate = value; }
};
}
The old answer:
Not really. You can also create an Immediately Invoked Function Expression (IIFE) for obj though:
obj = function(){
var privatething = 'hithere';
return {
get value() {
return privatething;
},
set value(v) {
privatething = v;
}
};
}();
obj.value; //=> 'hithere';
obj.value = 'good morning to you too';
obj.value; //=> 'good morning to you too'
As per ES6 and later style, default values can also be set in the signature.
const _ = function(_x = 'leafy greens', _y = 'chicken', _z = 'noodle soup') {
// console.log(_x)
return {
_x,
_y,
_z,
get x() { return this._x },
set x(value) { this._x = value }
}
}()
console.log(_.x)
_.x = 'beef & pork'
console.log(_.x)
This works.
var obj = {a:1};
console.log(obj.a); //1
Object.defineProperty(obj,"a",{
get: function(){
return this.b;
},
set: function(x){
this.b = x;
},
configurable:true,
});
obj.a = 10;
console.log(obj); //10
for(var key in obj)
{
console.log(key)
}
If you don't want the property b to be enumerated while using for...in loop or Object.keys(), just add the line
Object.defineProperty(obj,"b",{enumerable:false})
Note : The above code can also be used as a listener, to detect changes in the property's value. (By implementing the needed function in the set method, after setting the value.)
var obj = {a:1};
console.log(obj.a); //1
Object.defineProperty(obj,"a",{
get: function(){
return this.b;
},
set: function(x){
this.b = x;
console.log("obj.a value has been changed to "+x);
},
configurable:true,
});
obj.a = 10;
obj.c = 20;
obj.a = 30;

Javascript oop-like fail(?!?)

Consider this:
function f2(x) {
return x+1;
};
X = function(){
this.f1=function (x) {
return 2*f2(x);
}
return this;
};
then x = new X(); x.f1(1) works fine.
But when i want to do this:
X = function(){
this.f2 = function(x) {
return x+1;
};
this.f1=function (x) {
return 2*f2(x);
}
return this;
};
The same statement will complain that it can't find f2.
In, for example c#, you can say
class X {
int f2(int x){return x+1;}
int f1(int x){return 2*f2(x);}
}
and this will work
X x=new X();
x.f1(1)
Why?
You need to reference the f2 with the this keyword explicitly.
X = function(){
this.f2 = function(x) {
return x+1;
};
this.f1=function (x) {
return 2*this.f2(x);
}
return this;
};
because you forgot this.f2. Javascript don't see class variables without this
To reference f2 in your second code block, you'll need to use this.f2. this references the context in which the function is being executed. Since you call f1 in the following way:
x.f1();
... the context is set to the instance, x.
JavaScript does not make instance variables available to the scope in the same way as scope variables, i.e. those directly available:
X = function(){
var f2 = 123;
this.f2 = function(x) {
return x+1;
};
this.f1=function (x) {
console.log(f2); // => 123
console.log(this.f2); // => function(){}
return 2 * this.f2(x);
};
return this;
};
Javascript doesn't have the implicit this that you get in C#. You need to add the this in:
X = function(){
this.f2 = function(x) {
return x+1;
};
this.f1=function (x) {
return 2*this.f2(x);
};
return this;
};
X = function(){
this.f2 = function(x) {
return x+1;
};
this.f1=function (x) {
return 2*this.f2(x); // <-- Need this here since it is not implicit
}
return this;
};

Categories