Recursively search for a value in global variables and its properties - javascript

Let's say that I want to search for a value, like 'StackOverflow', in all declared variables in window.
I can do it with this code:
function globalSearch(obj, value) {
for(var p in obj)
if(obj[p] == value)
return(p);
}
globalSearch(window, 'StackOverflow');
This code will return the name of a variable that have this value (or returns nothing).
So, if I have declared a variable with value 'StackOverflow', it will successfully find it.
My problem is that I want to go deeper and search thru window's objects (and its own nested objects) too, to achieve a result like this:
var x = 'StackOverflow' // returns 'x'
var y = { a : 'StackOverflow' } // returns 'y.a'
var z = { a : { b: 'StackOverflow' } } // returns 'z.a.b'
I'm having problems with inherited methods of Objects. Is there a way to do this?

Deep search but without the recursive function calls
Functional recursion has internal stack limits and wastes memory.
Additional features added
Recursive object protection in the form of a searched array; It doesn't use up too much memory of course as the objects are only stored as references.
Return true if the the object itself matches the value. Otherwise it would return '' which would match to false.
Arrays use angle-bracket notation.
The code
function globalSearch(startObject, value) {
var stack = [[startObject,'']];
var searched = [];
var found = false;
var isArray = function(test) {
return Object.prototype.toString.call( test ) === '[object Array]';
}
while(stack.length) {
var fromStack = stack.pop();
var obj = fromStack[0];
var address = fromStack[1];
if( typeof obj == typeof value && obj == value) {
var found = address;
break;
}else if(typeof obj == "object" && searched.indexOf(obj) == -1){
if ( isArray(obj) ) {
var prefix = '[';
var postfix = ']';
}else {
var prefix = '.';
var postfix = '';
}
for( i in obj ) {
stack.push( [ obj[i], address + prefix + i + postfix ] );
}
searched.push(obj);
}
}
return found == '' ? true : found;
}
Problems
Without passing the initial variable name into the function, we can't return the fully qualified variable name from the beginning. I can't think of a solution and I would be surprised if there was one.
Variable names with spaces are valid as the key to an object, as are other invalid variable names, it just means that the value must be addressed using angle-brackets. There are a couple of solutions I can think of. Regex check each variable name to make sure it's valid and use angle-brackets notation if it is not. The overriding problem with this is that the reg-ex is a page long. Alternatively, we could only use angle-brackets but this isn't really true to the OPs original question.
The indexOf call on the array 'searched' might be a bit heavy on very large objects but I can't yet think of an alternative.
Improvements
Apart from cleaning up the code a little, it would also be nice if the function returned an array of matches. This also raises another issue in that the returned array would not contain references to recursive objects. Maybe the function could accept a result format configuration parameter.

This should work. It uses recursion to achieve the result.
function globalSearch(obj, value) {
for(var p in obj)
if(obj[p] == value){
return(p);
}else if(typeof obj[p] == "object" && obj[p] != obj){
var te = globalSearch(obj[p], value);
if(te!=false){ return p + "." + te }
}
return false;
}

Make your solution recursive. If you have an object, call your function again.
function globalSearch(obj, value) {
for(var p in obj) {
if (obj[p] == value) {
return(p);
} else if (typeof obj[p] === "object") {
var recursiveCheck= globalSearch(obj[p], value);
if (recursiveCheck) {
return p + "." + recursiveCheck;
}
}
}
}
globalSearch(window, 'StackOverflow');
I bet most browsers will hit a warning for too much looping.

This code, based on the other answer, allows for all possible value matches to be found.
function globalSearch(startObject, value, returnFirstResult = false) {
var stack = [[startObject,'']];
var searched = [];
var found = new Set();
var isArray = function(test) {
return Object.prototype.toString.call( test ) === '[object Array]';
}
while(stack.length) {
var fromStack = stack.pop();
var obj = fromStack[0];
var address = fromStack[1];
if( typeof obj == typeof value && obj == value) {
if (returnFirstResult) {
return address == '' ? false : address;
}
found.add(address)
}if(typeof obj == "object" && searched.indexOf(obj) == -1){
if ( isArray(obj) ) {
var prefix = '[';
var postfix = ']';
}else {
var prefix = '.';
var postfix = '';
}
for( i in obj ) {
stack.push( [ obj[i], address + prefix + i + postfix ] );
}
searched.push(obj);
}
}
return Array.from(found);
}

Related

Getting value of first index within jQuery array using .each()

