The constructor property - Relate Pre-existing Objects? - javascript

I'm currently trying to test whether it's possible to make one object inherit from another object AFTER both objects have been created using literals. I tried to aim the constructors and prototypes at one another but it seems like no matter what, the only way Im going to pull this off is by building a new object using one of the pre-existing ones.. Let me know if I'm wrong. Here was my quick attempt to solve the problem.
Object.relate = function(parent, child){
function F(){};
F.prototype = parent;
child.constructor = F;
}
alpha = {a:1};
beta = {b:2};
Object.relate(alpha, beta);

In your code beta can access properties defined on alpha by using beta.constructor.prototype.
When you use new on a function like
var obj = new F();
then obj.__proto__ is automatically set to F.prototype. When you have already existing objects and you are not creating the object using new you must set the __proto__ by yourself.
obj.__proto__ = F.prototype;
So in your example you need to call
child.__proto__ = parent;
Resources:
https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/proto
http://killdream.github.com//blog/2011/10/understanding-javascript-oop/index.html#sec-4-1
The problem is that now every browser expose the __proto__ property. IE doesn't support it so you cannot create a browser-compatible solution without actually creating a new object and copying the properties.

This method seems to work for me (tested in Chrome):
function relate(parent, child){
child.__proto__ = parent;
}
alpha = {a:1};
beta = {b:2};
relate(alpha, beta);
console.log(beta.a);
Output: '1'.

Related

Correct way to pass prototype to an object

