This is one of those problems that's been bothering me for a while but I always just worked around it without truly figuring out a proper solution... Apologies if it has been answered before but I couldn't find an answer. If at all possible I'd like to avoid refactoring the object literal pattern.
In the following example, I can't access NS.something and I'm not sure why...
var NS = {
something : 'abc',
init : function(){
NS.doSomething();
},
doSomething : function(){
$('.elements').jqueryPlugin({
pluginParameters: {
NS.something : 'xyz';
}
})
}
};
NS.init();
You cannot define an object literal with a variable key, you have to assign it after definition with [] notation.
doSomething : function(){
var pluginParameters = {};
pluginParameters[NS.property] = 'xyz';
$('.elements').jqueryPlugin({
pluginParameters: pluginParameters
})
}
Related
I was playing an online game named untrusted, which is played by writing code.
There are some syntax that I've never seen before and couldn't find one the web. Can someone explain this to me?
functionList['movePlayerToExit'] = function () {
map.writeStatus("Permission denied.");
}
functionList['pleaseMovePlayerToExit'] = function () {
map.writeStatus("I don't think so.");
}
functionList['movePlayerToExitDamnit'] = function () {
map.writeStatus("So, how 'bout them <LOCAL SPORTS TEAM>?");
}
Please explain the what is functionList, thank you!
And for those who are familiar with this game, please don't spoil, thank you again!
Most people would write
functionList['movePlayerToExit'] = ...
as
functionList.movePlayerToExit = ...
It's just ordinary JavaScript object property reference syntax. Since those strings would be valid if used as identifiers, there's no need to use the [ ] syntax.
Thus, if it's not clear, functionList is an object. Exactly what it means in the code you're looking at, I can't say. It looks like some sort of dispatch object, so that an operation code like "movePlayerToExit" can be looked up and the corresponding function invoked:
var actionCode = getActionCode(totallyMakingThisUp);
if (functionList[actionCode] != null)
functionList[actionCode]();
Note that in that made-up example, it is necessary to use [ ] to access the properties of functionList, because the property name is stored in a variable.
It is probably just an object where functions are assigned to keys (properties):
var obj = {};
obj["foo"] = function () { ... };
obj["bar"] = function () { ... };
Is the same as:
var obj = {
"foo": function () { ... },
"bar": function () { ... }
};
Just like a map.
However, it is possible it is an instance of a class which overrides the square bracket operator such as Array, Map, WeakMap, etc. But that doesn't really define a different behaviour.
I am using jQuery and I am still pretty new to JavaScript. I am implementing an object as the following:
MyObject = {
properties : [{}],
resetProperties: function resetProperties() { this.properties = [{}] }
};
As you can see in the above code I can reset the properties by running MyObject.resetProperties() but, in order to do that, I state two times the [{}] variable. How should I accomplish the same thing without repeating that code?
Update
I tried to do the following:
MyObject = {
properties : this.propertiesDefault,
resetProperties : function resetProperties() { this.properties = [{}] },
propertiesDefault: [{}]
};
but I get "TypeError: invalid 'in' operand MyObject.properties" and I am not sure that is the right way to proceed.
It seems to me that it would be impossible to avoid having your default / reset properties as a separate object to the one that will be modified.
I would recommend having a default value, and cloning it in your initialisation and reset function. Since you tagged your question with jQuery, I assume you are happy to clone the object with that:
MyObject = {
defaultProperties : [{}],
properties : jQuery.extend(true, {}, this.defaultProperties),
resetProperties: function() {
this.properties = jQuery.extend(true, {}, this.defaultProperties);
}
};
See this Stack Overflow question for more information on cloning objects:
What is the most efficient way to deep clone an object in JavaScript?
This is the documentation for jQuery.extend:
http://docs.jquery.com/Utilities/jQuery.extend
From what I know this isn't possible. You're going to have to hard-code the property reset. I tried setting a variable cache outside the object, but when I reset the property it unfortunately maintains its value.
var obj = {
p: [ {} ],
r: function() { this.p = this.cache; }
};
obj.cache = obj.p; // attempt to set to original
obj.p[0].m = 5; // modify
obj.r(); // reset
--------
>>> obj.p[0].m; // 5
We can assume the the cache property is being modified in the same way as p is. Therefore, we can't reset like that.
Depends on what you want. Since you're new to javascript, you may be unfamiliar with using functions to create custom objects, which is the general javascript "OOP" kinda way to do it.
function MyObjectClass() {
this.properties = null;
this.resetProperties();
}
MyObjectClass.prototype.resetProperties = function () { this.properties = [{}] };
var MyObject= new MyObjectClass();
But we don't really know that function MyObject needs to fulfill. There may be a requirement that it NEEDs to be a plain old javascript object. Or maybe not, and you're done.
Of course, you can always directly:
MyObject = {
properties : null,
resetProperties: function () { this.properties = [{}];}
};
MyObject.resetProperties();
I normally in my project create my class in this way... Object literal.
var objectName = {
//global variables
a : 'somevalue',
func1: function(){
},
func2: function(){
}
}
If i have to turn this into prototype format, how would I do that?
What would be my advantage of using prototype than this one, when the job is getting done with this format.
Why do people speak so much on prototype.
Turned into a prototype would look something like:
var someObject = function() {
this.a = "somevalue";
};
someObject.prototype.func1 = function() { // work };
someObject.prototype.func2 = function() { // work };
var myObject = new someObject();
What are some advantages? Well, there are a bunch, but there
are a handful really practical reasons when prototypes make
more sense than object literals.
First is reduction of duplicated code; So, lets say you wanted
another object very smiliar to objectName, but you wanted a to
be a different value. You would probably end up with something like:
var objectName = {
a : 'somevalue',
func1: function(){ },
func2: function(){ }
}
var otherObjectName = {
a : 'otherValue',
func1: function(){ },
func2: function(){ }
}
And you could reduce the duplicated functions by saying
var objectName = {
a : 'somevalue',
func1: function(){ },
func2: function(){ }
}
var otherObjectName = {
a : 'otherValue',
func1: objectName.func1,
func2: objectName.func2
}
Or, using a prototype, I could just make it so I could pass in the value I want for a in during the construction of the object. The refactored code would look something like this:
var someObject = function(a) {
this.a = a;
};
someObject.prototype.func1 = function() { /* work */ };
someObject.prototype.func2 = function() { /* work */ };
var myObject = new someObject("somevalue");
var myOtherObject = new someObject("otherValue");
Now, if i wanted to add a new function to both of them. Using the object literal apporach, then you would have to remember to also add it to otherObjectName. As the number of your literals increased, it would take longer and more difficult to manage them all.
Using the prototype approach, all we would have to say is:
someObject.prototype.func3 = function() { // do even more work }
or even more interesting i could dynamically extend both object by only
having a reference to one by saying.
// find what function made me, get its prototype, and add a new function to it
myObject.constructor.prototype.func3 = function() { /* work */ }
myOtherObject.func3() // tada magic!
or I could make a new object, by only knowing a reference. like:
var newObject = myObject.constructor(myObject.a + " new");
Because both myObject and myOtherObject share the same constructor and prototype, there are a lot of interesting things
you can do with that relationship that you can't do with object literals.
You can think of prototypes as little factories to create objects
rather than having to create every object yourself as a literal.
Now, if you are thinking, "Well, I'm only going to have one
of these and I'm not going to be doing any of your crazy method
extending magic." Then defining an object literals is a perfectly valid apporach
for some problems. Sometimes using a prototype is better. Use the
pattern that makes sense for the problem that you are trying to solve,
rather than trying to fit your problem into a pattern.
I am working on a legacy application and all JS seems mystrious to me.
Here is the few mysterious lines which are loaded before all and I don't have any idea what they are doing.
var i2b2 = {sdx:{TypeControllers:{},Master:{_sysData:{}}},events:{},hive:{cfg:{},helpers:{},base_classes:{}},h:{}};
if (undefined==i2b2.hive) { i2b2.hive = {}; }
i2b2.hive.tempCellsList = [
{ code: "PM",
forceLoading: true
},
{ code: "ONT" },
{ code: "CRC" },
{ code: "WORK"},
{ code: "SHRINE"},
{ code: "PLUGINMGR",
forceLoading: true,
forceConfigMsg: { params: [] }
}
];
There are many more var and if statements but they are doing same thing with different variables.
Please help me to solve this mystery.
The first line initialises i2b2 using nested object literals.
var obj = {}; is a shorter way of writing var obj = new Object();
A simple object literal will be
var simpleObject = {
property1: "Hello",
property2: "MmmMMm",
property3: ["mmm", 2, 3, 6, "kkk"],
method1: function() {
alert("my method")
}
};
A nested one will be
var rectangle = {
upperLeft: {
x: 2,
y: 2
},
lowerRight: {
x: 4,
y: 4
}
};
Yours is a classic.
var i2b2 = {
sdx: {
TypeControllers: {},
Master: {
_sysData: {}
}
},
events: {},
hive: {
cfg: {},
helpers: {},
base_classes: {}
},
h: {}
};
The second line should be IMHO
i2b2.hive = i2b2.hive || {};
This just says that if hive is undefined create a new object.
The last lines create a property tempCellsList to the object hive. ( Please note that hive in turn is a property of i2b2 )
Lastly a new array of objects are added to the property tempCellsList
This javascript code creates a variable called ib2b that has a number of properties: sdx, events, hive, etc. Those properties hold more composite objects, which are constructed below.
The idea is that this global object can be referenced from other javascript code and it stores global configuration for the client-side application.
I'm not quite sure, what exactly you don't understand. There are two "strange" points about the code above, which I'll try to explain, but if that's not enough you will need to describe better what you don't understand:
The code checks is i2b2.hive is is undefined and set it as an empty object, if it is. Since the property is obviously set in the previous line, my guess is that this code is generated dynamically and some of the logic (such as this check) is defined in the JavaScript code even if it could (should?) be the the server side code.
undefined==i2b2.hive is a bad/wrong way to test "undefinedness", because undefined is not a reserved word in JavaScript.This just works, because undefined is just a variable that - by chance - happens to be undefined. Instead one should use if (typeof i2b2.hive == "undefined") ... or just if (i2b2.hive) ....
It seems like it's setting a few parameters in that i2b2 object. It doesn't "do" anything in itself, but it seems to set a few basic configuration settings for further execution. Try and look for similar occurrences in the code further below.
E.g it sets i2b2.hive.tempCellList[5].forceLoading to true. Later on the application probably has if-conditions, such as
for(var i in i2b2.hive.tempCellList)
{
if(i2b2.hive.tempCellList[i].forceLoading === true)
{
// do something...
}
}
Here's a sample of my structure:
this.is.a.really.long.namespace = {
inputs : {},
buttons : {},
panels : {},
fn : {
abc : function() {},
def : function() {}
}
};
Now, as you can see I'm storing my inputs, buttons, panels, and functions in their own respective object literals. The issue lies within fn.abc, fn.def, or any other function inside of page.fn. I want to be able to access my inputs, buttons, and panels from within the functions inside of fn.
Obviously, I know I can type this.is.a.really.long.namespace.inputs, but as you can see, that's pretty long, and I don't want to have to type it out for every single instance where I need to reference an object within the page.
Is there not a way I can directly reference inputs, buttons, and panels from within fn?
I was thinking I could do:
fn : {
that : this.is.a.really.long.namespace,
abc : function() {},
def : function() {}
}
which would allow me to use that.inputs inside of fn.abc, but is there a concern with that method? Any sort of overhead I need to be aware of? Or is there a better way to accomplish this?
There is nothing wrong with this. In fact you are likely to reduce overhead for the following reasons:
Less run-time resolution of object heirarchies
Fewer characters = shorter script
A more fleshed out construct is the commonly used "module pattern."
Javascript is fairly inefficient internally (e.g. it doesn't have real indexed arrays) so anything you can do to reduce run-time lookups is usually good. Creating a pointer to a long heirarchy will be much faster than using the full heirarchy every time. This will probably only matter much in long loops, but since it's also easier to read, it's just a bonus of being a bit faster - there is no downside.
(edit)
to do this with straight objects you could do something like this, using jQuery to
simplify adding properties:
this.is.a.long.namespace = {};
$.extend(this.is.a.long.namespace,
{ that: this.is.a.long.namespace,
... // other properties
});
Generally speaking though if you're building functional objects the module pattern is better, because it's more flexible and lets you use scope to create private variable/objects.
this.is.a.long.namespace = (function()
{
var that = {},
somePrivateVariable;
function privateFunction() {
...
}
that.inputs = {};
...
// assign everything to "that"
return that;
}());
If you build the object in such a way that every level contains a parent parameter pointing to the level above it, then you can access the data that way. Take a look at this similar question.
Ok ... Here's what I ended up doing:
this.is.a.really.long.namespace = {
inputs : { firstName : undefined },
buttons : { submit : undefined },
fn : {
root : undefined,
abc : function() { console.log(this.root.inputs.firstName); },
def : function() { console.log(this.root.buttons.submit); }
},
init : function() {
var self = this,
fn = self.fn,
inputs = self.inputs,
buttons = self.button;
fn.root = this; // this is the key
inputs.firstName = $("#first-name");
buttons.submit = $("#submit-button");
fn.abc();
fn.def();
}
};
I would consider something like this:
var namespace = this.is.a.really.long.namespace
this.is.a.really.long.namespace = {
root : namespace,
inputs : {},
buttons : {},
panels : {},
fn : {
abc : function() {},
def : function() {}
}
};
from there you should have no problems referencing your namespace anywhere within the object.