I'm using the following JavaScript code:
var emp= new Object();
emp["name"]="pooja";
emp["salary"]=725;
emp["paycheck"]=function()
{
var monthly=this["salary"]/12;
alert(this["name"]+":"+monthly);
};
emp["paycheck"](); --work properly
document.write("<br/>");
var f=emp["paycheck"]; --dosen't work
f();
f() have to get reference on emp["paycheck"] function and display a suitable answer.
but insted i get NaN.
As i understood f() dosen't see the property of emp object("name" and "salary").
My question is why f() dosen't see the properties?
You refer to salary as this["salary"]. If you store the function and call it later, the this value is lost. It is only bound to the object if you directly call it, as in emp.paycheck(). You could pass the this value explicitly, though:
f.call(emp);
But you might rather want to refer to salary in the function as emp["salary"], since that will always work.
Note that instead of foo["bar"] you can use foo.bar, and that the new Object() part can just be:
var emp = {
name: "pooja",
salary: 725,
paycheck: function() {
...
}
};
The reason why is you are calling the function without a this parameter. You need to use apply to pass it an explicit this on which it can call the name and salary properties.
f.apply(emp);
you reference on a function, not on all object.
f = emp;
f.paycheck();
You didn't copy those properties to f. There are, unfortunately, no native ways to do this in JavaScript. See How do I correctly clone a JavaScript object? or What is the most efficient way to deep clone an object in JavaScript?, look at jQuery's extend(), or google "javascript deep copy object" or "javascript clone object".
Others have explained what's going on and how you don't pass this.
However, if you want to do something like this (a custom from Python perhaps?), you can make a helper function:
function makeDelegate(obj, fun) {
return function() {
fun.apply(obj, arguments);
};
}
Then use it like this:
var f = makeDelegate(emp, emp["paycheck"]);
f();
Related
Let's say I instantiate an object in Javascript like this:
var myObj = new someObject();
Now, is it possible to obtain the var object's name as string 'myObj' from within one of the class methods?
Additional details (edited):
The reason why I would like to get the name of the variable holding reference to the object is that my new myObj would create a new clickable DIV on the page that would need to call a function myObj.someFunction(). As I insert the new DIV I need to know the name of the variable holding reference to the object. Is there maybe a better way of doing this?
You are right, sorry for the mixup in terminology.
The reason why I would like to get the name of the variable holding reference to the object is that my new myObj would create a new clickable DIV on the page that would need to call a function myObj.someFunction(). As I insert the new DIV I need to know the name of the variable holding reference to the object. Is there maybe a better way of doing this?
Shog9 is right that this doesn't make all that much sense to ask, since an object could be referred to by multiple variables. If you don't really care about that, and all you want is to find the name of one of the global variables that refers to that object, you could do the following hack:
function myClass() {
this.myName = function () {
// search through the global object for a name that resolves to this object
for (var name in this.global)
if (this.global[name] == this)
return name
}
}
// store the global object, which can be referred to as this at the top level, in a
// property on our prototype, so we can refer to it in our object's methods
myClass.prototype.global = this
// create a global variable referring to an object
var myVar = new myClass()
myVar.myName() // returns "myVar"
Note that this is an ugly hack, and should not be used in production code. If there is more than one variable referring to an object, you can't tell which one you'll get. It will only search the global variables, so it won't work if a variable is local to a function. In general, if you need to name something, you should pass the name in to the constructor when you create it.
edit: To respond to your clarification, if you need to be able to refer to something from an event handler, you shouldn't be referring to it by name, but instead add a function that refers to the object directly. Here's a quick example that I whipped up that shows something similar, I think, to what you're trying to do:
function myConstructor () {
this.count = 0
this.clickme = function () {
this.count += 1
alert(this.count)
}
var newDiv = document.createElement("div")
var contents = document.createTextNode("Click me!")
// This is the crucial part. We don't construct an onclick handler by creating a
// string, but instead we pass in a function that does what we want. In order to
// refer to the object, we can't use this directly (since that will refer to the
// div when running event handler), but we create an anonymous function with an
// argument and pass this in as that argument.
newDiv.onclick = (function (obj) {
return function () {
obj.clickme()
}
})(this)
newDiv.appendChild(contents)
document.getElementById("frobnozzle").appendChild(newDiv)
}
window.onload = function () {
var myVar = new myConstructor()
}
Short answer: No. myObj isn't the name of the object, it's the name of a variable holding a reference to the object - you could have any number of other variables holding a reference to the same object.
Now, if it's your program, then you make the rules: if you want to say that any given object will only be referenced by one variable, ever, and diligently enforce that in your code, then just set a property on the object with the name of the variable.
That said, i doubt what you're asking for is actually what you really want. Maybe describe your problem in a bit more detail...?
Pedantry: JavaScript doesn't have classes. someObject is a constructor function. Given a reference to an object, you can obtain a reference to the function that created it using the constructor property.
In response to the additional details you've provided:
The answer you're looking for can be found here: JavaScript Callback Scope (and in response to numerous other questions on SO - it's a common point of confusion for those new to JS). You just need to wrap the call to the object member in a closure that preserves access to the context object.
You can do it converting by the constructor to a string using .toString() :
function getObjectClass(obj){
if (typeof obj != "object" || obj === null) return false;
else return /(\w+)\(/.exec(obj.constructor.toString())[1];}
You might be able to achieve your goal by using it in a function, and then examining the function's source with toString():
var whatsMyName;
// Just do something with the whatsMyName variable, no matter what
function func() {var v = whatsMyName;}
// Now that we're using whatsMyName in a function, we could get the source code of the function as a string:
var source = func.toString();
// Then extract the variable name from the function source:
var result = /var v = (.[^;]*)/.exec(source);
alert(result[1]); // Should alert 'whatsMyName';
If you don't want to use a function constructor like in Brian's answer you can use Object.create() instead:-
var myVar = {
count: 0
}
myVar.init = function(n) {
this.count = n
this.newDiv()
}
myVar.newDiv = function() {
var newDiv = document.createElement("div")
var contents = document.createTextNode("Click me!")
var func = myVar.func(this)
newDiv.addEventListener ?
newDiv.addEventListener('click', func, false) :
newDiv.attachEvent('onclick', func)
newDiv.appendChild(contents)
document.getElementsByTagName("body")[0].appendChild(newDiv)
}
myVar.func = function (thys) {
return function() {
thys.clickme()
}
}
myVar.clickme = function () {
this.count += 1
alert(this.count)
}
myVar.init(2)
var myVar1 = Object.create(myVar)
myVar1.init(55)
var myVar2 = Object.create(myVar)
myVar2.init(150)
// etc
Strangely, I couldn't get the above to work using newDiv.onClick, but it works with newDiv.addEventListener / newDiv.attachEvent.
Since Object.create is newish, include the following code from Douglas Crockford for older browsers, including IE8.
if (typeof Object.create !== 'function') {
Object.create = function (o) {
function F() {}
F.prototype = o
return new F()
}
}
As a more elementary situation it would be nice IF this had a property that could reference it's referring variable (heads or tails) but unfortunately it only references the instantiation of the new coinSide object.
javascript: /* it would be nice but ... a solution NOT! */
function coinSide(){this.ref=this};
/* can .ref be set so as to identify it's referring variable? (heads or tails) */
heads = new coinSide();
tails = new coinSide();
toss = Math.random()<0.5 ? heads : tails;
alert(toss.ref);
alert(["FF's Gecko engine shows:\n\ntoss.toSource() is ", toss.toSource()])
which always displays
[object Object]
and Firefox's Gecko engine shows:
toss.toSource() is ,#1={ref:#1#}
Of course, in this example, to resolve #1, and hence toss, it's simple enough to test toss==heads and toss==tails. This question, which is really asking if javascript has a call-by-name mechanism, motivates consideration of the counterpart, is there a call-by-value mechanism to determine the ACTUAL value of a variable? The example demonstrates that the "values" of both heads and tails are identical, yet alert(heads==tails) is false.
The self-reference can be coerced as follows:
(avoiding the object space hunt and possible ambiguities as noted in the How to get class object's name as a string in Javascript? solution)
javascript:
function assign(n,v){ eval( n +"="+ v ); eval( n +".ref='"+ n +"'" ) }
function coinSide(){};
assign("heads", "new coinSide()");
assign("tails", "new coinSide()");
toss = Math.random()<0.5 ? heads : tails;
alert(toss.ref);
to display heads or tails.
It is perhaps an anathema to the essence of Javascript's language design, as an interpreted prototyping functional language, to have such capabilities as primitives.
A final consideration:
javascript:
item=new Object(); refName="item"; deferAgain="refName";
alert([deferAgain,eval(deferAgain),eval(eval(deferAgain))].join('\n'));
so, as stipulated ...
javascript:
function bindDIV(objName){
return eval( objName +'=new someObject("'+objName+'")' )
};
function someObject(objName){
this.div="\n<DIV onclick='window.opener."+ /* window.opener - hiccup!! */
objName+
".someFunction()'>clickable DIV</DIV>\n";
this.someFunction=function(){alert(['my variable object name is ',objName])}
};
with(window.open('','test').document){ /* see above hiccup */
write('<html>'+
bindDIV('DIVobj1').div+
bindDIV('DIV2').div+
(alias=bindDIV('multiply')).div+
'an aliased DIV clone'+multiply.div+
'</html>');
close();
};
void (0);
Is there a better way ... ?
"better" as in easier? Easier to program? Easier to understand? Easier as in faster execution? Or is it as in "... and now for something completely different"?
Immediately after the object is instantiatd, you can attach a property, say name, to the object and assign the string value you expect to it:
var myObj = new someClass();
myObj.name="myObj";
document.write(myObj.name);
Alternatively, the assignment can be made inside the codes of the class, i.e.
var someClass = function(P)
{ this.name=P;
// rest of the class definition...
};
var myObj = new someClass("myObj");
document.write(myObj.name);
Some time ago, I used this.
Perhaps you could try:
+function(){
var my_var = function get_this_name(){
alert("I " + this.init());
};
my_var.prototype.init = function(){
return my_var.name;
}
new my_var();
}();
Pop an Alert: "I get_this_name".
This is pretty old, but I ran across this question via Google, so perhaps this solution might be useful to others.
function GetObjectName(myObject){
var objectName=JSON.stringify(myObject).match(/"(.*?)"/)[1];
return objectName;
}
It just uses the browser's JSON parser and regex without cluttering up the DOM or your object too much.
I'm learning javascript right now, seems like beautiful functional language to me, it is wonderful move from PHP, I should have done this earlier. Although, I cannot figure this one out:
var v1 = (/[abc]/).test;
v1('a');
says test method called on incompatible undefined, I'm trying to store the test method of that regex into variable and invoke it later.
but it works with my own functions:
function foo(){
return 'I\'m foo';
}
var f = foo;
f(); // returns I'm foo
It should work on methods too, since functions are just methods of parent object anyway, right?
Ultimately, the reason I'm trying this is to be able to write something like this:
var a = ['a', 'b', 'c'];
a.every( (/[abc]/).test );
to check each array member against that regex.
Why doesn't this work? Is it limitation in passing built-in functions around? Or am I just doing something wrong?
PS: If you grind your teeth now and muffling something about bad practices, screw good practices, I'm just playing. But I'd like to hear about them too.
it works with my own functions
You are not using this inside the function. Consider this example:
var obj = {
foo: 42,
bar: function() {
alert(this.foo);
}
};
var f = obj.bar;
f(); // will alert `undefined`, not `42`
It should work on methods too, since functions are just methods of parent object anyway, right?
"Method" is just a colloquial term for a function assigned to a property on object. And functions are standalone values. There is no connection to the object a function is assigned to. How would this even be possible, since a function could be assigned to multiple objects?
Why doesn't this work?
What this refers to inside a function is determined at run time. So if you assign the function to a variable and call it later
var v1 = (/[abc]/).test;
v1('a');
this inside the function will refer to window, not to the regular expression object.
What you can do is use .bind [MDN] to explicitly bind this to a specific value:
var a = ['a', 'b', 'c'];
var pattern = /[abc]/;
a.every(pattern.test.bind(pattern));
Note though that since .bind returns a function, the only advantage over using a function expression is that it is a tad shorter to write.
Is it limitation in passing built-in functions around?
No, the problem exists for every method/function because that's how functions work. The nice thing about built-in functions though is that they often explicitly tell you when this is referring to the wrong type of object (by throwing an error).
Learn more about this.
If you store just a method, it does not carry with it a reference to your object - it just stores a reference to the .test method, but no particular object. Remember, a method is "just" a property on an object and storing a reference to a method doesn't bind it to that object, it just stores a reference to the method.
To invoke that method on a particular object, you have to call it with that object.
You can make your own function that calls the method on the desired object like this:
var v1 = function(x) {
return /[abc]/.test(x);
}
Then, when you do this:
v1('a');
It will execute the equivalent of this in your function:
/[abc]/.test('a');
But, it isn't entirely clear why you're doing that as you could also just define the regex and call .test() on it several times:
var myRegex = /[abc]/;
console.log(myRegex.test('a'));
console.log(myRegex.test('b'));
console.log(myRegex.test('z'));
The test function expects this to be a regular expression. The expression /[abc]/.test gives an unbound function (it does not remember that it belongs to /[abc]/). When you invoke it like you do, this will be undefined and the function will fail.
You can use bind to make the function remember the object it belongs to:
var v1 = /[abc]/.test.bind(/[abc]/);
or
var v1 = RegExp.prototype.test.bind(/[abc]/);
Your reference to the method has lost its knowledge of what it was a method of.
This isn't so much good practice as just the way JS works.
You can do:
var v1 = /[abc]/;
v1.test('a');
If you must encapsulate the test method, then you could do:
var v1 = function(str){
return /[abc]/.test(str);
};
v1('a');
I don't know if this is an acceptable solution, but you can do:
v1 = function(exp) { return (/[abc]/).test(exp); }
v1('a');
So, I've got some code that looks like this (genericised from a closed-source project).
UserWizard = {
init: function(name) {
this.firstInit.call(name);
this.secondInit.call(name);
},
firstInit: function(name) {
// ...
},
secondInit: function(name) {
// ...
}
}
It's the first time I've ever seen the call method used in JS and it appears to be exactly the same as just calling the function with brackets, e.g.
this.firstInit(name);
So what is call doing here? Does it act any differently?
When calling
UserWizard.init('some name');
The this object of the firstInit and the secondInit functions will be the string 'some name' and the parameter name value will be undefined
UserWizard.firstInit('some name')
Is the same as:
UserWizard.firstInit.call(UserWizard, 'some name');
Hope I was clear
call() is not doing what you think it's doing here. It's actually changing the context of this within both firstInit and secondInit.
Function.prototype.call() is the link to the mozilla docs, quoting from there there:
A different this object can be assigned when calling an existing function. this refers to the current object, the calling object. With call, you can write a method once and then inherit it in another object, without having to rewrite the method for the new object. - by Mozilla Contributors
There's another function Function.prototype.bind() which I'd encourage you to look at. I find generally I use this more often, but it's a similar sort of idea, used to assign this to the function when it may get called later on. This is good for preventing issues like:
var person = {
name: 'First Last',
getName: function (){
return this.name;
}
};
var getName = person.getName;
getName(); // returns undefined as `this` is the global window object
I am trying to reference this.foo in an object I created, however this is referencing the HTML element that triggered the function. Is there any way that I can preserve the references to this in an object when it is called via an event?
Here is an example of what is going on:
$('document').on('click','button',object.action);
var object = {
foo : null,
action : function(){
this.foo = "something";
}
};
The error I would receive is
Uncaught TypeError: Object #<HTMLInputElement> has no variable 'var'
If you want to preserve this, you should probably attach your event like that:
$('document').on('click','button',function() { object.action() });
Also, if you use this object as it is presented in the question, you may as well use object instead of this:
var object = {
foo : null,
action : function(){
object.foo = "something";
}
};
Also you might want to familiarize yourself with the Bind, Call, and Apply - jQuery uses these behind the scenes to replace your this with HTML Element;
Also, var is a reserved keyword and you should not use it for a property name; if you really want to do that, use a string "var" and access it via [] notation like this:
var a = {"var": 1}
a['var']
var ist reserved word in JavaScript.
This works fine:
$(document).ready(function(){
var myObj = {
myVal: null,
action:function(){
this.myVal = "something";
}
};
myObj.action();
console.log(myObj.myVal);
});
Here link to JS Bin
I hope i could help.
Change this.var to object.var
The problem that this refers to context of where it was called from.
You call object.action from click event on button, so this is #<HTMLInputElement> here.
And, as it was already said, don't use reserved words like var as variable names
You can pass object as the this value using .apply():
$('document').on('click','button',function(){object.action.apply(object); });
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply
Your this should be referencing object but it is not most likely because of the use of var which is a reserved word in JavaScript.
I'm sure I'm missing something obvious here, but I'd expect the argument to the changeMe method to be passed "by reference" - in other words, that changes to the parameter inside the function will change the variable outside the function.
The following was run in jsfiddle, using Chrome's F12 developer tools to show the console output. http://jsfiddle.net/fzEpa/
var object1 = { Property1: 'Value1' };
changeMe(object1);
console.log(object1);
function changeMe(refToObject) {
console.log(refToObject);
refToObject = { Property1: 'Value2' };
console.log(refToObject);
}
It is passed by reference, but it is a reference to the object, not to the object1 variable (which is also a reference to the object).
You are overwriting the reference to the object with a reference to a new object.
This leaves the original reference to the original object intact.
To modify the object, you would do something like this:
function changeMe(refToObject) {
refToObject.Property1 = 'Value2';
}
A reference to the object is passed as the argument value. However:
refToObject = { Property1: 'Value2' };
At this point you lose the reference to the object formerly referenced by refToObject as you're assigning this variable to reference a different object.
Now if you were to edit the refToObject's properties instead of discarding the former object reference, your code would work as exepected (as firstly explained in #Quentin's answer).
If you're familiar with C++ this would be equal to doing something like this:
void f(int* ref) {
ref = new int(3);
}
int* a = new int(5);
f(a);
printf("%d",a); //Prints 5
you are trying to redefine the Property 1,so it wouldnt work. in order to work with pass by reference ypu have to do it this way refToObject.Property1='Value2' inside your ChangeMe() function . refer this for better understanding Pass Variables by Reference in Javascript