I have a JSON array returned via ajax that looks like:
"stuff": [["2","66%"], ["3","42%"],...
Problem
I want to match the zeroth index of each element in this array to a variable outside of the loop and if it matches, I want to return the percentage next to it.
I don't know the syntax in jQuery for this. Please have a look at my code below and see if that's correct or not:
var percentage = 0;
var stuffarr = jsonobj['stuff'];
var stuffID = jsonobj['stuff_id']
if (!stuffID || 0 === stuffID.length){
$("#stuff-element").html("--");
}
else {
var percentage = $.each(stuffarr, function (index, value) {
if(value[0] == stuffID)
return value[1]
});
}
Firstly, a bit of terminology. The data structure you have is an Object which holds several properties. It has nothing to do with JSON after it has been deserialised.
With regard to your issue, there's no jQuery required as you can use find() to find the item in the array by the stuffID variable's value. Try this:
var obj = {
"stuff": [
["2", "66%"],
["3", "42%"]
],
"stuff_id": "3"
}
var percentage = 0;
var stuffArr = obj['stuff'];
var stuffId = obj['stuff_id']
if (!stuffId || 0 === stuffId.length) {
$("#stuff-element").html("--");
} else {
percentage = stuffArr.find(function(el) {
return el[0] == stuffId;
})[1];
}
console.log(percentage);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
try this
var percentage = stuffarr.find(function (value) {
if(value[0] == stuffID)
return value[1];
})[1];
The return statement you used returns the result of the function(..) inside the .each(..) function and is not the return value of the .each(..) function.
the valid return value is boolean which 'tells' the .each(..) function whether it should continue or not. instead use the following syntax:
var ret = '';
$(arr).each(function () {
var curr = $(this);
//console.log(curr);
if(curr[0] == stuffID){
//console.log('>>found: ' + curr[1]);
ret = curr[1];
//if found -> break loop
return false;
}
});
comment: you should consider instead of using an inner array data structure use an object, this is a more 'correct' data structure:
// "stuff": [{"id":"2","percent":"66%"}, {"id":"3","percent":"42%"},...
var ret = '';
$(arr).each(function () {
var curr = this;
//console.log(curr.id);
if(curr.id == stuffID){
//console.log('>>found: ' + curr.percent);
ret = curr.percent;
//if found -> break loop
return false;
}
});
#LiverpoolOwen approach is clean and nice, and if you want to use it combining with the object approach do this:
arr.find(function (value) {
if(value.id == stuffID)
return value;
}).percent;

Where am I going wrong in my recursive function?

I am working on a learning project that requires me to implement a recursive function that stringifies a passed in object, without using JSON.stringify. I have to consider all data types as parameters that my function will receive, and while I am fine with that, I seem to be getting confused when an array/object is passed, and I call the function on itself to iterate over the object contents.
I am not doing it right and every change I make is impacting other areas I thought I had completed so my frustration is starting to win this battle. Areas I need help on:
Output all elements of an array/object in the same way as JSON.stringify when I call the function on itself. An example of an issue I see is, if I pass an array like ["SO"], I am am getting [SO] returned, but it looks like I have that possibility covered!
What to do when a function is passed as a param, which is not allowed.
Here is what I have so far. I appreciate any help you can offer.
var myJSONRecursiveFunc = function (obj) {
var stringed = "";
var result;
if (Number.isInteger(obj)) {
return "" + obj + "";
} else if (obj === null) {
return "" + null + "";
} else if (typeof obj === "boolean") {
return "" + obj + "";
} else if (typeof obj === "string") {
return '"' + obj + '"';
} else if (Array.isArray(obj)) {
if (obj.length === 0) {
return "[" + obj + "]";
}
for (var i = 0; i < obj.length; i++) {
if (Array.isArray(i)) {
myJSONRecursiveFunc(i);
} else {
stringed += "" + obj[i] + ""
}
}
return result = "[" + stringed + "]";
} else {
for (var val in obj) {
if (typeof val === "object") {
myJSONRecursiveFunc(val);
}
stringed += "" + val + "" + ":" + "" + obj[val] + "" + '';
}
return result = "{" + stringed + "}";
}
};
It is far from perfect as I am still learning so please let me know where I can improve along with any help in getting this to work as is.
Output all elements of an array/object in the same way as JSON.stringify when I call the function on itself. An example of an issue I see is, if I pass an array like ["SO"], I am am getting [SO] returned, but it looks like I have that possibility covered!
Your recursion of var val in obj is only passing in val, which is the key of obj. You need to call myJSONRecursiveFunc(obj[val]) in order to get the right result. Additionally, this is true for your array. Your if statement needs to check to see if obj[i] is an array, not i which would just be an integer. In this case, you need to say:
if (Array.isArray(obj[i])) {
myJSONRecursiveFunc(obj[i])
}
What to do when a function is passed as a param, which is not allowed.
You would need to have a check to see if the function being passed in is a function, with typeof, such as: if (typeof func === function)
This is a pretty fun exercise. I did this a few months back, and had access to the Underscore library to do so. Here's working code:
var stringifyJSON = function(obj) {
//Strings and null should be addressed here. Strings have quotes inside the string so I can't lump them together with booleans and numbers.
if (_.isString(obj)){
return '"' + obj.split('"').join('\\"') + '"';
}
if (_.isNull(obj)){
return 'null';
}
//Arrays get a temporary array that their stringified elements get pushed to, and then that temporary array is joined together and concatenated with the brackets that exist within the returned string.
if (_.isArray(obj)){
var tempArr = [];
_.each(obj, function(elem){
tempArr.push(stringifyJSON(elem));
});
return '[' + tempArr.join(',') + ']';
}
//Objects get a temporary string to add their stringified data to. Including a check for undefined values and function keys.
if (_.isObject(obj)){
var tempArr = [];
for (var k in obj){
if (_.isUndefined(obj[k]) || _.isFunction(k)){
return '{}';
} else {
tempArr.push(stringifyJSON(k) + ':' + stringifyJSON(obj[k]));
}
}
return '{' + tempArr.join(', ') + '}';
}
//Everything else = booleans, numbers
else {
return obj.toString();
}
};
Okay, let's do this.
Annotated suggestions
function toJSON(obj) {
// There are people who will disagree with me
// but I think this variable is declared way too early.
// It's used in 2 places as a temp variable, so should
// be declared closer to where it's used.
// It should also be named more appropriately for how it's used.
// I used `arrayParts` and `keyValuePairs` instead.
var stringed = "";
// As far as I can tell, this variable is never actually
// used for anything useful.
// It's always `return result = <thing>`.
// If you're immediately returning, there's no need to save
// to a variable.
var result;
if (Number.isInteger(obj)) {
// The initial `"" + <number>` converts to a string.
// Appending another "" to the end is pointless in
// all of the below lines.
return "" + obj + "";
} else if (obj === null) {
return "" + null + "";
} else if (typeof obj === "boolean") {
return "" + obj + "";
} else if (typeof obj === "string") {
return '"' + obj + '"';
} else if (Array.isArray(obj)) {
// If the object is an array with length 0, you
// already know what it looks like.
// It's `[]`, so just return that instead of adding
// the empty array in the middle.
if (obj.length === 0) {
return "[" + obj + "]";
}
for (var i = 0; i < obj.length; i++) {
// In the top of this function, you handle all the
// different types of objects, so you should recurse and
// reuse that logic. Checking again here is wasted effort.
if (Array.isArray(i)) {
myJSONRecursiveFunc(i);
} else {
stringed += "" + obj[i] + ""
}
}
return result = "[" + stringed + "]";
// A better way to write this section would have
// looked like this.
// var arrayParts = []
// for( var i = 0; i < obj.length; i++ ){
// var stringifiedElement = toJSON( obj[ i ] )
// arrayParts.push( stringifiedElement )
// }
// return '[' + arrayParts.join( ',' ) + ']'
} else {
for (var val in obj) {
// Again, your function's start checks type and handles it.
// Use that recursively.
if (typeof val === "object") {
myJSONRecursiveFunc(val);
}
stringed += "" + val + "" + ":" + "" + obj[val] + "" + '';
}
return result = "{" + stringed + "}";
// This section could be rewritten as:
// var keyValuePairs = []
// for( var key in obj ){
// var pair = '"' + key + '":' + toJSON( obj[ key ] )
// keyValuePairs.push( pair )
// }
// return '{' + keyValuePairs.join( ',' ) + '}'
}
};
Your error
For the record, when you pass in ['SO'] into your function, this is what is happening. The isArray block catches the object first.
} else if( Array.isArray( obj ) ){
Then inside your loop, the else block returns "" + obj[i] + "", which converts to "" + "SO" + "", which turns into "SO".
When this is returned, "[" + "SO" + "]" turns into "[SO]".
for (var i = 0; i < obj.length; i++) {
if (Array.isArray(i)) {
myJSONRecursiveFunc(i);
} else {
stringed += "" + obj[i] + "" // <-- the error
}
}
Additional Suggestions
When you loop over obj as an actual object near the end, you do so like this.
for( var val in obj ){
// foo
}
Sidenote: val is actually the key, so that's a bit misleading.
This is an ugly part of Javascript. If the raw Object is modified, for example: Object.prototype.foobar = 5, then 'foobar':5 will show up in every object in your program. It's worth noting that only developers who are very sure what they are doing should ever be doing this, but it is possible.
To make sure this does not break your program, add the following code.
for( var key in obj ){
if( ! obj.hasOwnProperty( key ) ){
continue
}
}
obj.hasOwnProperty( <name> ) checks if obj has a direct property <name>. If it does not, then we skip to the next loop iteration with continue.

Compare property value in an array of objects

Hello I am working in a project to keep learning js wich is in this URL: http://themapapp.herokuapp.com/ and this is the github page: https://github.com/xtatanx/mapApp
In some of the parts of my code I need to check if some property already exists in an array of objects and also I that property value is equal to something, so far the code that I am using to to dis is this one:
// check if property value exist in an array of objects
function searchByValue(value, property, array){
for(var i = 0; i < array.length; i++){
if(array[i][property] === value){
return true;
}
}
return false;
}
And I use it like this:
if(searchByValue('myDestiny', 'id', map.markers)){
map.markers[1].setPosition({
lat: results[0].geometry.location.k,
lng: results[0].geometry.location.A
});
}else{
createMarker(results[0].geometry.location.k, results[0].geometry.location.A, 'myDestiny');
My question is if actually I am doing it the way it is or if I am wrong because I sometime think that the function its not returning the correct value or is not working good, I will appreciate if some of you guys could give me some advice in how to achieve this, or improve it.
EDIT
i finished with something like
Array.prototype.searchBy = function(property, value){
var _property = arguments[0];
var _value = arguments[1];
if(arguments.length === 1){
return Array.prototype.indexOf.apply(this, arguments);
}
for(var i = 0; i < this.length; i++){
if(this[i][_property] === _value ){
return true;
}
}
return false;
};
Didnt used the checkprop part because actually doesnt understood how it works o_O. thank you very much to #GameAlchemist and #jshanley
Your code works well as long as every object in the array you are searching has defined the property you check for. I could see running into a problem otherwise. You might try adding a check that the property is defined before trying to access its value, like this:
function searchByValue(value, property, array){
for(var i = 0; i < array.length; i++){
// check that property is defined first
if(typeof array[i][property] !== 'undefined') {
// then check its value
if(array[i][property] === value){
return true;
}
}
}
return false;
}
I would rather define this function as a method of Array, and why not overload indexOf, that would act as std indexOf with one argument, and as indexOf(value, propertyName, checkProp) with three arguments.
var __oldIndexOf = Array.prototype.indexOf ;
Array.prototype.indexOf = function() {
if (arguments.length==1) return __oldIndexOf.apply(this, arguments);
var value = arguments[0];
var property = arguments[1];
var checkProp = arguments[2];
if (!checkProp) {
for(var i = 0; i < this.length; i++){
if(this[i][property] === value){
return i;
}
} else {
for(var i = 0; i < this.length; i++){
var thisItem = this[i] ;
if (!Object.hasOwnProperty(thisItem, property))
throw('indexOf error : object ' + thisItem + ' has no property ' + property);
if(this[i][property] === value){
return i;
}
}
return -1;
};
so, for your code,
if (searchByValue('myDestiny', 'id', map.markers)) { ...
becomes :
if (map.markers.indexOf('myDestiny', 'id') != -1 ) { ...
and obviously you can store the found index in case you need it.
i think that, in your case, what you meant was rather using the found index :
var destinyIndex = map.markers.indexOf('myDestiny', 'id');
if(destinyIndex != -1){
map.markers[ destinyIndex ].setPosition({
lat: results[0].geometry.location.k,
lng: results[0].geometry.location.A
});
} else {
createMarker(results[0].geometry.location.k, results[0].geometry.location.A,
'myDestiny');
}
Edit : idea of checking that property exists is courtesy of #jshanley

Cast string to an object?

I am enumerating through the properties of an object. It works fine when I set the object directly.
I need to use prompt (class assignment) to allow the user to input an object name. The problem is obj returns as a string
How can I cast the value from the prompt to an object?
function enumObject(){
var obj;
var propertyName;
obj = prompt("Please enter an object name","window.navigator");
obj = window.navigator;
if (typeof obj == "object"){
for (propertyName in obj){
document.write(propertyName + " : " + obj[propertyName] + "<br>");
}
}
else {
alert('The object name is undefined.');
}
obj = null;
propertyName = null;
}
enumObject();
An object name...?!?
Do you want your user to inform a global variable name which refers an object?
If so, you could do:
var name = prompt("Enter a global variable name.");
var obj = window[name];
If you want your user to enter a string which will be converted to an object literal, you could do:
var objDef = prompt("Enter a string representing an object");
var obj = eval("(function(){return " + objDef + ";})()");
or...
var objDef = prompt("Enter a string representing an object");
var obj = new Function("return " + objDef)();
If you want to access a object variable in a function scope and you're not using "strict mode", try:
(function(){
var someObj = { b:123, c: 321 };
var name = prompt("Enter an object variable name in local scope.");//Here, your user could enter "someObj"
eval("console.log(" + name + ")");
})();
I would suggest:
function enumObject(){
var obj;
var propertyName;
obj = prompt("Please enter an object name","window.navigator");
window[obj] = {};
if (typeof window[obj] == "object"){
for (propertyName in obj){
document.write(propertyName + " : " + obj[propertyName] + "<br>");
}
}
else {
alert('The object name is undefined.');
}
}
enumObject();
I need to use prompt (class assignment) to allow the user to input an
object name. The problem is obj returns as a string
How can I cast the value from the prompt to an object?
You can't since Objects don't have names. You can have either variables or object properties whose value is a reference to an object though:
var obj = {};
creates a variable whose name is obj and whose value is a reference to an object.
If you want to dynamically create variables, you can use eval, but it's not recommended. It is very much warned against to use eval to execute random code entered by users since they are completely unaware of the variables that already exist and that you don't want them to mess with.
What you can do is create an object specifically to add properties to, since almost any string value can be used as a property name. So you might do:
function enumObject(){
// markup and div will be used later
var markup = '';
var div;
// Here's where the property names will be stored
var obj = {};
var propertyName = prompt("Please enter an object name", "window.navigator");
obj[propertyName] = {};
// This is redundant since an object was just assigned so it will
// always return true
if (typeof obj[propertyName] == "object") {
// Always perform a hasOwnProperty check so you don't get
// inherited properties, you only want the ones added by the user
// Also, don't re-used variables, create a new one
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
// Don't use document.write after the page has finished loading
// as it will clear the entire document first before writing
markup += propertyName + " : " + obj[propertyName] + "<br>";
}
}
// This should never execute since the test should always be true
} else {
alert('The object name is undefined.');
}
// Write to the document without destroying it
div = document.createElement('div');
div.innerHTML = markup;
document.body.appendChild(div);
}
Edit
Maybe you want to access object properties based on user defined strings. In that case, you can do something like the following. It only uses eval if the root of the property accessor is not window and only strings that appear to be valid identifiers, not random code:
// Assumes dot notation like window.navigator or foo.bar
function getObjectValueByString(s) {
var identifier, path = [];
// Very simple identifier re
var identifierRe = /^[_$a-z][a-z0-9_$]*$/i;
s = s.split('.');
// Loop over parts of s
for (var i=0, iLen=s.length; i<iLen; i++) {
identifier = s[i];
path.push(identifier);
if (identifierRe.test(identifier)) {
// Get root of accessor
if (i == 0) {
if (identifier == 'window') {
obj = window;
// Only use eval on what appear to be valid identifiers
// not arbitrary code
} else {
obj = eval(identifier);
}
// If not root, get property value
} else {
obj = obj[identifier];
}
// Stop if obj isn't an object
if (typeof obj != 'object') {
// Message if didn't get to end of accessor
if (i < iLen - 1) {
return 'Stopped at ' + path.join('.') + ' = ' + obj;
}
}
} else {
return identifier + ' is not a valid identifier';
}
}
return path.join('.') + ' = ' + obj;
}
To play with it:
<input onblur="console.log(getObjectValueByString(this.value));">
A much more rigorous regular expression for identifier names that excludes reserved words is in the accepted answer for Valid Characters for JavaScript Variable Names.
If only properties of window are required, life becomes much simpler and eval is not needed at all, so nor is the regular expression to check for valid identifiers:
function getWindowValueByString(s) {
var identifier, path = [];
var obj = window;
s = s.split('.');
// Loop over parts of s
for (var i=0, iLen=s.length; i<iLen; i++) {
identifier = s[i];
path.push(identifier);
// Check only using window
if (i == 0) {
if (identifier != 'window') {
return 'Only valid for properties of window';
}
} else {
obj = obj[identifier];
}
// Stop if obj isn't an object
if (typeof obj != 'object') {
// Message if didn't get to end of accessor
if (i < iLen - 1) {
return 'Stopped at ' + path.join('.') + ' = ' + obj;
}
}
}
return path.join('.') + ' = ' + obj;
}

Javascript deep search and change in object

I have a JavaScript function what is dig through on object and make a string value to function object.
Have this JSON:
{
"active": true,
"icons": {
"activeHeader": "ui-icon-alert"
},
"animate": {
"duration": 1000, "always": "dMethod"
}
}
I use JSON.parse on this string so I reach options.animate.always as a string with value dMethdod which is actually a name of the method. So I can access this through window[options.animate.always] and I wish to change the options.animate.always from string to method that is pointed to the string.
I make a function for this job:
function SetFunctions(options, functionName) {
var path = functionName.split(".");
var setterObject = options;
for (var k = 0; k < path.length; k++) {
if (setterObject != undefined) {
setterObject = setterObject[path[k]];
} else {
break;
}
}
if (setterObject != undefined && window[setterObject] != undefined) {
setterObject = window[setterObject];
}
}
I call this function with the variable returned from the parse and function name animate.always as value.
The part that find the correct property is worked, but when I set the value of the setterObject the change is not affect the original value.
I'm thinking to build up the reference as string 'options.animate.always = dMethod' and use eval on it, but I really want to avoid using eval function (I know eval is evil :)).
FINAL SOULUTION:
I put answers together and finished my method. Finally become two methods. I comment it and share maybe useful to others:
function ChangeStringToFunction(functionPath, rootObject, separator) {
// functionPath is required parameter
if (functionPath === undefined || functionPath === null) return;
// rootObject is optional. If not supplied the window object will be the base of the search
var localRootObject = rootObject === undefined ? window : rootObject;
// separator is optional. If not supplied the '.' will be the separator
var localSeparator = separator === undefined ? "." : separator;
// split the string reference (example "jui.someObj1.someOjb2"
var pathParts = functionPath.split(localSeparator);
var currentObject = localRootObject;
// exclude the last part
for (var i = 0; i < pathParts.length - 1; i++) {
currentObject = currentObject[pathParts[i]];
// it's useless to go forward if there is no object
if (currentObject === undefined) return;
}
// get the string represent the name of the function (full path could be included)
var currentValue = currentObject[pathParts[pathParts.length - 1]];
// the value must be a string
if (typeof currentValue !== "string") return;
// get the function reference based on the value provided
var functionReference = ResolveFunction(currentValue);
// if the result is not a function it's meaningless to continue
if (typeof functionReference !== "function") return;
// and finally change the string value of the object with the function value represent by our string
currentObject[pathParts[pathParts.length - 1]] = functionReference;
}
function ResolveFunction(functionPath, separator, rootObject) {
if (functionPath === undefined || functionPath === null) return undefined;
var localRootObject = rootObject === undefined ? window : rootObject;
var localSeparator = separator === undefined ? "." : separator;
var pathParts = functionPath.split(localSeparator);
var currentObject = localRootObject;
for (var i = 0; i < pathParts.length; i++) {
currentObject = currentObject[pathParts[i]];
if (currentObject === undefined) break;
}
return typeof currentObject === "function" ? currentObject : undefined;
}
but when I set the value of the setterObject the change is not affect the original value.
Yes, you are only assigning to a variable. That will never change anything else but the variable, since JavaScript does not have pointers.
To change an object, you will have to assign to a property. In your case, you will have to omit the last iteration to get the object which you then assign to:
function SetFunctions(options, functionName) {
var path = functionName.split("."),
setterObject = options;
for (var k=0; setterObject!=null && k<path.length-1; k++) {
setterObject = setterObject[path[k]];
}
var prop = path[k],
fn = setterObject!=null && window[setterObject[prop]];
if (fn) {
setterObject[prop] = fn;
}
}
Btw, I think in your case it might be easier to build a CallFunctions function that directly invokes the function with the name stored in that property, instead of replacing the property value with the method - unless you plan to invoke it very often.
It depends on the level of indirection you want.
If the method will always be called "always", you can do something like this:
function SetFunction(object, propertyName, functionName) {
var functionObj = window[functionName];
object[propertyName] = functionObj;
}
And call it like this:
SetFunction(myObj.animate, "always", myObj.animate.always);
But I suspect you want something a bit more generic?

Categories