问题
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;
}
回答1:
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.
回答2:
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?
来源:https://stackoverflow.com/questions/18189367/javascript-deep-search-and-change-in-object