I was trying something different and ended up with these codes..
var f1 = function() {
this.x = 10;
this.innerf = function() { console.log(this.x); }
}
var of1 = new f1();
of1.innerf();
var f2 = function() {
return function() {
this.x = 10;
this.innerf = function() { console.log(this.x); }
}
}
var of2 = new f2();
of2.innerf();
It is throwing error ??! of2.inner is not a function
So, my anonymous function is returning same function body to my variable.
Why still i cannot able to instantiate??
The first part returns an object of which you can call the innerf method.
The second part returns a function that would return an object if you called it. But you don't.
This would work. Call the function f2(). It's return value is the anonymous function. Then, with new <return value of f2>(), you can create an instance of the object.
var f2 = function() {
return function() {
this.x = 10;
this.innerf = function() { console.log(this.x); }
}
}
var of2 = new (f2())();
of2.innerf();
// The two lines above can also be written as:
var of3constructor = f2(); // This returns the inner anonymous function.
var of3 = new of3constructor(); // This creates an instance by invoking the anonymous function.
of3.innerf();
Examples that work:
Creating it directly:
var f1 = function() {
this.x = 11;
this.innerf = function() {
console.log(this.x);
}
}
var of1 = new f1();
of1.innerf();
Returning a new object from a function:
var f2 = function() {
return new function() {
this.x = 12;
this.innerf = function() {
console.log(this.x);
}
}
}
var of2 = f2();
of2.innerf();
Returning an object:
var f3 = function() {
return {
x: 13,
innerf : function() {
console.log(this.x);
}
}
}
var of3 = f3();
of3.innerf();
Another one:
var f4 = function() {
return function() {
this.x = 10;
this.innerf = function() {
console.log(this.x);
}
}
}
var of4 = new (f2())();
of2.innerf();
Remember that when you call a function without the "new" keyword "this" points object where the functions was declared, in this case "window"
You need to return this from the inner function to the outer function. Also you need to run the inner function immediately.
jsFiddle:
http://jsfiddle.net/5dxybbb5/
var f1 = function() {
this.x = 10;
this.innerf = function() {console.log(this.x);}
}
var of1 = new f1();
of1.innerf();
var f2 = function() {
return function() {
this.x = 10;
this.innerf = function() {console.log(this.x);}
return this;
}();
}
var of2 = new f2();
of2.innerf();
Also this explains the () after a function declaration
What is the (function() { } )() construct in JavaScript?
Related
I'm using an example from here.
function Restaurant() {
this.mongoose = 'beans';
this.freedom = {bear: 'love', a: 12};
var myPrivateVar;
// Only visible inside Restaurant()
var private_stuff = function() {
myPrivateVar = "I can set this here!";
this.mongoose = 12;
this.freedom.a = 14; // <= 'a' undefined 2nd time
}
// use_restroom is visible to all
this.use_restroom = function() {
private_stuff();
}
// buy_food is visible to all
this.buy_food = function() {
private_stuff();
}
private_stuff.call(this);
}
var bobbys = new Restaurant();
bobbys.buy_food() // <= fails
I set this.freedom.a to 14 in private_stuff() and then I call bobbys.buy_food().
When that function is called, this.freedom apparently is undefined, so I can't set a.
Does anybody know why it fails on freedom and not on mongoose?
I appreciate comments, but if someone posts an 'Answer', then I can close this as solved, and give you the credit.
If you're interested in using this pattern correctly, its whole point is to avoid this (let alone .call(this)) altogether. Your "private" methods and properties are just variables in a closure, and public methods/props are attached to a local object, which is either a closed this or simply a literal:
function Restaurant() {
var self = this; // or {}
self.publicProp = '';
var privateProp = '';
var privateFunc = function() {
privateProp = 'hello';
self.publicProp = 'world';
}
self.publicFunc = function() {
privateFunc();
return privateProp;
}
// return self; // if used a literal above
}
var bobbys = new Restaurant();
console.log(bobbys.publicFunc())
console.log(bobbys.publicProp)
Now it should work :)
just use call in your buy food method.
function Restaurant() {
this.mongoose = 'beans';
this.freedom = {bear: 'love', a: 12};
var myPrivateVar;
// Only visible inside Restaurant()
var private_stuff = function() {
myPrivateVar = "I can set this here!";
this.mongoose = 12;
this.freedom.bear = 14; // <= 'a' undefined 2nd time
}
// use_restroom is visible to all
this.use_restroom = function() {
private_stuff();
}
// buy_food is visible to all
this.buy_food = function(...args) {
private_stuff.call(this, ...args);
}
private_stuff.call(this);
}
var bobbys = new Restaurant();
bobbys.buy_food()
function Restaurant() {
var ths = this;
this.mongoose = 'beans';
this.freedom = {bear: 'love', a: 12};
var myPrivateVar;
// Only visible inside Restaurant()
var private_stuff = function() {
myPrivateVar = "I can set this here!";
this.mongoose = 12;
ths.freedom.a = 14; // <= 'a' undefined 2nd time
}
// use_restroom is visible to all
this.use_restroom = function() {
private_stuff();
}
// buy_food is visible to all
this.buy_food = function() {
private_stuff();
}
private_stuff.call(this);
}
var bobbys = new Restaurant();
bobbys.buy_food()
Try this
I have a type that looks a little something like this:
var x = function(){
this.y = function(){
}
this.z = function(){
...
this.A = function(){
CALLING POINT
}
}
}
From calling point, I'm attempting to call function this.y. I don't need to pass any parameters, but when I set some stuff from this.A, I need to call this.y.
Is this possible? I'm OK with passing extra parameters to functions to make it possible.
Is this possible?
Yes, you can assign this reference to another variable and then call function y on it
this.z = function() {
var self = this;
this.A = function() {
self.y();
}
}
Version with bind, basically this adds a new method a to the object.
var X = function () {
this.y = function () {
document.write('y<br>');
}
this.z = function () {
document.write('z<br>');
this.a = function () {
document.write('a<br>');
this.y();
}
}.bind(this);
};
var x = new X;
//x.a(); // does not exist
x.z(); // z
x.a(); // a y
Working example with saved inner this.
var X = function () {
var that = this; // <--
this.y = function () {
document.write('y<br>');
}
this.Z = function () {
document.write('Z<br>');
this.a = function () {
document.write('a<br>');
that.y();
}
}
}
var x = new X,
z = new x.Z; // Z
z.a(); // a y
Instead of function() you can try modern JavaScript or Typescript ()=>. I also like .bind(this).
You cannot because this.y() is not within the scope that this.A() is in. You can if you set this.y() to a global function y:
var y = function() {};
var x = function() {
this.y = y;
this.z = function() {
...
this.A = function() {
this.y(); // will be successful in executing because this.y is set to the y function.
};
}
};
I want to have a function A that accepts another function B as an argument, and then runs B as it were defined within the closure scope of A, i.e. has access to all the local variables.
For example, simplistically:
var A = function(B){
var localC = "hi";
B();
}
var B = function(){
console.log(localC);
}
A(B); // to log 'hi'
The only way I have found is to use eval. Does ec6 give any better options maybe?
One solution is to pass localC as argument in function B:
var A = function(B) {
var localC = "hi";
B(localC);
}
var B = function(localC) {
console.log(localC);
}
A(B); // outputs hi
Alternative using arguments:
var A = function(B) {
var localC = "hi";
B(localC, "test");
}
var B = function() {
var i = 0;
for (i; i < arguments.length; i++) {
console.log(arguments[i]);
}
}
A(B); // outputs hi, test
You can make the context explicit and pass it to B:
var A = function(B){
var context = {
localC: "hi"
};
B(context);
}
var B = function(context){
console.log(context.localC);
}
A(B); // hi
You can also use this with new and prototype:
var A = function() {
this.localC = "hi";
}
A.prototype.b = function(context){
console.log(this.localC);
}
var a = new A();
a.b(); // hi
or without the prototype:
var A = function() {
this.localC = "hi";
}
var a = new A();
a.b = function(context){
console.log(this.localC);
};
a.b(); // hi
You can use this with bind:
var a = {
localC: "hi"
};
function B(foo) {
console.log(this.localC, foo);
}
B.bind(a)("foo"); // hi foo
// .call:
B.call(a, "foo"); // hi foo
bind sets the context for this. call takes the context as it's first argument.
This one is not good:
var A = function(B){
var localC = "hi";
B.bind(this)(); // this is the global object, you need `new` to create a new scope
}
var B = function(){
console.log(this.localC);
}
A(B); // undefined
var A = function(B){
var self = this;
self.localC = "hi";
self.localD = "hello";
B();
};
var B = function(){
var self=this;
alert(self.localD);
}
A(B); // to log 'hi'
var Foo = function() {
this.message = "Hi";
}
Foo.prototype = {
say: {
hi: function() {
console.log(this.message);
}
}
}
[edit]I know "this" in hi() refers say, is there any way to achieve this?
var he = new Foo();
he.say.hi(); //"Hi" to console
You can access like this.
var Foo = function(){
this.par = 3;
this.sub = new(function(t){ //using virtual function to create sub object and pass parent object via 't'
this.p = t;
this.subFunction = function(){
alert(this.p.par);
}
})(this);
}
var myObj = new Foo();
myObj.sub.subFunction() // will popup 3;
myObj.par = 5;
myObj.sub.subFunction()
All you need is to bind the hi function just like this:
var Foo = function() {
this.message = "Hi";
this.say.hi = this.say.hi.bind(this);
}
Foo.prototype = {
say: {
hi: function() {
console.log(this.message);
}
}
}
var he = new Foo();
he.say.hi();
It works fine as the following:
function A() {
}
A.prototype.f1 = function() {
alert('f1');
};
A.prototype.f2 = function() {
// calls f1
A.prototype.f1();
};
var a = new A();
a.f2(); // alert f1 correctly
But there's a function B to make A undefined to window scope, but can be accessed inside B scope:
function A() {
}
A.prototype.f1 = function() {
alert('f1');
};
A.prototype.f2 = function() {
// calls f1
A.prototype.f1();
};
function B() {
var PrivateA = null;
this.makePrivate = function() {
PrivateA = A; // private access
A = undefined; // undefined with window object
};
this.callA = function() {
var a = new PrivateA();
a.f2(); // it calls A.prototype.f1();, but A is undefined now
};
}
var b = new B();
// expect to accessible
var a = new A();
b.makePrivate();
// expect to inaccessible to window
alert(typeof A); // expect to be 'undefined'
b.callA(); // expect to alert 'f1', which not works now since A is undefined
I want make A accessible before B is called and A inaccessible when B is called.
Please give some advice.
You can set up B to look like this:
function B() {
var PrivateA; // It's not accessible from outside of B's scope
this.makePrivate = function() {
PrivateA = A; // Still in B's scope, so it works
A = undefined;
};
this.callA = function() {
var a = new PrivateA(); // So is this
a.f2();
};
}
Here's what happens when I run it:
> var b = new B();
> A
function A() {
this.f1 = function() {
alert('f1');
};
this.f2 = function() {
// calls f1
this.f1();
};
}
> b.makePrivate();
> A
undefined
> b.callA(); // I get an alert that says 'f1'