My understanding of prototypes is as follows:
let Animal = function() {
this.bark = "woof";
}
Animal.prototype.barkLoud = function() {
return this.bark.toUpperCase();
}
let x = new Animal();
x.barkLoud() = "WOOF";
Everything above makes sense to me but then I saw a tutorial what seemingly appears to be 2 different ways to pass prototypes to an object. Are these the same thing? If so, which approach is better:
let obj = {
age: 45;
__proto__: Animal
}
vs
let obj = {
age: 45;
}
obj.prototype = Object.create(Animal.protoype);
As a rule of thumb, the more underscore (_) characters you see around a property name in JS, the more of implementation details it is - and the more discouraged you are from even querying it, let alone attempting to modify.
While __proto__ is indeed supported by all the existing browsers, its usage to set up a prototype is not recommended. Use Object.create() instead.
BTW, two ways you've showed are not even equivalent. See, __proto__ refers to the prototype object, but Animal is not the one - it's a function. Animal.prototype is an object that will be used as a prototype (__proto__ value) for all the objects created by this function with new` operator.
So the first object won't be able to resolve barkLoud name from the prototype chain:
> obj.barkLoud // undefined
__proto__ way is deprecated by the way and I've never seen it implemented anywhere.
Go with Object.create as the official and recommended way to create/assign prototype of existing object to the newly created object.

Making an object created by JSON.parse inherit from another class

I receive a bunch of objects via JSON which ultimately need to have some instance member functions.
Is there a way to do this without copying the data?
For example:
var DataObject = function() {};
DataObject.prototype.add = function() { return this.a + this.b; };
var obj = JSON.parse('{"a":1, "b":2}');
// Do something to obj to make it inherit from DataObject
console.assert( obj.add() === 3 );
I've tried setting obj.prototype = DataObject.prototype but that doesn't seem to work. What am I missing?
Well, in ECMAScript6 (in IE11, and every other non ie browser today), that would be __proto__
obj.__proto__ = Object.create(DataObject.prototype);
[fiddle]
Generally, make sure you only do this at the object creation case, otherwise it can be very risky to do.
Also note, setting the protoype explicitly is not always faster than copying two properties, as you can see here so you have to be sure there is actual gain here.

IE9 does not recognize prototype function?

I'm working on an AngularJS SPA and I'm using prototypes in order to add behavior to objects that are incoming through AJAX as JSON. Let's say I just got a timetable x from an AJAX call.
I've defined Timetable.prototype.SomeMethod = function() and I use https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/setPrototypeOf in order to set the prototype of x to TimeTable.prototype. I have the polyfill in place too.
If I call x.SomeMethod() this works in IE > 9, FF, Chrome etc. However, IE 9 gives me a headache and says throws an error stating 'x does not have property or member SomeMethod'.
Debugging in IE shows me that the _proto_ of x has SomeMethod() in the list of functions, however, calling x.SomeMethod() gives the same error as described.
How can I make this work in IE9 ?
More comment than answer
The main problem with "extending" a random object retrieved from some other environment is that javascript doesn't really allow random property names, e.g. the random object may have a property name that shadows an inherited property. You might consider the following.
Use the random object purely as data and pass it to methods that access the data and do what you want, e.g.
function getName(obj) {
return obj.name;
}
So when calling methods you pass the object to a function that acts on the object and you are free to add and modify properties directly on the object.
Another is to create an instance with the methods you want and copy the object's properties to it, but then you still have the issue of not allowing random property names. But that can be mitigated by using names for inherited properties that are unlikely to clash, e.g. prefixed with _ or __ (which is a bit ugly), or use a naming convention like getSomething, setSomething, calcLength and so on.
So if obj represents data for a person, you might do:
// Setup
function Person(obj){
for (var p in obj) {
if (obj.hasOwnProperty(p)) {
this[p] = obj[p];
}
}
}
Person.prototype.getName = function(){
return this.name;
};
// Object generated from JSON
var dataFred = {name:'fred'};
// Create a new Person based on data
var p = new Person(dataFred);
You might even use the data object to create instances from various consructors, e.g. a data object might represent multiple people, or a person and their address, which might create two related objects.
This is how I solved it at the end:
Object.setPrototypeOf = Object.setPrototypeOf || function (obj, proto) {
if (!isIE9()) {
obj.__proto__ = proto;
} else {
/** IE9 fix - copy object methods from the protype to the new object **/
for (var prop in proto) {
obj[prop] = proto[prop];
}
}
return obj;
};
var isIE9 = function() {
return navigator.appVersion.indexOf("MSIE 9") > 0;
};

Whats the neatets way to declare two arrays on two keys in an object in javascript?

This is how I do it now. It feels like a hazzle...
var broken_posts = new Object();
broken_posts.empty = new Array();
broken_posts.one = new Array();
var broken_posts = { empty: [], one: [] };
var broken_posts = {
empty: [],
one: []
};
The answers by Andru and Thilo are both correct, but perhaps some information on why is in order:
Avoid direct calls to the Array constructor: it's confusing and misleading. var a = new Array(5); returns [undefined,undefined,undefined,undefined,undefined], whereas var b = new Array('5'); returns ['5']. Or even var c = new Array(5,5); => [5,5].
Same applies for the direct object constructor. There's really no reason to create an object calling the basic object constructor. The only times you should use the keyword new is when creating a date object, or calling a self-made constructor function (and even in that case, there's no real need for the new keyword, there are alternative design patterns). Using the object literal {} is more common, allows for direct assignment of properties (and even methods). Besides, It's so much easier to create your objects in a JIT sort of way. Not only does it require less lines of code, with correct use of closures, or just for the one call, an object can get GC'ed once you're finished with it.
function iWantAnObject(obj)
{
if (obj instanceof Object)
{
return true;
}
return false;
}//function returns, obj is GC'ed
iWantAnObject({just:'some',rand:'Object',withA:function(){console.log('a method';}});
As opposed to this scenario:
var tempObj = new Object();
tempObj.just = 'some';//etc...
//etc...
iWantAnObjct(tempObj);
//tempObj isn't yet GC'ed
In the last example chances are: you accidentally create global variables, have various objects in memory that are no longer required, and, last but not least: isn't very in tune with the prototypal nature of JS.
I would prefer to use CoffeeScript instead.
Then you can do it this way:
broken_posts =
empty: []
one: []

mootools Type function

So I am trying to learn javascript by learning how Mootools works internally. I am looking at these lines specifically:
var Type = this.Type = function(name, object){
if (name){
var lower = name.toLowerCase();
var typeCheck = function(item){
return (typeOf(item) == lower);
};
Type['is' + name] = typeCheck;
if (object != null){
object.prototype.$family = (function(){
return lower;
}).hide();
}
}
if (object == null) return null;
object.extend(this);
object.$constructor = Type;
object.prototype.$constructor = object;
return object;
};
//some more code
new Type('Type',Type);
What is happening here?
What is the object being assigned to in the constructor statement down at the bottom, the global window object?
Why is it being called as a constructor with the new statement when the Type function seems to only update the passed in object rather than creating a new one?
Specifically what is 'this' in the line object.extend(this); ? is it the global window object, if so is it adding all the key, value pairs of that object to the Type object?
Sheesh, questions lately seem to focus a lot more on mootools internals.
I will answer to the best of my knowledge as I am not a core dev.
Type in MooTools is pretty similar to Class (in fact, the Class constructor itself is a Type) but it focuses more on data / values and the Types of values. It also is meant to extend the native Types defined by ECMA spec and make them more flexible.
I guess there is no point in talking about data types in general (String, Number, Array, Object, etc). Why is there are need to extend them? Well, for starters, Duct Typing is a little quirky in js. typeof {}; // object, typeof []; // object, typeof new Date(); // object etc - not the most helpful, even if since all types inherit from object and is logical for them to be grouped together, it does not help you write code.
So, in the context of js objects, they are created from constructor objects...
What Type does is not replace the constructor functions but changes an existing constructor by adding new methods or properties to it.
eg. new Type('Array', Array);
This will turn the native Array constructor into a type object of sorts. You don't need to save the result or anything - it's a one off operation that mods the original and leaves it open for manipulation.
typeOf(Array); // type
So, what is different? Well, for starters, typeOf([]) is now able to actually tell us what it really is - array. And what really happens here is this: object.extend(Type);, the magical bit. It will copy to the target object all the properties defined on the Type object - you can see them here:
https://github.com/mootools/mootools-core/blob/master/Source/Core/Core.js#L211-232
So, immediately, your newly created Type gets the all important implement and extend methods.
More advanced, let's create a new type that is based on the native Array constructor:
var foo = new Type('foo', Array),
a = new foo();
// it's a real boy!
a.push('hi');
// ['hi'], foo, object
console.log(a, typeOf(a), typeof a);
But, what if we wanted a custom Type? One that is magical and special? No problem, because argument 2 can actually be a (anonymous) function.
var Awesome = new Type('awesome', function(name, surname) {
// console.log('I R teh construct0r!');
this.name = name;
this.surname = surname;
});
// extend it a little.
Awesome.implement({
getName: function() {
return this.name;
},
getSurname: function() {
return this.surname;
}
});
var Dimitar = new Awesome('dimitar', 'christoff');
console.log(typeOf(Dimitar)); // awesome
console.log(Dimitar.getName()); // dimitar
In another example, look at DOMEvent. It takes the above and makes it into a faster leaner Object type. https://github.com/mootools/mootools-core/blob/master/Source/Types/DOMEvent.js#L21
So why is that not a class? Because, Classes are more expensive and events happen all the time.
I hope this helps you somewhat. for a more detailed explanation, ask on the mailing list and hope for the best, perhaps a core dev will have time as it's not your standard 'how do I get the accordion working' type of question...

Categories

Resources