I'm having this issue today:
I'd like to extend a JavaScript Object class with some useful functions, so I wrote something like this:
Object.prototype.fn = function() {
// Do some cool stuff...
};
Then I use another function to do a loop like this:
for( var i in obj ) {
this[i] = obj[i]; // 'this' --> is another Object
console.log( i, obj[i] );
}
So I moved stuff to another object from 'obj'. However, as you can see in logs, 'fn' function is now either in my extended object and in it's __proto__. All I want is to avoid this without using this in my 'for' loop:
if( typeof obj[i] !== 'function' ) // Then do it
So I was wondering how native functions (like toString() for example) are implemented to stay invisible outside the prototype. Any suggestions?
You can use a method called defineProperty to set your property and have it not be enumerable (or as you said, stay invisible):
var obj = {};
Object.defineProperty(obj, 'test', {
enumerable: false,
configurable: false,
writable: true,
value: 'hello'
});
your property obj.test exists (value is hello) but now wont be enumerable, so doing something like:
for(var i in obj) console.log(i);
// OR
Object.keys(obj);
will not print 'test', BUT you can still access it as a property (obj.test)
Related
I'm trying to define a non-enumerable toJSON function on a prototype object without much luck. I'm hoping for something similar to ECMAScript 5 toJSON:
Object.defineProperty(obj, prop, { enumerable: false });
However this defines it as a property which cannot be accessed as a method.
[EDIT: Nick is wrong; it can be accessed as a method. His mistake was in code that is not shown in this question - see his comments on answers below, for details.]
I was hoping to be able to define the function in a non-enumerable fashion, as I was planning to define in the prototypes of all primitive types (String, Number, Boolean, Array, and Object), so that I can recursively apply the function through complex objects.
The end goal here is to be able JSONify a Backbone model/collection with nested collections recursively.
I guess in total I have two main questions:
Is it possible to define a non-enumerable function on a prototype? If so how?
Is there a better way to JSONify nested Backbone models?
I don't get it, why can't you access it as a method?
var foo = {};
Object.defineProperty(foo, 'bar', {
enumerable: false,
value: function () {console.log('foo.bar\'d!');}
});
foo.bar(); // foo.bar'd!
If you wanted it on the prototype, it's as easy as
Object.defineProperty(foo.prototype, /* etc */);
or even directly in Object.create
foo.prototype = Object.create(null, {
'bar': {value: function () {/* ... */}}
});
However, unless you're creating instances of foo, it won't show up if you try to foo.bar, and only be visible as foo.prototype.bar.
If foo has it's own prototype (e.g. foo = Object.create({})), you can get it with Object.getPrototypeOf, add the property to that and then foo.bar would work even if it is not an instance.
var proto = Object.getPrototypeOf(foo); // get prototype
Object.defineProperty(proto, /* etc */);
You can see visibility of enumerable vs non-enumerable properties here.
Paul S. is right about needing to set the property definition's value instead of a get, but I wanted to add that you don't need to pass enumerable: false, because false is the default for that option in Object.defineProperty() The answer can be simplified to:
var foo = {};
Object.defineProperty(foo, 'bar', {
value: function(){ console.log('calling bar!'); }
});
foo.bar();
Always you can avoid enumerable functions properties in object when you looping through it. And instead of define property in each object and set enumerable to false , you can create function which will call to any object with the property you want and put a condition to not take the property in the looping list. here is the example :
const obj = {
name: "myName",
title: "developer"
}
function prop() {
this.loop = function(i) {
for (i in this) {
if (typeof(this[i]) == "function") {
continue;
} else {
console.log(this[i]);
}
}
}
}
prop.call(obj);
obj.loop();
output >> myName, developer
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?
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
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) {
}
Object.create is a great addition to JavaScript, because it adheres more to the prototypical nature of JS. However, I can't help but find the syntax of the 2nd parameter to the function to be too verbose, and a step back.
For example, if I want to create an object, and specify a new property in the derived object, I need to include that property value within a property object, regardless if I'm interested in the extra features or not.
So, something as simple as this:
o = Object.create({}, { p: 42 })
Now becomes:
o = Object.create({}, { p: { value: 42 } })
Obviously this is a simple example, but to me the verbosity is unnecessary, and should be optional.
Does anyone understand the decision to require a properties object? What is your opinion of the requirement of the new syntax?
Note: I understand there are easy solutions to overcome this requirement.
The syntax is done this way so that you can add parameters that control each property:
So, when you do this:
o = Object.create({}, { p: { value: 42 } })
you are saying that you want a property named p with a value of 42. The key here is that there are other parameters you can set for each property and if there wasn't this extra level of object hierarchy, you wouldn't have any way to pass those extra parameters.
So, for example, you could also do this:
o2 = Object.create({}, { p: { value: 42, writable: true, enumerable: true, configurable: true } });
Here's you are not just specifying the value of 42, but also some options for that property. If there wasn't the extra level of object hierarchy here, then you wouldn't have a place to put those extra options.
Yes, it does seem inconvenient when you only want the simple case. But, you could easily write yourself a helper function that made the simpler syntax work:
function myCreate(proto, props, enumerable, writable, configurable) {
// last three arguments are optional - default them to true if not present
if (typeof enumerable === "undefined") {enumerable = true;}
if (typeof writable === "undefined") {writable = true;}
if (typeof configurable === "undefined") {configurable = true;}
var wrapper = {};
for (var i in props) {
wrapper[i] = {
value: props[i],
enumerable: enumerable,
configurable: configurable,
writable: writable
};
}
return(Object.create(proto, wrapper));
}
Demo here: http://jsfiddle.net/jfriend00/vVjRA/