How to console.log all inherited properties? - javascript

Sorry for noob question. I'm just learning JavaScript.
I have an easy Object.
var bike = {
wheels: 2,
};
I create a new one that inherits all the bike values via create() and add some new properties to new Object.
var raleigh = Object.create(bike);
raleigh.color = 'red';
When I do console.log on new raleigh Object I can't see propeties inherited from bike Object.
console.log(raleigh);
The log is:
{ color: 'red' }
How to log to console all properties including these inherited?

When an object is printed through console.log, it is printed with all its own properties and a link to the object it inherits from. You can see all the inherited properties in console, you just need to follow the prototype chain of the displayed object (typically using __proto__ or [[prototype]] keys).

When you use Object.create then your prototype will be the same the object that you are inheriting, so, to show "father" properties you could see the prototype:
console.log(raleigh);
console.log(Object.getPrototypeOf(raleigh));
Maybe you will expect something more but I think that is the fast way to show that properties.

Would this help?
I'm throwing an alert, u can check the console as well!
var bike = {
wheels: 2,
};
var raleigh = Object.create(bike);
raleigh.color = 'red';
function getAllProperties( obj ) {
var properties = [];
do {
properties= properties.concat(Object.getOwnPropertyNames( obj ));
} while ( obj = Object.getPrototypeOf( obj ) );
return properties;
}
alert(getAllProperties(raleigh));
console.log(getAllProperties(raleigh));

You could create a new Object especially for your log which has everything as own properties
function flatten_inheritance(e) {
var o = Object.create(null), i, prop;
do {
prop = Object.getOwnPropertyNames(e);
for (i = 0; i < prop.length; ++i)
if (!(prop[i] in o))
o[prop[i]] = e[prop[i]];
} while (e = Object.getPrototypeOf(e));
return o;
}
flatten_inheritance(raleigh); // Object {color: "red", wheels: 2, valueOf, toString, etc..}
If you want to stop at Object.prototype or some other prototype you can do this in the while condition for example;
while (e = Object.getPrototypeOf(e) && e !== Object.prototype);
I would recommend you only do this when debugging rather than moving all your code away from inheritance though

Related

Are there lifecycle callback functions for javascript objects such as array & string

Ok guys I've been messing about with prototypes for a while now and am not ready to give up on their usefulness just yet... despite heavy criticism!
I'm battling the age old problem of Object.prototype property inheritance in other objects such as arrays & strings. ie:
Object.defineProperty(
Object.prototype, 'jsf',
{get:function(){
return JSON.stringify(this);
}};
);
x = {abc: 123};
y = document.createElement('div');
If you're reading this page, and you are!, then you will know that because both x & y are objects, based on typeof x or y, both x & y will inherit the jsf property, ergo:
x.jsf = {"abc": 123}
y.jsf = Uncaught TypeError: Converting circular structure to JSON
Now I know there are various work-rounds like:
Object.defineProperty(y, 'jsf', {value: void 0});
And my favorite:
function Master_Object(){ this.jsf = JSON.stringify(this) }
function Master_Element(){ this.str = this.outerHTML }
Object.defineProperty(
Object.prototype, 'ms',
{get:function(){
cons=this.constructor.name;
if(cons=='Object') return new Master_Object();
else if(cons=='HTMLDivElement') return new Master_Element();
}}
);
Where every object only has 1 manageable custom property, .ms, and that property is an object containing properties specific to the objects constructor, thus:
x.ms.jsf = {"abc": 123}
y.ms.jsf = undefined
y.ms.str = <div></div>
x.ms.str = undefined
Favorite or not I don't want to have to type the prefix .ms, it's untidy and frankly in the way!
I've been playing with custom elements and I know about the life-cycle callbacks, and how they track the progression of an element...
var proto = Object.create(HTMLElement.prototype);
proto.createdCallback = function() {...};
proto.attachedCallback = function() {...};
var XFoo = document.registerElement('x-foo', {prototype: proto});
Thing is I can't seem to translate these callbacks to be used on an object scope as opposed to an element scope?!
It would save me a lot of hassle if I could just write something along these lines:
Object.defineProperty(
Object.prototype, 'createdCallback',
{value: function(){
var Proto_Clone = Object.create(Object.prototype);
var cons = this.constructor.name;
if(cons == 'Object'){
Object.defineProperty(Proto_Clone,'...',{value:...});
}
else if (cons == ...) ...;
this.prototype = Proto_Clone;
}}
);
The idea being that when an object is instantiated, a check is performed on it to ascertain it's constructor and if the said constructor is Object then it's prototype is changed to the modified Proto_Clone before it is parsed.
That way the original Object.prototype is never modified and there is no leakage of properties from one object to the next...???!!!
So what do YOU think ? Is it possible, and if so how?
You could use try/catch:
Object.defineProperty(
Object.prototype, 'jsf',
{get:function(){
try {
return JSON.stringify(this);
} catch (e) {
return undefined;
}
}};
);

Object property in prototype

