javascript: 'this' object not accessible? - javascript

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

Related

How to reuse closure with different variables

I want to reuse the function sayMyName but with different variables. Please let me know if I'm structuring this the wrong way and what is the best practice what what I'm trying to do.
var sayMyName = function(myName) {
console.log(myName)
};
var name1 = function() {
// myName should not be a global variable
// because there may be more variables/functions
// that I'd want to closed inside sayMyName().
// Declaring all of them to the global scope is not ideal.
var myName = 'Walter';
sayMyName();
// I don't want to pass in myName as argument like this:
// sayMyName(myName);
// I want myName to be implicitly included in sayMyName()
// I want to pass in everything that is declared in name1 to sayMyName() implicitly.
};
var name2 = function() {
var myName = 'White';
sayMyName();
}
name1(); // should give me 'Walter'
name2(); // should give me 'White'
I'm not sure why you specifically want a closure, but by looking at your example it seems that a bind would be more appropriate than a closure.
var sayMyName = function(myName) {
console.log(myName)
};
var name1 = sayMyName.bind(undefined, 'Walter');
var name2 = sayMyName.bind(undefined, 'White');
name1(); // log 'Walter'
name2(); // log 'White'
Move your variable myName to the outermost scope:
var myName;
var sayMyName = function() {
console.log(myName)
};
var name1 = function() {
myName = 'Walter';
sayMyName();
};
var name2 = function() {
myName = 'White';
sayMyName();
}
name1(); // should give me 'Walter'
name2(); // should give me 'White'
Update: Thinking about it, if you're willing to use the non-standard, Error.stack attribute, are willing to use named functions, and are willing to use a naming convention, you could hackishly achieve your goal:
function sayMyName() {
try {
throw new Error();
}
catch (e) {
if (e.stack) { // non-standard attribute
var reNames = /^\s*at myNameIs([A-Z][^(\s]*)\s*\(/mg;
reNames.lastIndex = 0;
var buffer = [];
for (var match = reNames.exec(e.stack); null !== match; match = reNames.exec(e.stack)) {
buffer.push(match[1]);
}
console.log(buffer.join(" "));
}
}
}
function myNameIsWalter() {
sayMyName();
}
function myNameIsWhite() {
myNameIsWalter();
};
myNameIsWalter(); // "Walter"
myNameIsWhite(); // "Walter White"
... and if you're willing to use eval (bad !!!), then you could do fancier things like the following:
var sayMyName = function () {
try {
throw new Error();
}
catch (e) {
if (e.stack) { // non-standard attribute
var reNames = /^\s*at ([_a-zA-Z][_a-zA-Z0-9]+(\.[_a-zA-Z][_a-zA-Z0-9]+)*)/mg;
reNames.lastIndex = 0;
var reMyName = /\bmyName\s*=\s*(?:"([^"]*)"|'([^']*)')/g;
var identifier, definition, match, myName, buffer = [];
while (null !== (match = reNames.exec(e.stack))) {
try {
identifier = match[1];
if ("sayMyName" !== identifier) {
definition = eval(match[1] + '.toString()');
if (/\bsayMyName\(\)/.test(definition)) {
reMyName.lastIndex = 0;
buffer.length = 0;
while (null !== (myName = reMyName.exec(definition))) {
buffer.push(myName[1]);
}
console.log(buffer.join(" "));
}
}
}
catch (_) {
// continue
}
}
}
}
};
function name1() {
var myName = "Walter";
sayMyName();
}
function name2() {
var myName;
myName = "Walter";
myName = "White";
sayMyName();
}
name1(); // "Walter"
name2(); // "Walter White"
You could even use the non-standard, Function.caller attribute, which is probably the cleanest approach (if it works in your browser -- it's non-standard for a reason):
function sayMyName() {
var reMyName = /\bmyName\s*=\s*(?:"([^"]*)"|'([^']*)')/g;
var definition, buffer = [];
for (var caller = sayMyName.caller; caller; caller = caller.caller) {
definition = caller.toString();
if (/\bsayMyName\(\)/.test(definition)) {
reMyName.lastIndex = 0;
buffer.length = 0;
while (null !== (myName = reMyName.exec(definition))) {
buffer.push(myName[1]);
}
console.log(buffer.join(" "));
}
}
};
function name1() {
var myName = "Walter";
sayMyName();
}
function name2() {
var myName;
myName = "Walter";
myName = "White";
sayMyName();
}
name1(); // "Walter"
name2(); // "Walter White"
This is arguably no less code than just passing a parameter, though.
If you want closure then this is example.
function sayMyName(myName){
return function(){
console.log(myName); //myName is available from parent scope
return myName;
}
}
var name1 = sayMyName('Walter');
var name2 = sayMyName('White');
//no console output by now
name1(); //Walter
name2(); //White
//myName is not available in global scope
console.log(myName); //undefined

Try to create object of returned function?

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?

Javascript: Run a function defined outside this closure as if it were defined inside this closure

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'

Calling property from an object set to prototype

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

Javascript Object-Oriented-Programming

I found a Module pattern in JS:
<script>
var MODULENAME = (function(my, $) {
my.publicVar = "5";
my.publicFn = function() {};
return my;
}(MODULENAME || {}, jQuery));
</script>
However I cannot perform instantiation. Does the module pattern allow for that?
Instantiantion means basically that you'll run a function using new.
So maybe you're looking for this?
var Some = function (param) {
var somePrivateVar = 'private';
this.somePublicVar = 'public';
this.method = function () {
return param;
};
};
var some = new Some('abla');
console.log(some.method());
// some.somePrivateVar === undefined
// some.somePublicVar === 'public'
In your case MODULENAME is an object (object, not a function) with publicVar and publicFn. It's not meant to be instantiated the same way you wouldn't call new jQuery().
Your module object can contain anything. Perhaps you're looking for including a constructor in it:
var MODULENAME = (function(my, $) {
var privateVar = 10;
my.SomeConstructor = function() {
this.publicVar = 5;
}
my.SomeConstructor.prototype.someMethod = function() {};
my.SomeConstructor.prototype.getPrivate = function() { return 10; };
return my;
}(MODULENAME || {}, jQuery));
var instance = new MODULENAME.SomeConstructor();
instance.publicVar; // 5
instance.privateVar; // undefined
instance.getPrivate(); // 10
You can do this also with prototype Inheritance :
var MyClass = function(name)
{
//sharing name within the whole class
this.name = name;
}
MyClass.prototype.getName = function(){
return this.name;//now name is visible to getName method too
}
MyClass.StaticMethod = function()
{
console.log("Im Static");
// and since is not in prototype chain, this.name is not visible
}
var myclass = new MyClass("Carlos");
console.log(myclass.getName())//print "Carlos"
MyClass.StaticMethod()// print "Im Static"
myclass.StaticMethod() // error
Se all this article

Categories