Given an Array Literal inside a JavaScript Object, accessing its own object's properties does not seem to work:
var closure = {
myPic : document.getElementById('pic1'),
picArray: [this.myPic]
}
alert(closure.picArray[0]); // alerts [undefined]
Whereas declaring an Array Item by accessing an other JavaScript Object seem to work
var closure1 = {
myPic : document.getElementById('pic1')
}
var closure2 = {
picArray: [closure1.myPic]
}
alert(closure2.picArray[0]); // alerts [object HTMLDivElement]
Example:
http://jsfiddle.net/5pmDG/
The this value will not work like that, it refers to a value determined by the actual execution context, not to your object literal.
If you declare a function member of your object for example, you could get the desired result:
var closure = {
myPic: document.getElementById('pic1'),
getPicArray: function () {
return [this.myPic];
}
};
//...
closure.getPicArray();
Since the this value, inside the getPicArray function, will refer to your closure object.
See this answer to another question, where I explain the behavior of the this keyword.
Edit: In response to your comment, in the example that I've provided, the getPicArray method will generate a new Array object each time it is invoked, and since you are wanting to store the array and make changes to it, I would recommend you something like this, construct your object in two steps:
var closure = {
myPic: document.getElementById('pic1')
};
closure.picArray = [closure.myPic];
Then you can modify the closure.picArray member without problems.
The this property does not point to the closure object. If we were to define the myPic property on the global scope, then you will see picArray initialized with that value. Consider this example:
<script>
window.myPic = "Global myPic";
var closure = {
myPic : document.getElementById('pic1'),
picArray: [this.myPic] // this refers to the global object
};
console.log(closure.picArray); // ["Global myPic"];
</script>
this is one of the hardest concepts in JavaScript. You might like this article on the topic.
Related
I am new to JS so bear with me.
What is the difference between
function get (attr) {
return function (object) { return object[attr]; }
}
and
function get (attr) {
return object[attr];
}
Why the first function worked but second did not? could not find a logical explanation for this.
Working Example code: https://jsfiddle.net/xf2u0ncL/
In your second code, where does object come from?! That's the entire problem.
The first code is used like this:
// same as getter = function (object) { return object['foo']; }
var getter = get('foo');
var value = getter({ foo: 'bar' });
get accepts a property name and returns a function which accepts an object and returns the value. Your second function doesn't accept any object at any point, so what's it supposed to return?
Looks like you've got a method where your trying to return a property of an object.
Both methods above will work but expect variables in different scopes and will be executed differently.
the first method returns a second method where you pass it an object to get the property from. So
get('foo')({foo: 'bar'}); //returns 'bar'
Whereas the second works like this
var object = {
foo: 'bar'
}
get('foo'); //returns 'bar';
the second excepts object to be a global variable or at least in a higher scope as it is not defined in the function it self.
the first method is passed an object to search for a property from. The first, whilst a little convoluted would be better and more easily tested than the second which expects and relies on global variables.
see fiddle: http://jsfiddle.net/b327nr74/
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 want to create an object such that object.a is an array while object.b is the length of it and this is what I have:
var object = {
a:[1,2,3,2],
b: this.a.length
}
alert(b);
But this won't alert 4. There is something wrong with b: this.a.length:
Uncaught TypeError: Cannot read property 'length' of undefined
I'd be glad if someone can explain to me why this is happening.
It would actaully alert 4 if I write it this way:
var object = {
a:[1,2,3,2]
}
alert(object.a.length);
[update] even create the object this way, it doesn't work:
var object = {
a:[1,2,3,2],
b:object.a.length
}
The main problem is that in javascript data declaration like your first example, the value of this is not set to the object being defined. So since this is not your object, this.a inside the object declaration does not refer to the a property of your object.
It is whatever it was in the context right before your data declaration. If that was the global context, then this would be the window object and this.a probably doesn't exist. If it doesn't exist (e.g. it's undefined), then when you try to reference this.a.length, you are trying to read the property .length off something isn't an object and that is a javscript error.
As for solving this problem it is generally a bad idea to copy the length of an array to another property. That just gives you a chance for it to be wrong and out-of-sync with the actual length of the array. If you want the length of the array, you should just retrieve it upon demand with:
object.a.length
If you really want it to be a property (that has a fixed value and doesn't change when a changes), you can set it after you create the object:
var object = {
a:[1,2,3,2],
};
object.b = object.a.length;
alert(object.b);
all properties of an object are instantiated at once, so this refers to the window object when creating the property b. You'd need to defer the interpretation of b's value, one way is to use a function instead:
var object = {
a:[1,2,3,2],
b: function () {
return this.a.length;
}
}
Another way is to add the property b after the object literal has been declared:
var object = {
a:[1,2,3,2]
}
object.b = object.a.length;
Finally, on newer browsers you can take advantage of a getter:
var object = {
a:[1,2,3,2],
get b() {
return this.a.length;
}
}
In the first example 'b' is undefined, because it is looking for a variable named 'b' not the property 'b' inside of the object 'object'. You should use object.b instead.
Add b to the object after creating it:
var object = {
a:[1,2,3,2]
}
object.b = object.a.length
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();
I have some properties in an object that I would like to add to the global namespace. In javascript on the browser I could just add it to the window object like so:
var myObject = {
foo : function() {
alert("hi");
}
// and many more properties
};
for (property in myObject) {
window[property] = myObject[property];
}
// now I can just call foo()
foo();
But since rhino doesn't have the global window object I can't do that. Is there an equivalent object or some other way to accomplish this?
I found a rather brilliant solution at NCZOnline:
function getGlobal(){
return (function(){
return this;
}).call(null);
}
The key to this function is that the this object always points to the global object anytime you are using call() or apply() and pass in null as the first argument. Since a null scope is not valid, the interpreter inserts the global object. The function uses an inner function to assure that the scope is always correct.
Call using:
var glob = getGlobal();
glob will then return [object global] in Rhino.
You could use this, which refers to the global object if the current function is not called as a method of an object.
Here's how I've done it in the past:
// Rhino setup
Context jsContext = Context.enter();
Scriptable globalScope = jsContext.initStandardObjects();
// Define global variable
Object globalVarValue = "my value";
globalScope.put("globalVarName", globalScope, globalVarValue);
You could just define your own window object as a top-level variable:
var window = {};
You can then assign values to it as you please. ("window" probably isn't the best variable name in this situation, though.)
See also: Can I create a 'window' object for javascript running in the Java6 Rhino Script Engine
I've not used rhino but couldn't you just use var?
i.e.
var foo = myObject.foo;
foo();
Edit:
Damn knew there'd be a catch! Miles' suggestion would be the go in that case.