I have a problem I can't solved because I can't explain this behaviour :
var A = function(value) {
this.prop = value;
};
A.prototype = {
prop: 0
};
var a = new A(1);
var b = new A(2);
console.log(a.prop);
console.log(b.prop);
output :
1
2
But, with this code (almost the same) :
var A = function(value) {
this.prop.value = value;
};
A.prototype = {
prop: {
value: 0
}
};
var a = new A(1);
var b = new A(2);
console.log(a.prop.value);
console.log(b.prop.value);
I have this output :
2
2
Can anybody explain me this ?
Thanks...
EDIT :
Here's a solution :
var A = function(value) {
this.prop = {};
this.prop.value = value;
};
A.prototype = {
};
var a = new A(1);
var b = new A(2);
console.log(a.prop.value);
console.log(b.prop.value);
In example 1, this.prop is a primitive type, which is referenced by value and thus not shared between instances.
In example 2, this.prop is an Object whose reference is initialized from the prototype from a single object, so this single object is shared by all instances.
In the last "example" solution, you create a new object with = {}, so all instances now have their own object.
More details about primitive types : Primitive value vs Reference value
prototype is created only once and it's only a simple object whose childs are attached for all instances of a function it belongs to.
So it's basically the same as if you write:
var obj = { value: 0 };
var a = {}, b = {};
a.obj = obj;
b.obj = obj;
obj.value = 2;
as you can see both a.obj and b.obj references to the same obj and both a.obj.value and b.obj.value will be 2 in this example
This is happening because in JS, objects are passed by reference, while primitives are not.
Since the prototype is shared between the 2 instances, modifying a object on it will update all instances.
Think of a prototype property as a property shared amongst all instances.
Yet you can override it on each instance, that 's what you do in the first example.
Once overriden in each instance, you do not access any more to the prototype property with obj.prop, which now refers to the instance property. You would need to use obj.prototype.prop to read it again, but this syntax is illegal : you can use obj.__proto__.prop (non standard) or Object.getPrototypeOf(obj).prop (EcmaScript 5) to do so.
In the second instance, you do not change the property in the constructor : rather you change a property of this property. So both constructor access to the very same object, then change one of its property value, so the last to set it will 'win'. Here the prototype property is not overriden ('hidden') by the instance property and accessing obj.prop in fact access 'obj.prototype.prop'.

When updating an array in a JavaScript object the prototype is updated. Why?

Kind of strange thing is happening with my code. What I observe is something like this:
var prototype = {
property : "",
array : []
}
var objectArray = [];
function myFunction {
objectArray[0] = Object.create(prototype);
objectArray[1] = Object.create(prototype);
objectArray[0].property = "Hello 1";
objectArray[0].array.push("Hello 1");
objectArray[1].property = "Hello 2";
objectArray[1].array.push("Hello 2");
// At this point when running the program I get:
// objectArray[0].property == "Hello 1"
// objectArray[1].property == "Hello 2";
// objectArray[1].array == objectArray[1].array == prototype.array
// == ["Hello 1", "Hello 2"]
}
What I want, and expected, was two separate arrays for the two objects. What am I missing here?
In JavaScript, objects are copied by reference, so both objectArray objects are simply references to the same object ( prototype ). You need to clone the object or create instances using the new keyword and a constructor to create separate objects.
Example on how to do it using the new keyword:
var prototype = function() {
this.property = "";
this.array = [];
};
objectArray[0] = new prototype();
objectArray[1] = new prototype();
You can also do:
var prototypeFactory = function() {
return {
property: "",
array: []
};
};
objectArray[0] = prototypeFactory();
objectArray[1] = prototypeFactory();
The prototype object exists the same as the [[Prototype]] for each object. They don't get a fresh copy when you use Object.create().
You'd need to use assignment, which never walks the prototype chain.
I wonder if you aren't asking yourself "why does it work for property, but not for array?". The fact is, it doesn't work for property either, JavaScript is fooling you.
When objects share the same prototype, one must consider that:
All properties of the prototype are shared by the objects that inherit from that prototype.
You cannot assign to properties of the prototype, only read them (unless it's an accessor property, but let's keep that aside).
So what's actually happening here:
objectArray[0].property = "Hello 1";
objectArray[1].property = "Hello 2";
is that a new own property called "property" is being created on each object, while prototype.property remains untouched. The array property is behaving differently because you're not assigning to it, you're accessing prototype.array and calling the push method on it.
Don't forget that Object.create() isn't yet standardized, and won't work in IE8 or FF3.6. A simple work-around to clone an object is to use the JSON object:
function clone(obj) {
return JSON.parse(JSON.stringify(obj));
}

Proper way to create object

