Let´s assume I have an object property which is passed into a function. In this case 'name' is filled with 'myObject.name' (which has the value 'Tom') - so basically 'Tom' gets passed into the function as the 'name'
function(name) {
do something //non-essential for my question
}
Is it possible to get the object, where 'Tom' is the property of, just by having the information 'Tom'? Basically I´m looking to get myObject.
Thanks :)
No, that's not possible.
All that the function knows is that one of its parameters was pointed to the string "Tom", not what else points to that string somewhere else in memory.
You can store objects within an array, filter the array to match property name of object to parameter passed to function using for..of loop, Object.entries(), which returns an array of property, values of an object.
const data = Array();
const setObjectPropertyName = _name => {
data.push({[_name]:_name});
return data
}
const getObjectByPropertyName = prop => {
let res = `${prop} property not found in data`;
for (let obj of data) {
for (let [key] of Object.entries(obj)) {
if(key === prop) return obj;
}
}
return res;
}
let s = setObjectPropertyName("Tom");
let g = getObjectByPropertyName("Tom");
let not = getObjectByPropertyName("Tome");
console.log(s,"\n", g, "\n", not);
Disclaimer: you absolutely should not do this. I'm only posting this because it is in fact possible (with some caveats), just really not advisable.
Going on the assumption that this is running in the browser and it's all running in the global scope (like in a script tag), you could technically iterate over the window object, check any objects in window for a name property and determine if their name property matches the name passed to your function.
var myObject = {
name: 'Tom',
thisIs: 'so awful',
imSorry: true,
};
function doSomethingWithName(name) {
for (var obj in window) {
var tmp = window[obj];
if (Object(tmp) === tmp && tmp.name === name) {
return tmp;
}
}
}
console.log(doSomethingWithName(myObject.name));
Is there a way to find out all user defined window properties and variables (global variables) in javascript?
I tried console.log(window) but the list is endless.
You could also compare the window against a clean version of the window instead of trying to snapshot during runtime to compare against. I ran this in console but, you could turn it into a function.
// make sure it doesn't count my own properties
(function () {
var results, currentWindow,
// create an iframe and append to body to load a clean window object
iframe = document.createElement('iframe');
iframe.style.display = 'none';
document.body.appendChild(iframe);
// get the current list of properties on window
currentWindow = Object.getOwnPropertyNames(window);
// filter the list against the properties that exist in the clean window
results = currentWindow.filter(function(prop) {
return !iframe.contentWindow.hasOwnProperty(prop);
});
// log an array of properties that are different
console.log(results);
document.body.removeChild(iframe);
}());
This is in the same spirit as #jungy 's answer but we can do it in 3 lines:
document.body.appendChild(document.createElement('div')).innerHTML='<iframe id="temoin" style="display:none"></iframe>';
for (a in window) if (!(a in window.frames[window.frames.length-1])) console.log(a, window[a])
document.body.removeChild($$('#temoin')[0].parentNode);
First we add a hidden iframe; then we test existing variables against the standard JavaScript API in the iframe; then we remove the iframe.
To work more conveniently, it could be useful to sort the results in alphabetical order, and it's still possible in a 3 lines version:
document.body.appendChild(document.createElement('div')).innerHTML='<iframe id="temoin" style="display:none"></iframe>';
Object.keys(window).filter(a => !(a in window.frames[window.frames.length-1])).sort().forEach((a,i) => console.log(i, a, window[a]));
document.body.removeChild($$('#temoin')[0].parentNode);
And it can be packed into a bookmark:
javascript:document.body.appendChild(document.createElement('div')).innerHTML='<iframe%20id="temoin"%20style="display:none"></iframe>';Object.keys(window).filter(a=>!(a%20in%20window.frames[window.frames.length-1])).sort().forEach((a,i)=>console.log(i,a,window[a]));document.body.removeChild(document.querySelectorAll('#temoin')[0].parentNode);throw 'done';
You would need to do the work for yourself. Read in all properties, on the first possible time you can. From that point on, you can compare the property list with your static one.
var globalProps = [ ];
function readGlobalProps() {
globalProps = Object.getOwnPropertyNames( window );
}
function findNewEntries() {
var currentPropList = Object.getOwnPropertyNames( window );
return currentPropList.filter( findDuplicate );
function findDuplicate( propName ) {
return globalProps.indexOf( propName ) === -1;
}
}
So now, we could go like
// on init
readGlobalProps(); // store current properties on global object
and later
window.foobar = 42;
findNewEntries(); // returns an array of new properties, in this case ['foobar']
Of course, the caveat here is, that you can only "freeze" the global property list at the time where your script is able to call it the earliest time.
I ran this in the console in ChromeDev tool and it copied all of the user defined proper
const getUserDefinedKeys = () => {
const globalKeys = [ 'postMessage','blur','focus','close','parent','opener','top','length','frames','closed','location','self','window','document','name','customElements','history','locationbar','menubar','personalbar','scrollbars','statusbar','toolbar','status','frameElement','navigator','origin','external','screen','innerWidth','innerHeight','scrollX','pageXOffset','scrollY','pageYOffset','visualViewport','screenX','screenY','outerWidth','outerHeight','devicePixelRatio','clientInformation','screenLeft','screenTop','defaultStatus','defaultstatus','styleMedia','onanimationend','onanimationiteration','onanimationstart','onsearch','ontransitionend','onwebkitanimationend','onwebkitanimationiteration','onwebkitanimationstart','onwebkittransitionend','isSecureContext','onabort','onblur','oncancel','oncanplay','oncanplaythrough','onchange','onclick','onclose','oncontextmenu','oncuechange','ondblclick','ondrag','ondragend','ondragenter','ondragleave','ondragover','ondragstart','ondrop','ondurationchange','onemptied','onended','onerror','onfocus','oninput','oninvalid','onkeydown','onkeypress','onkeyup','onload','onloadeddata','onloadedmetadata','onloadstart','onmousedown','onmouseenter','onmouseleave','onmousemove','onmouseout','onmouseover','onmouseup','onmousewheel','onpause','onplay','onplaying','onprogress','onratechange','onreset','onresize','onscroll','onseeked','onseeking','onselect','onstalled','onsubmit','onsuspend','ontimeupdate','ontoggle','onvolumechange','onwaiting','onwheel','onauxclick','ongotpointercapture','onlostpointercapture','onpointerdown','onpointermove','onpointerup','onpointercancel','onpointerover','onpointerout','onpointerenter','onpointerleave','onselectstart','onselectionchange','onafterprint','onbeforeprint','onbeforeunload','onhashchange','onlanguagechange','onmessage','onmessageerror','onoffline','ononline','onpagehide','onpageshow','onpopstate','onrejectionhandled','onstorage','onunhandledrejection','onunload','performance','stop','open','alert','confirm','prompt','print','queueMicrotask','requestAnimationFrame','cancelAnimationFrame','captureEvents','releaseEvents','requestIdleCallback','cancelIdleCallback','getComputedStyle','matchMedia','moveTo','moveBy','resizeTo','resizeBy','scroll','scrollTo','scrollBy','getSelection','find','webkitRequestAnimationFrame','webkitCancelAnimationFrame','fetch','btoa','atob','setTimeout','clearTimeout','setInterval','clearInterval','createImageBitmap','onappinstalled','onbeforeinstallprompt','crypto','indexedDB','webkitStorageInfo','sessionStorage','localStorage','chrome','onformdata','onpointerrawupdate','speechSynthesis','webkitRequestFileSystem','webkitResolveLocalFileSystemURL','openDatabase','applicationCache','caches','ondevicemotion','ondeviceorientation','ondeviceorientationabsolute','WebUIListener','cr','assert','assertNotReached','assertInstanceof','$','getSVGElement','getDeepActiveElement','findAncestorByClass','findAncestor','disableTextSelectAndDrag','isRTL','getRequiredElement','queryRequiredElement','appendParam','createElementWithClassName','ensureTransitionEndEvent','scrollTopForDocument','setScrollTopForDocument','scrollLeftForDocument','setScrollLeftForDocument','HTMLEscape','elide','quoteString','listenOnce','hasKeyModifiers','isTextInputElement' ];
return Object.fromEntries(Object.entries(window).filter(([ key ]) => !globalKeys.includes(key)));
};
const getCircularReplacer = () => {
const seen = new WeakSet();
return (key, value) => {
if (typeof value === 'object' && value !== null) {
if (seen.has(value)) {
return;
}
seen.add(value);
}
return value;
};
};
copy(JSON.stringify(getUserDefinedKeys(), getCircularReplacer()));
The properties of window object are in chronological order. So, create some variable with unique name at the beginning of your first script included in your webpage and get the index of this property:
var abcdefghijklmnopqrstuvwxyz = true;
var firstOwnPropertyFound = Object.keys(window).indexOf('abcdefghijklmnopqrstuvwxyz');
Then anywhere you want to get array of all user defined properties use:
let myProp = Object.keys(window).slice(firstOwnPropertyFound);
or if you want to skip the first two variables:
let myProp = Object.keys(window).slice(firstOwnPropertyFound + 2);
The myProp variable is array contains all property names you created. In my test webpage for example:
Array(7) [
0: "abcdefghijklmnopqrstuvwxyz"
1: "firstOwnPropertyFound"
2: "st"
3: "clog"
4: "tstfnc"
5: "tstFNC1"
6: "obj"
length: 7
]
Then access all variables:
myProp.forEach(item => {
console.log(window[item]);
}
I use this and it works. (Sorry for my bad English)
Maybe this?:
for (var property in window)
{
if (window.hasOwnProperty(property))
console.log(property)
}
I note the following similarity to this post:
Dynamic deep setting for a JavaScript object
However, the above post is based upon a known structure and depth to the javascript object and not truly dynamic. Truly dynamic would suggest that you did not have any precursor knowledge of the structure, just a path and a value to replace it with. I have created a fairly good use case over on JSFiddle here:
http://jsfiddle.net/kstubs/nJrLp/1/
function Message(message) {
$('result').insert('<div>' + message + '</div>');
}
var obj = {
"array": [1, 2, 3],
"boolean": true,
"null": null,
"number": 123,
"object": {
"a": "b",
"c": "d",
"e": "f",
"complex_array1": [{
"g": "h"
}, {
"bingo": "bongo"
}, {
"x": {
"complex_array2": [{
"h": "i"
}, {
"j": "k"
}, {
"bingo": "bongo"
}, {
"bango": "jango"
}]
}
}]
},
"string": "Hello World"
};
var list = [{
"h": "i"
}, {
"j": "k"
}];
function walk(path,value) {
var a = path.split('.');
var context = obj;
for (i = 0; i < a.size(); i++) {
context = context[a[i]];
}
}
The use case:
Find complex_array2
Update its list to a new list (a new array)
The new array is the array list which should replace the list for complex_array2. The javascript function walk does just that, walks the javascript object until the path criteria is met and then sets the value to whatever value is passed to the walk function, however the new value does not stick.
I know why it doesn't stick, because as you walk over an object of type array you lose the pointer to the original object. So, the challenge is to walk the javascript object and not lose context of the original object.
Thanks for any assistance.
Karl..
Just loop over all but the last element in the path. Then the final element is used for assignment after the loop.
var i = 0;
for (; i < a.size() - 1; i++) {
context = context[a[i]];
}
context[a[i]] = value;
Technically you can leave the declaration of i inside the for. I just find this clearer.
http://jsfiddle.net/nJrLp/2/
The reason your code doesn't work as it's written is because rather than changing a property on an object you have a reference to, you're actually changing which object your local variable points to.
context = context[a[i]];
context is a pointer to an object, and it's a local variable. When you assign to it, you're assigning a new pointer value, which loses the reference to the previous object. If you want to replace it, you'll have to refer to it from its parent object. Assume parent is one such object; once you locate your target object's key name (let's say you've put it in variable key), you could overwrite the existing value as such:
parent[key] = new_value;
This will dereference parent, find the property named by key, and replace its value (which is a pointer) with the memory address of new_value. What you have currently works something like this:
var context = parent[key];
context = new_value;
In this case you're simply changing the pointer value of the local variable context, not the object that parent[key] points to.
I used a helper function for reading complex json objects. (http://jsfiddle.net/JBBAJ/)
var object = {
data: {
users: [
{
firstName: "White"
},
{
firstName: "Black"
}
]
}
}
var read = function(path, obj) {
var path = path.split(".");
var item = path.shift();
if(item.indexOf("]") == item.length-1) {
// array
item = item.split("[");
var arrayName = item.shift();
var arrayIndex = parseInt(item.shift().replace("]", ""));
var arr = obj[arrayName || ""];
if(arr && arr[arrayIndex]) {
return read(path.join("."), arr[arrayIndex]);
} else {
return null;
}
} else {
// object
if(obj[item]) {
if(path.length === 0) {
return obj[item];
} else {
return read(path.join("."), obj[item]);
}
} else {
return null;
}
}
}
console.log(read("data.users[0].firstName", object)); // White
console.log(read("data.users[1].firstName", object)); // Black
console.log(read("data.test.users[0]", object)); // null
The function read accepts a path and an object.
I have an object created from JSON via AJAX from the server. The object has several sub-objects in an array, e.g.:
obj.subObj1[0].value="abc";
obj.subObj1[1].value="abc";
obj.subObj2[0].value="abc";
Now I want to set some values in this object but I dont know if they already exist.
obj.subObj1[0].value="new Value"; // No Problem
obj.subObj2[1].value="new Value2"; // Problem because obj.subObj2[1] is no Object.
I would need to do obj.subObj2[1]={} first.
Because I have this problem very often I am looking for method to automate this. A method or class which does automatically create the needed object (or array if I use an integer).
It should be able to handle an infinite depth of such sub-objects. Like this:
var obj = TheObject();
obj.sub1.sub2[10].sub3[1].sub4='value';
Now automatically all needed sub-objects and arrays should be created.
Cannot really guarantee anything about cross-browser compatibility, but how about trying this on for size (works in Chrome):
// Safely sets value property of index of an array of an object.
function setObj(obj, subObjName, index, val) {
// Ensure the object exists
if (typeof obj == 'undefined') {
obj = new Object();
}
// Ensure the array property exists
if (typeof obj[subObjName] == 'undefined') {
obj[subObjName] = new Array();
}
// Ensure the array properties index exists
if (typeof obj[subObjName][index] == 'undefined') {
obj[subObjName][index] = {};
}
// Set the value
obj[subObjName][index].value = val;
// Return the object
return obj;
}
Example use:
<script type="text/javascript">
var obj;
obj = setObj(obj, "something", 1, "val");
setObj(obj, "something", 0, "someValue");
alert(obj.something[1].value);
alert(obj.something[0].value);
</script>
If you can assume that the referenced item in the array will be either undefined or an object it simplifies things. Of course the simple (non-automatic) way would be something like this:
if (!obj.subObj2[1]) obj.subObj2[1] = {};
obj.subObj2[1].value = "new Value2";
A not-very generic function to do it for you would be:
function setArrayObjectProp(arr, index, prop, val) {
if (!arr[index])
arr[index] = {};
arr[index][prop] = val;
}
// called as
setArrayObjectProp(obj.subObj2, 1, "value", "new Value2");
heloo
try testing the type of the array item first if its not object then equal it to the new object format {value:"new Value2"}
if(typeof(obj.subObj2[1])!='object')
{
obj.subObj2[1] = {value:"new Value2"};
}
else
{
obj.subObj2[1].value = "new Value2";
}