I've create a namespace like the one below.
var Constants = {
Foo: 'bar',
SomeVar: {
key: 'value'
}
};
What I want to do is:
var Constants = {
Foo: 'bar',
SomeVar: {
key: Constants.Foo + 'value' // Notice the Constants.Foo
}
};
What I want to do is be able to use the value of Constants.Foo to create a value for SomeVar. However this throws an error in Firebug.
So I'm wondering, how do I access the value of Foo inside the Constants namespace; and also, I've been reading a few articles on encapsulation in Javascript (like this one), is it possible to access value of Foo without having to do Constants.Foo? Perhaps some sort of way to preserve a reference to the namespace's this keyword and then I can do something like thisParent.Foo.
Thanks!
EDIT:
This is the error I'm getting by the way:
TypeError: Constants is undefined
That's not possible. An object literal doesn’t have a name until you assign it to something, and by then, it’s too late. Object literals aren't functions, either, so there’s no contextual keyword you could use; this would still be whatever it was in the containing function. Adding the property afterwards is the only way.
var Constants = {
Foo: 'bar',
SomeVar: {}
};
Constants.SomeVar.key = Constants.Foo + 'value';
And no, a namespace is not a thing in JavaScript. That is an object. Nothing more.
The problem is that Constants doesn't exist until the assignment is executed, which is after the object is constructed. You could do something like this (an IIFE):
var Constants = (function() {
self = { Foo : 'bar' };
self.SomeVar = self.Foo + 'value';
return self;
}());
Related
I'm trying to "reverse-engineer" JS code of one of my favorite web game. I'm not beginner in web developing, but JS is not my strength (nor english, sorry), I'm more backend programmer.
The code is full of such "objects":
var Foo = {
prop: {...},
prop2: [...],
bar: function(val) {
this.prop.k = val;
Foo.doSomething();
},
doSomething: function() {
var my = Foo.prop;
...
return this.prop2;
},
};
...somehere on the page...
<input type="text" name="in" value="Pretty text" onclick="Foo.bar(this.value)" />
As far as I understand it, it's object Foo made from anonymous class, making it somewhat static. But I'm very confused by using this and Foo as object name. It seems to me randomly used, one or another. It's not related to properties or functions, both are used both ways. Even in the same method is used both. I think, that in this case are this and Foo the same. When I try to make such an objects and dump them in console, this and Foo returns the same.
Can anyone explain to me, where can be a difference, please? Or can it be just something lost in translation, because original code is minified?
Thanks.
var x = {
something: 'something',
log: function() {
return this.something
},
log2: function() {
return x.something
}
}
If you run the above code, you can see that the log() method and log2() method both return the same result. Which concludes that this and x refers to the same object in this scenario. Yours might be the same case if I'm not wrong.
Here are some cases when this and the name of the object are not referring the same object.
let Foo = {
prop: 'a',
log() {
console.log(
'this.prop is', this.prop, ', Foo.prop is', Foo.prop
);
}
},
Bar = {
prop: 'b',
mock: Foo.log
},
Baz = Object.create(Foo, {
prop: {
value: 'c'
}
});
Foo.log();
Bar.mock();
Baz.log();
// You can also bind the this reference when calling
Bar.mock.call(Baz);
Baz.log.apply(Bar);
In Baz case, the original Foo.prop preserves its value, since setting a property with the same name in an instance makes it an own property of that instance, the value of the property in the prototype is not overridden.
All of these scenarios help you to reuse already written code, hence reducing the code. Whether this was a goal in your favorite web game or not is not known, when reading the short examples only. With the given code, there's no difference.
I want to add a method to the prototype of an inner class. Is that possible?
This is what I tried:
var Foo = function Foo() {};
Foo.prototype = {
Bar: function Bar() { },
Bar.prototype: { // <- this does not work
barMethod: function () {
console.log('hello');
}
},
fooMethod: function () {
var bar = new this.Bar();
bar.barMethod();
}
}
var foo = new Foo();
foo.fooMethod();
But Bar.prototype doesn't work, it throws a SyntaxError with the message Unexpected token ..
Your problem is that you're defining the Foo.prototype object, and as such, you're bound to the rules and syntax of object creation, for example the parser expects you to list the attributes in a key: value, nextkey: nextvalue format, which Bar.prototype does not fit. (Keys are effectively strings, and it doesn't make sense to use . in them, as they would create ambiguity while parsing*)
Try this:
var Foo = function Foo() {};
Foo.prototype.Bar = function Bar() { };
Foo.prototype.Bar.prototype = {
barMethod: function () {
console.log('hello');
}
};
There's a slight semantic difference though, as this way you're not overriding the prototype, just extending it. (consider equaling it to {} first, then extending it with every attribute of the object you tried to create)
(*) A note on ambiguity: I mention above that having a . in your object key would create ambiguity, here's a simple example:
var foo = {
bar: {
baz: 0,
qux: 20
},
bar.baz: 150 //note that this will throw an error
};
console.log(foo.bar.baz);
If this code above wouldn't throw an error, what would you expect console.log(foo.bar.baz) to print, 0 or 150?
That's why it doesn't make sense to use . in a key, and that's why the parser throws the unexpected token error on any ..
Of course, you could use the "bar.baz" string as a key as "bar.baz": 150 above (please don't!), but then you'd have to reference the value as
foo["bar.baz"]
which would be distinctly different from
foo.bar.baz;
All in all, this is just some intuition-based reasoning behind why you can't use a . in your keys, but the real reason is plainly this: because the parser will throw an error.
In an object literal you can only define properties of that object literal, but not properties of the values.
However, if you want to set the prototype when creating the object, consider Object.assign (which can be polyfilled):
Foo.prototype = {
Bar: Object.assign(function Bar() { }, {
prototype: {
barMethod: function () {
console.log('hello');
}
}
}),
fooMethod: function () {
var bar = new this.Bar();
bar.barMethod();
}
};
However, note that replacing all the prototype is a bad practice because you erase the constructor property.
Look at the code below
var foo = function(){
prop1 : "value";
}
foo.prop2 = "value";
console.log("prop1" in foo) // logs flase
console.log("prop2" in foo) // logs true
Why can't we add properties to a function object like we do in an object literal? Why had I to declare the property for the function object outside its body? Is there a different syntax to add properties to a function object directly in its body.
That's because the grammar of functions in javascript doesn't allow for it. What you need is just a plain object.
Is there a different syntax to add properties to a function object
directly in its body.
Yes. There is. And it's called a constructor function.
function Foo(){
this.prop1 = "value";
}
var obj = new Foo();
console.log(obj.prop1);
Are you using something akin to CoffeeScript? You forgot the {} on the object.
First I suggest you return a proper object:
var foo = function(){
{ prop1 : "value" };
}
Still it won't work. It will result in:
foo.prop2 = "value2";
{ [Function] prop2: 'value2' }
foo() will return
{ prop1: 'value' }
foo.prop2 will return value2
The reason it doesn't work is because you're adding to the instance. Not to the function body (You can't change the code, just the objects.).
A better solution would be:
var newFoo = foo()
{ prop1: 'value' }
newFoo.prop2 = "value2";
{ prop1: 'value', prop2: 'value2' }
As we've seen, you CAN modify the function, but you can't modify it's return statement, because it would require the software rewriting the function and we're not quite skynet... Yet. ;D
Another interesting way of modifying stuff is prototyping:
Function.prototype.prop2 = "value2"
foo()
{ prop1: 'value' }
foo.prop2
'value2'
But seeing as Function.prototype will make EVERY FUNCTION gain the .prop2 property, it wouldn't make much sense in this case.
Because you have used a semi colon. You do it using a comma.
Correct usage would be:
var foo = {
prop1 : "value",
prop2 : "value"
}
When making objects I assumed that this would return the object's instance - instead it seems it's something else. Why is this?
var Obj = {
foo : 'value',
bar : function() { return this.foo; } // Error
bar : function() { return Obj.foo; } // Works
}
Update: I must be missing something because in some cases using this inside objects doesn't work. How come this only references the object instance sometimes?
It does. You have a syntax issue.
Use commas to delimit object members
var Obj = {
foo : 'value',
bar : function() { return this.foo; },
}
within member functions this refers to a reference to the object that the function is called on.
jsFiddle Example
Within a JavaScript function this is set depending on how the function was called.
With your example Obj, assuming you correct the syntax error and use commas between properties:
var Obj = {
foo : 'value', // needs comma, not semicolon
bar : function() { return this.foo; }
}
If you use the "dot" syntax on Obj to call the bar function then this will be automatically set to Obj:
Obj.bar(); // this will be Obj
That's an easy way to ensure this ends up set the way you want. But if you call the function in some other way this could be set to something else:
var nonObjBar = Obj.bar; // get a reference to the function
nonObjBar(); // this will (probably) be `window`, but depends if
// in strict mode or inside some other function, etc
var Obj2 = { foo: "other foo" };
Obj.bar.call(Obj2); // the .call() method sets this to Obj2
// so bar will return Obj2's foo, "other foo"
That last example uses the .call() method on Obj.bar to invoke the function in a way that allows you to set this to anything you like (strict versus non-strict mode affects the way this works for some cases).
It might seem strange if you're coming from languages like Java, but JavaScript functions don't belong to any given object. This behaviour is pretty well defined and on purpose.
After fixing the semi-colon after 'value', this seems to work:
var Obj = {
foo : 'value',
bar : function() { return this.foo; } // Error
};
alert(Obj.bar()); // alerts 'value'
See working jsFiddle here: http://jsfiddle.net/jfriend00/UFPFf/.
When you call a method on an object, the javascript engine sets the this pointer to point to the object for the duration of the method call.
You shouldn't have a semicolon after foo.
Actually when you call Obj.bar you will have this referring to Obj.
See http://jsfiddle.net/AAkbR/
var Obj = {
foo : 'value',
bar : function () { return this.foo; }
};
alert(Obj.bar() === Obj.foo);
Alerts true.
If I set a function to Object.prototype, and try to call the function from object Foo, is there a way for the function to know what object originally called it?
Object.prototype.MyFunc = function () {
console.log("I was called by " + (//object name here...));
}
Foo = {};
Foo.MyFunc();
Thanks!
AFAIK it's impossible because objects are objects, multiple variables can refer to the same object, no variable name is stored on the object unless done explicitly.
You can of course refer to the object at hand with this but you can't get the variable unless you did something like..
Object.prototype.alertName = function() {
alert( this.name )
}
var names = [
{name:'John'}
];
names[0].alertName()
As far as I know, it’s not possible to get the actual object name (i.e. var name).
You can however refer to the object the function was invoked upon by using this.
Object.prototype.MyFunc = function() {
this.foo = 'bar';
}
MyObject = {};
MyObject.MyFunc();
MyObject; // Object { foo = 'bar' }