How to iterate through functions defined in a javascript object - javascript

I have an object that defines a bunch of functions like this:
myObject = {
"item 1": function() {
return "I'm item 1";
},
"item 2": function() {
return "I'm item 2";
}
};
I want to write a function that calls all of the functions defined in this object without having to know the names of the functions or the number of functions. Is this possible?

In ECMAScript >=5.1 you can use the for .. in construct.
obj = {
test : function() {
console.log("test called");
}
};
for(idx in obj) {
obj[idx]();
}
You may want to check that the property is actually a function.

You can do this by first using a for-in loop to go through each of the objects properties. Then, after checking if the value is a function, you can call it.
for (var key in obj) {
if (typeof obj[key] === 'function') {
obj[key]();
}
}

You could either use Object.keys or a for-in loop depending on your needs.
Object.keys(obj); // ==> ["item-1", "item-2"]
Object.keys(obj).forEach(function (key) {
var fn = obj[key];
fn();
});
// or with a for-in loop
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
obj[key]();
}
}
Using Object.keys is arguably a bit more clear, but the for-in loop has better browser compatibility and possibly performance. For a more general comparison of object enumeration in JavaScript, refer to this question How do I enumerate the properties of a JavaScript object?.

Related

JavaScript property & field reflection

I came across this little snippet of code for property reflection in JavaScript:
function GetProperties(obj) {
var result = [];
for (var prop in obj) {
if (typeof obj[prop] !== "function") {
result.push(prop);
}
}
return result;
}
I've tested it using the following "CustomObject":
var CustomObject = (function () {
function CustomObject() {
this.message = "Hello World";
this.id = 1234;
}
Object.defineProperty(CustomObject.prototype, "Foo", {
get: function () {
return "foo";
},
enumerable: true,
configurable: true
});
Object.defineProperty(CustomObject.prototype, "Bar", {
get: function () {
return "bar";
},
enumerable: true,
configurable: true
});
return CustomObject;
})();
Here is a little test using jQuery:
$(document).ready(function () {
console.log(GetProperties(new CustomObject()));
});
Here are the results:
["message", "id", "Foo", "Bar"]
I understand that the GetProperties function just returns an array of anything in the input object that is not a function, but I want to filter the results to get only the "real" properties, so my output should be:
["Foo", "Bar"]
Is this possible?
Also, can I do the opposite and just return the fields?
There are two things you could do (and possibly more, it depends on your exact situation):
Name "private" properties differently, e.g. with a trailing underscore and check whether the property name ends with an underscore when you are iterating over the properties (and exclude them).
If by "real properties" you mean the properties defined on the prototype and you want to ignore all properties defined on the object itself, you can use .hasOwnPrototype to check where it is defined. Alternatively, you could use Object.getPrototypeOf and iterate over the properties of the prototype only.
Bad code. I'm leaving (with a comment) it 'cause the subsequent discussion
might help somebody else.
If you always use defineProperty() to get non enumerable properties, then this would work:
function GetProperties(obj) {
var result = [];
for (var prop in obj) {
// propertyIsEnumerable() returns false just because the properties
// are inherited thru the prototype chain. It was just a coincidence
// that it got the desired result. Don't do this.
if (typeof obj[prop] !== "function" && !obj.propertyIsEnumerable(prop)) {
result.push(prop);
}
}
return result;
}
Otherwise, I'd be curious to know a general solution to the problem.
EDIT: I see that the code has enumerable: true and still my code does exactly what was asked. Double you tee ef?

Javascript passing object as function parameter

I'm quite new to javascript, so maybe it's a silly error.
I created an object like the follwing:
function objA(){
this.prop1;
this.prop2;
this.prop3;
this.func1=function(){
alert('func1');
}
this.func2=function(){
alert('func2');
}
}
I now have a function where I want to pass the object:
var foo=new objA;
function test(foo){....}
The problem is that when I call test(), I get the functions in objA (objA.func1 and objA.func2) executed.
I would like just to get the properties value of objA.
I have to use another function and an array, fill the array with the properties of objA and then pass the array:
var arrayA={}
function fillArray(data){
arrayA.prop1=data.prop1;
arrayA.prop2=data.prop2;
arrayA.prop3=data.prop3;
}
function test(arrayA){....}
Is it the only way or I'm doing something wrong ?
Functions are properties of an object (they are first-class values), and thus they show up in for (var propName in myObj) loops like any other property. You can avoid examining them further via:
for (var prop in myObj){
if (!myObj.hasOwnProperty(prop)) continue; // Skip inherited properties
var val = myObj[prop];
if (typeof val === 'function')) continue; // Skip functions
// Must be my own, non-function property
}
Alternatively, in modern browsers you can make specific properties (like your functions) non-enumerable, so they won't show up in a for ... in loop:
function objA(){
this.prop1 = 42;
Object.defineProperty(this,'func1',{
value:function(){
...
}
});
}
For more on this, see the docs for Object.defineProperty or Object.defineProperties.
Finally, if you don't need to define your functions as closures you can define them on the prototype of your object in which case the hasOwnProperty test will cause them to be skipped:
function objA(){
this.prop1 = 42;
}
objA.prototype.func1 = function(){
// operate on the object generically
};
var a = new objA;
"func1" in a; // true
a.hasOwnProperty("func1"); // false