What's the proper way to create an object (with its "namespaces" and such)?
1
//Company object
var Microsoft = {};
//Create an employee
Microsoft.employee = function(name) {
this.name = name;
}
or
2
//Company object
Apple = {
employee: function(name) {
this.name = name;
}
}
OR another way? Shoot.
Read something about prototypes and such. What's the proper way to do it; benefits and downsides?
First off, you forgot the var for Apple. But otherwise these are basically the same thing.
Secondly, in my examples I'm not going to use the attribute name since, when dealing with functions, the name is an empty string by default. At least in Node.js and Chrome. So I'll use empName instead.
In the Microsoft example you are making an empty object and then adding an attribute to it after the fact.
In the Apple example you are making an object with the attribute right away.
It's really just what makes the most sense to you, and which you prefer. Since they are, more or less, equivalent.
Now, this has nothing to do with prototypes. Here's an example of what you did:
var Apple = {
employee: function(empName) {
this.empName = empName;
}
};
Apple.employee('Hank');
Apple.empName; // 'Hank'
And here's how you would do this with an instance (using the new operator, and the prototype)
var Apple = function() {}; // base 'parent'
Apple.prototype.employee = function(empName) {
this.empName = empName
};
var a = new Apple();
a.employee('Hank');
a.empName; // 'Hank'
Apple.empName; // undefined
So prototype is used to add attributes to new instances of an object (using 'object' loosely). Note that to access employee in Apple, on this second example, you would have to do something like
Apple.prototype.employee('Hank'); // doesn't really do much
Apple.empName; // undefined
// but you can call the employee prototype with a bound variable
// you'd do this if you don't want to make an instance of Apple
// but still want to use one of it's prototypes
var obj = {};
Apple.prototype.employee.call(obj, 'Hank');
obj.empName; // 'Hank'
// a practical use of accessing a prototype method is
// when wanting to convert a function's arguments
// to an array. function arguments are like an array,
// but until turned into one they are not completely the same
var func = function() {
var args = Array.prototype.slice.call(arguments);
var sum = 0;
for(var i = 0, l = args.length; i < l; i++) {
sum += args[i];
}
return sum;
};
func(1); // 1
func(1, 2, 3, 4, 5); // 15
Hope that helps.
EDIT: Also, don't prototype objects (e.g. {} or Object). It's not safe to do this. Since, essentially, every variable in JavaScript is an object, then any prototypes you add to them will be available on all variables. So if you did Object.prototype.xyz = 12 then had var obj = { a: 1, b: 2, c: 3} and then tried for(var key in obj) { console.log(key); } you would result in the following logs: a, b, c and xyz ... which you wouldn't want.

Cloning a JavaScript object? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How to clone js object?
This is another way to create a javascript object (using object literal notation instead of function):
user = {
name: "Foo",
email: "bar#baz.com"
}
Is there a way to clone this object or is it a singleton?
Try this:
var clone = (function(){
return function (obj) { Clone.prototype=obj; return new Clone() };
function Clone(){}
}());
Here's what's going on.
Clone is a dummy constructor.
We assign the object we want to clone to the Clone constructor's prototype.
We call Clone using 'new', so the constructed object has the original object as its constructor's prototype aka (non-standard) __proto__.
The cloned object will share all the properties of the original object without any copies of anything being made. If properties of the cloned object are assigned new values, they won't interfere with the original object. And no tampering of built-ins is required.
Keep in mind that an object property of the newly-created object will refer to the same object as the eponymous property of the cloned object. Assigning a new value to a property of the clone won't interfere with the original, but assigning values to the clone's object properties will.
Try this in chrome or firebug console:
var user = {
name: "Foo",
email: "bar#baz.com"
}
var clonedUser = clone(user);
console.dir(clonedUser);
A detailed explanation of this cloning technique can be found here.
You can use JSON object (present in modern browsers):
var user = {name: "Foo", email: "bar#baz.com" }
var user2 = JSON.parse(JSON.stringify(user))
user2.name = "Bar";
alert(user.name + " " + user2.name); // Foo Bar
See in jsfiddle.
EDIT
If you need this in older browsers, see http://www.json.org/js.html.
I like to use this:
if (typeof Object.create !== 'function') {
Object.create = function (o) {
var F = function () {};
F.prototype = o;
return new F();
};
}
then any object I want to clone can be done as:
user = {
name: "Foo",
email: "bar#baz.com"
};
var user2 = Object.create(user);
As shown in (or similar to) JavaScript The Good Parts
Most of the javascript frameworks have good support for object cloning.
var a= {'key':'value'};
var b= jQuery.extend( true, {}, a );
Object.prototype.clone = function clone(obj) {
obj = obj || this;
var new_obj = {};
for( var p in obj ) {
if ( obj.hasOwnProperty(p) ) {
if( obj[p] !== null && typeof(obj[p]) === "object" ) {
new_obj[p] = clone( obj[p] );
}
else {
new_obj[p] = obj[p];
}
}
}
return new_obj;
};
/* Example */
var foo = {
name: "Foo"
, email: "bar#baz.com"
, obj: {a:"A",b:"B"}
};
var bar = foo.clone();
bar.name = "Bar";
bar.obj.b = "C";
// foo and bar should have a different 'name'
// foo and bar should retain the same email
// foo and bar should have different values for <foo/bar>['obj']['b']
// foo and bar should have the same values for <foo/bar>['obj']['a']
console.dir(foo);
console.dir(bar);

Categories