Here is my code:
var structure = {
A: function() {
this.B();
},
B: function() {
console.log(arguments.callee.caller.toString());
}
};
Then I run:
structure.A();
As you understand, I'm trying to get caller function name, but result is empty string. Are any ideas how to do that?
I've added the function name A, and slightly changed the statement that gets the string to print. Does this do what you want?
var structure = {
A: function A() {
this.B();
},
B: function() {
console.log(arguments.callee.caller.name);
}
}
structure.A();
Related
I have something similar to this:
var a = (function () {
return {
b: 1,
c: function () {
console.log(this.b);
}
};
})();
So,
a.c(); // = 1
But if I do
b = 2;
a.c.apply(this); // = 2
Is it possible to preserve the context of "this" inside "a.c()" without changing (too much) the structure of "a" object? I don't have the control of the function's call, so I'd need a workaround to deal with this inside the object itself.
UPDATE:
To be more specific, this is the structure of my files:
Structure 1 (singleton like pattern):
var a = (function () {
var _instance;
function init() {
return {
b: 1,
c: function () {
console.log(this.b);
}
};
}
return {
getInstance: function () {
if (_instance === undefined) {
_instance = init();
}
return _instance;
}
}
})();
Structure 2:
var b = {
c: 1,
d: function () {
console.log(this.c);
}
};
SOLUTION:
I have implemented a solution based on Mahout's answer, spliting the return statement inside init(), so it remains safe for the object context (and the instance) under any situation.
For singleton pattern:
var a = (function () {
var _instance,
self;
function init() {
return self = {
b: 1,
c: function () {
console.log(self.b);
}
};
}
return {
getInstance: function () {
if (_instance === undefined) {
_instance = init();
}
return _instance;
}
};
})();
For object literal:
var b = (function () {
var self;
return self = {
c: 1,
d: function () {
console.log(self.c);
}
};
})();
So
a.getInstance().c(); // 1
a.getInstance().c.apply(this); // 1
setTimeout(a.getInstance().c, 1); // 1
$.ajax({ complete: a.getInstance().c }); // 1
You can slightly change the way you are returning the object from the anonymous function:
var a = (function () {
var result = {};
result.b = 2;
result.c = function() {
console.log(result.b);
};
return result;
})();
This should have the same effect, however it does remove the use of this.
If you can't afford to change the structure of a this much, then alternately you can (much) more dangerously use:
a.c.apply = function() { // Stops the apply function working on a.c by overriding it
return a.c();
}
If you choose this though you must be wary that anytime a.c.apply is used it will no longer work 'as expected' - it will fix the issue presented here though.
I made this pen to illustrate the differences,I hope it helps:
http://codepen.io/dieggger/pen/BNgjBa?editors=001
var a = (function () {
return { b: 1,
c: function () {
console.log(this.b);
}
};
})();
a.c(); //prints 1
b = 2; // global variable "b" which is being hoisted BTW
// The following will act like this:
//it throws "cannot read property 'apply' from undefined"
//though it prints "1" since the first part invokes the "c" function
//inside of the"a" module which has the console.log
a.c().apply(this);
//In this case "this" is the window object which has the variable "b"
a.c.apply(this); // it'll print 2
You can do this:
var a = (function ()
{
return {
b: 1,
c: function ()
{
console.log(this.b);
}
}
})();
var decorator = function() { return a; };
var b = 2;
decorator.call(this).c(); // => 1
Basically it looks like you want to bind the IIFE, and not the object that it returns, to the outside scope, so that the nested returned object preserves the value of the interior b.
When experimenting with a method to make private static methods, I came across this very strange behavior. In the following code, the public method getData is overwritten by it's own return data, though it is never explicitly called! This is very strange to me and wondered what is going on here. I suppose it serves me right for not just encompassing the entire page in the anonymous function as per the module pattern, but I would still like to understand this bug.
function MyClass() {
this._prop = true;
}
MyClass.prototype.getData = function () {
this._prop = false;
return { a: 2344, b: 765, c: 234 };
}
(function () {
var privateStatic = 0;
MyClass.prototype.getCount = function () {
return privateStatic++;
}
} ());
var m = new MyClass();
console.log(m.getData()); //Error (object is not a function)
console.log(m.getData); //prints {a:2344,b:765,c:234}
The reason for this strange behavior is that getData is being immediately invoked due to the lack of a semicolon after the function declaration (great spot, dandavis) and the IIFE straight after it, wrapped in parens. Essentially, this:
MyClass.prototype.getData = function () {
this._prop = false;
return { a: 2344, b: 765, c: 234 };
} // Notice no semicolon here!
(function () {
var privateStatic = 0;
MyClass.prototype.getCount = function () {
return privateStatic++;
}
} ());
Becomes this:
MyClass.prototype.getData = function () {
this._prop = false;
return { a: 2344, b: 765, c: 234 };
}();
Which is therefore setting the getData property to the return value of the function. Hence why m.getData prints out { a: 2344, b: 765, c: 234 } and m.getData() doesn't work (it's no longer a function!).
Given the following object literal how do I call c from within b?
Update 1 - missed one thing I use JQuery load, which changes the context:
var a = {
b: function (e) {
$o.load(path, function (e) { // need to call c from here });
},
c: function (e) {
}
};
You should be able to do a.c() inside .b:
var a = {
b: function(e) {
a.c();
},
c: function(e) {}
};
a.b(); // calls c
Also, this will be bound to the a object which will allow you to access its properties using this.property:
b: function(e) {
this.c();
},
Try this:-
var a = {
b: function(e) {
a.c();
},
c: function(e) {}
};
a.b();
var a = {
b: function (e) {
a.c();
},
c: function (e) {
// magic goes here
}
};
a will be a closure so it's accessible in the functions (that is, a is defined in an wide, outer scope, which the narrower, inner scopes in each function inherit). Calling context is irrelevant; closures are formed when and where the functions are defined, so inside b, object a will always stay the same (unlike this, which can change).
From the method b you may call c using this.c as long as they are on the same object. However for the function expression being passed to $o I would suggest you bind the this pointer of b to it. Thus you do:
var a = {
b: function (e) {
$o.load(path, function (e) {
this.c();
}.bind(this));
},
c: function (e) {
}
};
Edit: The way you're creating and using this object is fragile. The this pointer may point to anything, such as when you unbind the methods or call it with a different context. Even using a.c isn't foolproof as other code may change a and when the method b is called a will point to something else.
I would do something like this:
var a = function (a) {
a.b = function (e) {
$o.load(path, function (e) {
a.c();
});
};
a.c = function (e) {
};
return a;
}({});
This code can not be tampered with and allows you to create private variables and closures.
The easiest solution which requires the minimum changes is to use jQuery.proxy():
var a = {
b: function (e) {
$o.load(path, $.proxy(function (e) { this.c(); }, this));
},
c: function (e) {
}
};
A = {
f1: function() {
return {
a: function(){ alert('sss'); }
}
}
}
A.f1().a();
Why is it used in this way?
Why is the method a() bound to A.f1()?
Member function f1 of A returns an object literal with its member a set to a function. It could've also been written as:
A = {
f1: {
a: function() { alert('sss'); }
}
}
A.f1.a();
Returning an object could in this case be personal preference. There is no functional difference between these two examples.
When you do as below:
var x = A.f1();
What you get on to x is the object returned by the f1 function. which is:
{
a: function(){ alert('sss'); }
}
now the object 'x' has function a() on it. You can call that function as:
x.a();
Which is exatly similar to:
A.f1().a();
if in a literal object i try to reference a function using "this" inside a nested property/function, this don't work. Why? A nested property have it's own scope?
For example, i want to call f1 from inside d.f2:
var object = {
a: "Var a",
b: "Var b",
c: "Var c",
f1: function() {
alert("This is f1");
},
d: {
f2: function() {
this.f1();
}
},
e: {
f3: function() {
alert("This is f3");
}
}
}
object.f1(); // Work
object.d.f2(); // Don't Work.
object.e.f3(); // Work
Thanks, Andrea.
this refers to d inside f2 and not object. You could store a reference to object, or call object directly, or use call/apply to call the function and explicitly tell it what this means inside that function:
object.d.f2.call(object); // now this refers to object inside f2
Here's an alternative approach which doesn't change the context of this inside f2(), based on #slaver113's idea:
var object = (function() {
var _this = {
f1: function() {
alert('This is f1');
},
d: {
f2: function() {
_this.f1();
}
}
}
return _this;
})();
object.d.f2(); // Alerts 'This is f1'