Adding function to Object prototype causes function to show up in all 'for X in OBJ' loops

So, here's some sample javascript code:
Object.prototype.simpleFunction = function () {
return true;
}
var tempObject = {};
for (var temp in tempObject) {
console.log(temp);
}
Note that if you execute this, you'll get 'simpleFunction' output from the console.log commands in Google Chrome. (I'm using 19.0.1084.46m .)
However, the wide variety of related Object functions are not passed to the console.log.
How can I add functions onto the Object prototype without them showing up in my 'for property in object' loops?
Edit: I should have mentioned that the last thing I wanted was to throw another 'if' statement in there, as it'd mean I'd need to add it to ALL for loops. :(
Which is why you should always check hasOwnProperty:
for (var temp in tempObject) {
if (Object.prototype.hasOwnProperty(tempObject, temp)) {
console.log(temp);
}
}
Crockford advocates using Object.prototype.hasOwnProperty instead of tempObject.hasOwnProperty, just in case you override hasOwnProperty in your object.
In ES5, you can set it to not be enumerable:
Object.defineProperty(Object.prototype, 'simpleFunction', {
value: function() {
return true;
},
enumerable: false, // this is actually the default
});
Alternatively (in ES5), you can use Object.keys() to only get the object's own keys:
Object.keys(tempObject).forEach(function(key) {
console.log(key);
});
Do you mean something like:
for (var temp in tempObject) {
if (tempObject.hasOwnProperty(temp )) {
console.log(temp);
}
}
It's not possible to do this in javascript. You need to filter the results yourself. One potential method is to define your own prototype properties in another object:
var myObjectExt = {
sampleFunciton: function(){}
}
var p;
for(p in myObjectExt){
Object.prototype[p] = myObjectExt[p];
}
var obj = {};
for(p in obj){
if(myObjectExt[p])continue;
//do what you need
}
You can skip the inherited properties by doing this:
if (tempObject.hasOwnProperty(temp)) {
// property didn't come from the prototype chain
}
The bottom line is, you can't add functions to the prototype without having them being iterated using in.
You could define an external interface in which you always pass the object, e.g.
function simpleFunction(obj) {
}

Making primitive data types readOnly/nonConfig in JavaScript

Does anyone have any example implementation of making individual object props readOnly/non-configurable? I mean primitive data types. Have tried using ES5 Object API, but hitting a brick wall.
I can't show code, because it's still at that "messy" phase, but basically I'm iterating through an outside object which, itself, holds numeruos objects. Those objects each hold various primitive data types. I have made the outer objects readOnly, non-config, etc, but can't figure out how to do likewise for individual props, the innermost props.
So, if outer.inner.prop === "Hello", I want to make that value readOnly.
Thanks!
UPDATE
I just figured this out, it was all in the for loop I was using to iterate over props. Now I've actually get data descriptors for the props, even the primitive ones. :) Thanks all!
You have to iterate through the inner object, since there is no way to deep-freeze an object using standard ES5 methods.
function deepFreeze(obj) {
Object.keys(obj).forEach(function (key) {
if (typeof obj[key] == 'object')
deepFreeze(obj[key]);
});
Object.freeze(obj);
}
Edit:
Also works for defineProperty if you don't want to freeze:
function deepWriteProtect(obj) {
Object.keys(obj).forEach(function (key) {
if (typeof obj[key] == 'object')
deepWriteProtect(obj[key]);
Object.defineProperty(obj, key, { writable: false });
});
}
I'm not 100% sure I understand your question correctly, but from what I gather you are asking for private variables. If so, that can be easily achieved using closures.
function myClass(){
var mySecretProperty = 10;
this.getMySecretProperty = function(){
return mySecretProperty;
}
this.changeMySecretProperty = function(s){
// whatever logic you need for a setter method
mySecretProperty = s;
}
}
var myObj = new MyClass();
myObj.changeMySecretProperty(120);
myObj.getMySecretProperty(); // will return 120
myObj.mySecretProperty // will return undefined
Would the following (ES5) example help? It creates an empty constructor, with a getter for property a (and no setter, so de facto a is read only):
var Obj = function(){};
Obj.prototype = {
get a() {return 5;}
}
var x = new Obj;
alert(x.a); //=> 5
x.a = 6; //=> TypeError: setting a property that has only a getter
Not using ES5 you can do
var Obj = function(){
var a = 5;
if (!Obj.prototype.getA) {
Obj.prototype.getA = {
toString: function() {
return a;
}
};
}
}
var y = new Obj;
alert(y.getA); //=> 5
But that is not 100% failsafe: Obj.prototype.getA can be overwritten.
Here is a jsfiddle showing how you can use ES5 getter/setter definitions to make a property of an object something that can only be fetched. The code looks like this:
var object = {
get x() {
return 17;
}, set x() {
alert("You cannot set x!");
}
};
Of course the getter could obtain the value of the property ("x") from anywhere, like a closure from a constructor or something. The point is that the setter simply does not change the value, so attempts to change it:
object.x = 100;
will not have any effect.

Is there a way to print all methods of an object? [duplicate]

This question already has answers here:
How to display all methods of an object?
(11 answers)
Closed 3 years ago.
Is there a way to print all methods of an object in JavaScript?
Sure:
function getMethods(obj) {
var result = [];
for (var id in obj) {
try {
if (typeof(obj[id]) == "function") {
result.push(id + ": " + obj[id].toString());
}
} catch (err) {
result.push(id + ": inaccessible");
}
}
return result;
}
Using it:
alert(getMethods(document).join("\n"));
If you just want to look what is inside an object, you can print all object's keys. Some of them can be variables, some - methods.
The method is not very accurate, however it's really quick:
console.log(Object.keys(obj));
Here is an ES6 sample.
// Get the Object's methods names:
function getMethodsNames(obj = this) {
return Object.keys(obj)
.filter((key) => typeof obj[key] === 'function');
}
// Get the Object's methods (functions):
function getMethods(obj = this) {
return Object.keys(obj)
.filter((key) => typeof obj[key] === 'function')
.map((key) => obj[key]);
}
obj = this is an ES6 default parameter, you can pass in an Object or it will default to this.
Object.keys returns an Array of the Object's own enumerable properties.
Over the window Object it will return [..., 'localStorage', ...'location'].
(param) => ... is an ES6 arrow function, it's a shorthand for
function(param) {
return ...
}
with an implicit return.
Array.filter creates a new array with all elements that pass the test (typeof obj[key] === 'function').
Array.map creates a new array with the results of calling a provided function on every element in this array (return obj[key]).
Take a gander at this code:-
function writeLn(s)
{
//your code to write a line to stdout
WScript.Echo(s)
}
function Base() {}
Base.prototype.methodA = function() {}
Base.prototype.attribA = "hello"
var derived = new Base()
derived.methodB = function() {}
derived.attribB = "world";
function getMethods(obj)
{
var retVal = {}
for (var candidate in obj)
{
if (typeof(obj[candidate]) == "function")
retVal[candidate] = {func: obj[candidate], inherited: !obj.hasOwnProperty(candidate)}
}
return retVal
}
var result = getMethods(derived)
for (var name in result)
{
writeLn(name + " is " + (result[name].inherited ? "" : "not") + " inherited")
}
The getMethod function returns the set of methods along with whether the method is one that has been inherited from a prototype.
Note that if you intend to use this on objects that are supplied from the context such as browser/DOM object then it won't work IE.
From here:
Example 1: This example writes out all the properties of the "navigator" object, plus their values:
for (var myprop in navigator){
document.write(myprop+": "+navigator[myprop]+"<br>")
}
Just replace 'navigator' with whatever object you are interested in and you should be good to go.
As mentioned by Anthony in the comments section - This returns all attributes not just methods as the question asked for.
Oops! That'll teach me to try and answer a question in a language I don't know. Still, I think the code is useful - just not what was required.
Since methods in JavaScript are just properties that are functions, the for..in loop will enumerate them with an exception - it won't enumerate built-in methods. As far as I know, there is no way to enumerate built-in methods. And you can't declare your own methods or properties on an object that aren't enumerable this way.

Categories

Resources