Searching for an instance of a custom object - javascript

I want to check if my javascript object is of a certain type.
I have an object (I cannot edit this object.) and I have made instances of that object. Now I want to loop through all the objects that are available at any given point and figure out which ones are the instances that I am looking for.
Example:
var myObject = function() { };
var obj_person = new myObject();
Now if I write
typeof obj_person
It gives me object which is not useful. I cannot use instanceof as it does not work in IE8.
Is there anyway to check if obj_person is an instance of myObject?
Thanks.
EDITED***
Here is the code
var arr_instances = [];
for(var v in window)
{
var obj_required;
if(typeof window[v] == 'object')
{
obj_required = window[v];
if(obj_required.imgSrc)
{
arr_instances.push(obj_required);
}
}
}
Then I can iterate withing arr_instance and do whatever I want to do.
for(var i=0; i<arr_instances.len; i++)
{
if(arr_instances[i].imgSrc == 'requiredImg.jpg')
{
arr_instances[i].imgSrc = 'newImg.jpg';
}
}

Related

Referencing an object through a variable in JavaScript

I've defined the methods "checkThreshold" and "checkOtherObject" in my prototype. checkOtherObject iterates across objects listed in attribute "nextDev" and is supposed to invoke checkThreshold for each object, thus:
// Protoype
function foo(otherObject) {
// attributes
this.nextDev=otherObject; // comma-delimited list of objects
// Method that references another method
this.checkOtherObject= function() {
successorList=this.nextDev.split(",");
for (var i=0; i<successorList.length;i++) {
successorList[i]['checkThreshold']();
}
}
// Method referenced by checkOtherObject
this.checkThreshold = function () {
<Do Stuff>
}
//Instantiations
var A = new foo ("B");
var B = new foo ("");
Thus, expected behavior is that A.checkOtherObject would invoke B.checkThreshold, but when I get to that line, B.checkThreshold isn't invoked. What am I doing wrong?
The root problem: you're trying to assign value of instances in theirselves. Note: what you're doing is still wrong, otherObject is a object, but it's a String object and it's not referring to the current foo's instance (this).
this.nextDev = otherObject
Other problem is that you're calling String().checkThreshold, but not foo().checkThreshold. You can check that at your statements:
successorList = this.nextDev.split(",");
for (var i = 0; i < successorList.length; i++) {
successorList[i]['checkThreshold']();
}
As you can see you're iterating string literals. String().split returns a object with string literals back, not a list with foo()'s.
/* confirm that the successorList is a array object */
successorList instanceof Array; // true
/* confirm that the first successorList's item is a string object */
typeof successorList[0] === "string"; // true
I'm basically not sure about what's your objective. It looks like you've a extra-ordinary giant confusion between String objects and objects. Maybe you want to store nextDev out of foo(), and at nextDev you want to store a Array object containing instances of foo? Then try:
var devs = [];
function foo(string) {
devs.push(this);
}
foo.prototype = {
checkOtherObjects: function() {
var me = this;
var myIndex;
var i = 0, len = devs.length;
for (; i < len; ++i) {
if (devs[i] === me) {
myIndex = i;
break;
}
}
for (i = myIndex + 1; i < len; ++i)
devs[i].checkThresold()
}
};
To offer a bit of a better explanation - yes, you CAN use window[successorList[i]], however, that is highly, highly not recommended, and here's why:
This becomes an issue if the variables no longer in the global scope. For example, if you place the code inside of a function, including an IIFE or a document ready function, you can no longer reference your variables from the window object, unless you were to declare them with window.A, window.B, but declaring global variables like that can get so messy, especially when working with other libraries/plugins.
So...how can you work around these issues? Simple - pass the object itself as #Bergi mentioned instead of passing the string that contains the name of the variable.
Here's what the code would look like:
// Protoype
function foo(otherObject) {
this.nextDev = otherObject || [];
// Method that references another method
this.checkOtherObject = function() {
this.nextDev.forEach(function(obj, index) {
obj.checkThreshold();
});
};
// Method referenced by checkOtherObject
this.checkThreshold = function() {
// Do Stuff
console.log("Checking Threshold for: ", this);
};
}
//Instantiations
var B = new foo(null);
var A = new foo([B]); //or [B, C, D, E, ...]
A.checkOtherObject();

How to stringify inherited objects to JSON?

json2.js seems to ignore members of the parent object when using JSON.stringify(). Example:
require('./json2.js');
function WorldObject(type) {
this.position = 4;
}
function Actor(val) {
this.someVal = 50;
}
Actor.prototype = new WorldObject();
var a = new Actor(2);
console.log(a.position);
console.log(JSON.stringify(a));
The output is:
4
{"someVal":50}
I would expect this output:
4
{"position":0, "someVal":50}
Well that's just the way it is, JSON.stringify does not preserve any of the not-owned properties of the object. You can have a look at an interesting discussion about other drawbacks and possible workarounds here.
Also note that the author has not only documented the problems, but also written a library called HydrateJS that might help you.
The problem is a little bit deeper than it seems at the first sight. Even if a would really stringify to {"position":0, "someVal":50}, then parsing it later would create an object that has the desired properties, but is neither an instance of Actor, nor has it a prototype link to the WorldObject (after all, the parse method doesn't have this info, so it can't possibly restore it that way).
To preserve the prototype chain, clever tricks are necessary (like those used in HydrateJS). If this is not what you are aiming for, maybe you just need to "flatten" the object before stringifying it. To do that, you could e.g. iterate all the properties of the object, regardless of whether they are own or not and re-assign them (this will ensure they get defined on the object itself instead of just inherited from the prototype).
function flatten(obj) {
var result = Object.create(obj);
for(var key in result) {
result[key] = result[key];
}
return result;
}
The way the function is written it doesn't mutate the original object. So using
console.log(JSON.stringify(flatten(a)));
you'll get the output you want and a will stay the same.
Another option would be to define a toJSON method in the object prototype you want to serialize:
function Test(){}
Test.prototype = {
someProperty: "some value",
toJSON: function() {
var tmp = {};
for(var key in this) {
if(typeof this[key] !== 'function')
tmp[key] = this[key];
}
return tmp;
}
};
var t = new Test;
JSON.stringify(t); // returns "{"someProperty" : "some value"}"
This works since JSON.stringify searches for a toJSON method in the object it receives, before trying the native serialization.
Check this fiddle: http://jsfiddle.net/AEGYG/
You can flat-stringify the object using this function:
function flatStringify(x) {
for(var i in x) {
if(!x.hasOwnProperty(i)) {
// weird as it might seem, this actually does the trick! - adds parent property to self
x[i] = x[i];
}
}
return JSON.stringify(x);
}
Here is a recursive version of the snippet #TomasVana included in his answer, in case there is inheritance in multiple levels of your object tree:
var flatten = function(obj) {
if (obj === null) {
return null;
}
if (Array.isArray(obj)) {
var newObj = [];
for (var i = 0; i < obj.length; i++) {
if (typeof obj[i] === 'object') {
newObj.push(flatten(obj[i]));
}
else {
newObj.push(obj[i]);
}
}
return newObj;
}
var result = Object.create(obj);
for(var key in result) {
if (typeof result[key] === 'object') {
result[key] = flatten(result[key]);
}
else {
result[key] = result[key];
}
}
return result;
}
And it keeps arrays as arrays. Call it the same way:
console.log(JSON.stringify(flatten(visualDataViews)));
While the flatten approach in general works, the snippets in other answers posted so far don't work for properties that are not modifiable, for example if the prototype has been frozen. To handle this case, you would need to create a new object and assign the properties to this new object. Since you're just stringifying the resulting object, object identity and other JavaScript internals probably don't matter, so it's perfectly fine to return a new object. This approach is also arguably more readable than reassigning an object's properties to itself, since it doesn't look like a no-op:
function flatten(obj) {
var ret = {};
for (var i in obj) {
ret[i] = obj[i];
}
return ret;
}
JSON.stringify takes three options
JSON.stringify(value[, replacer[, space]])
So, make use of the replacer, which is a function, that is called recursively for every key-value-pair.
Next Problem, to get really everything, you need to follow the prototpes and you must use getOwnPropertyNames to get all property names (more than you can catch with keysor for…in):
var getAllPropertyNames = () => {
const seen = new WeakSet();
return (obj) => {
let props = [];
do {
if (seen.has(obj)) return [];
seen.add(obj);
Object.getOwnPropertyNames(obj).forEach((prop) => {
if (props.indexOf(prop) === -1) props.push(prop);
});
} while ((obj = Object.getPrototypeOf(obj)));
return props;
};
};
var flatten = () => {
const seen = new WeakSet();
const getPropertyNames = getAllPropertyNames();
return (key, value) => {
if (value !== null && typeof value === "object") {
if (seen.has(value)) return;
seen.add(value);
let result = {};
getPropertyNames(value).forEach((k) => (result[k] = value[k]));
return result;
}
return value;
};
};
Then flatten the object to JSON:
JSON.stringify(myValue, flatten());
Notes:
I had a case where value was null, but typeof value was "object"
Circular references must bee detected, so it needs seen

Can you use custom objects as properties of an object in javascript?

Suppose I create a custom object/javascript "class" (airquotes) as follows:
// Constructor
function CustomObject(stringParam) {
var privateProperty = stringParam;
// Accessor
this.privilegedGetMethod = function() {
return privateProperty;
}
// Mutator
this.privilegedSetMethod = function(newStringParam) {
privateProperty = newStringParam;
}
}
Then I want to make a list of those custom objects where I can easily add or remove things from that list. I decide to use objects as a way to store the list of custom objects, so I can add custom objects to the list with
var customObjectInstance1 = new CustomObject('someString');
var customObjectInstance2 = new CustomObject('someOtherString');
var customObjectInstance3 = new CustomObject('yetAnotherString');
myListOfCustomObjects[customObjectInstance1] = true;
myListOfCustomObjects[customObjectInstance2] = true;
myListOfCustomObjects[customObjectInstance3] = true;
and remove custom objects from the list with
delete myListOfCustomObjects[customObjectInstance1];
but if i try to iterate through the list with
for (i in myListOfCustomObjects) {
alert(i.privilegedGetMethod());
}
I would get an error in the FireBug console that says "i.privilegedGetMethod() is not a function". Is there a way to fix this problem or an idiom in javascript to do what I want? Sorry if this is a dumb question, but I'm new to javascript and have scoured the internet for solutions to my problem with no avail. Any help would be appreciated!
P.S. I realize that my example is super simplified, and I can just make the privateProperty public using this.property or something, but then i would still get undefined in the alert, and I would like to keep it encapsulated.
i won't be the original object as you were expecting:
for (i in myListOfCustomObjects) {
alert(typeof i); // "string"
}
This is because all keys in JavaScript are Strings. Any attempt to use another type as a key will first be serialized by toString().
If the result of toString() isn't somehow unique for each instance, they will all be the same key:
function MyClass() { }
var obj = {};
var k1 = new MyClass();
var k2 = new MyClass();
obj[k1] = {};
obj[k2] = {};
// only 1 "[object Object]" key was created, not 2 object keys
for (var key in obj) {
alert(key);
}
To make them unique, define a custom toString:
function CustomObject(stringParam) {
/* snip */
this.toString = function () {
return 'CustomObject ' + stringParam;
};
}
var obj = {};
var k1 = new CustomObject('key1');
var k2 = new CustomObject('key2');
obj[k1] = {};
obj[k2] = {};
// "CustomObject key1" then "CustomObject key2"
for (var key in obj) {
alert(key);
}
[Edit]
With a custom toString, you can set the object as the serialized key and the value to keep them organized and still continue to access them:
var customObjectInstance1 = new CustomObject('someString');
var customObjectInstance2 = new CustomObject('someOtherString');
var customObjectInstance3 = new CustomObject('yetAnotherString');
myListOfCustomObjects[customObjectInstance1] = customObjectInstance1;
myListOfCustomObjects[customObjectInstance2] = customObjectInstance2;
myListOfCustomObjects[customObjectInstance3] = customObjectInstance3;
for (i in myListOfCustomObjects) {
alert(myListOfCustomObjects[i].privilegedGetMethod());
}
The for iteration variable is just the index, not the object itself. So use:
for (i in myListOfCustomObjects) {
alert(myListOfCustomObjects[i].privilegedGetMethod());
}
and, in my opinion, if you use an Object as an array index / hash, it just would be converted to the string "Object", which ends up in a list with a single entry, because all the keys are the same ("Object").
myListOfCustomObjects =[
new CustomObject('someString'),
new CustomObject('someOtherString'),
new CustomObject('yetAnotherString')
]
you will get access to any element by index of array.

Javascript - Reflecting encapsulated members

I created a javascript "class" as follows:
function MyClass(member1, member2) {
this.Member1 = member1;
this.Member2 = member2;
}
All members are Strings.
I want to take an instance of MyClass and "clean" the members by calling
function NoneBecomesNull(item) {
if (item === "[None]")
item = "";
return item;
}
for-each member of the class. Is there an effecient way to accomplish this task? (In the case where MyClass has 30 members).
I would like to avoid doing...
myClassInstance.Member1 = NoneBecomesNull(myClassInstance.Member1);
myClassInstance.Member2 = NoneBecomesNull(myClassInstance.Member2);
//...30+ times
Try the following
for (var name in theObject) {
if (theObject.hasOwnProperty(name) && theObject[name] === "[None]") {
theObject[name] = "";
}
}
I used hasOwnProperty to prevent the reseting of properties higher up in the prototype chain. Your example didn't show the use of a prototype chain here and hence it's likely not necessary for this example. But it's good practice.
Why not encapsulate this behaviour inside your object?
WORKING EXAMPLE
function MyClass(member1, member2) {
this.Member1 = member1;
this.Member2 = member2;
this.clean = function() {
for ( var member in this ) {
if (this.hasOwnProperty(member) && this[member] === "[None]") {
this[member] = "";
}
}
};
}
Then it only takes one line to accomplish...
var obj = new MyClass("[None]", "hello");
obj.clean();

Do I have to initialize every level of an object in Javascript?

I'm not terribly good with Javascript so I'm wondering if there is a better way of doing this:
if (games[level] === undefined) {
games[level] = {};
games[level]['pending'] = {};
}
if (!games[level]['pending'].length) {
return game.create(level);
}
In PHP I can just test empty($games[$level]['pending']). Is there a better way of testing for this? Basically all I want to do is create the object if it does not exist.
if (games[level] === undefined) {
games[level] = game.create(level);
}
If there is no such level game create should be called to initialize all of the data needed. I don`t see any point of making it an object and then checking for "pending". It will be always empty, because you just created the object.
If your the second if returns something for games[level]['pending'].length you have a big problem with your code. You can`t create an empty object ( games[level]['pending'] = {} ) and find that it already has properties.
In addition:
games[level] = {};
// games[level]['pending'] = {}; - bad
games[level].pending = {}; // this way object properties should be used
you can make yourself a function to do that, pass it the games object a a string like "level.pending.id.something.something" and goes on and creates the objects.
function makeObj(obj, path) {
var parts = path.split("."), tmp = obj, name;
while (parts.length) {
name = parts.shift();
if (typeof tmp[name] === 'undefined') {
tmp[name] = {};
}
tmp = tmp[name];
}
}
var x = {};
makeObj(x, "this.is.a.test");
games[level] = games[level] || {pending: {}};
if (!games[level].pending.length) {
return game.create(level);
}

Categories

Resources