best way to add back constructor to object.create in javascript - javascript

I am fully aware of other very similar posts about object.create but I really cannot arrive to answer on this particular question.
I saw a code once where it looks like it was using object.create to create new prototype and then adding back to constructor
function blah(){
// typical constructor
}
blah.prototype = Object.create(somethingelse.prototype);
blah.prototype.constructor = blah;
Something like that .. and I tried that in chrome dev tool but did not see them as equal.. Now trying to see what that code I did see was trying to accomplish? I assume there is more difference in Object create and new(than just missing constructor?)
function blah(){
//...
}
undefined
function somethingelse(){
//
}
undefined
somethingelse.prototype = {
// something else
}
Object {}
blah.prototype = Object.create(somethingelse.prototype);
Object {}
blah.prototype.constructor = blah;
blah(){
//...
}
blah == somethingelse;
false

You've created two different objects (blah and something).
I think you are confused about what inheritance means.
when you compare (==) 2 objects the reference is being evaluated - and it is different.

Related

Object.create() JavaScript

I am quoting this statement from the JavaScript Definitive Guide book in section 6.1.4 Object.create(). The following statement doesn't seem clear to me.
You can pass null to create a new object that does not have a prototype, but if you do this, the newly created object will not inherit anything, not even basic methods like toString() (which means it won't work with the + operator either)
var o2 = Object.create(null) // o2 inherits no props or methods.
At this point, I was thinking "Oh Wow". It doesn't inherit any basic methods, when you set Object.create(null). So, I tried to give it a try on console to see if this was really the behavior. I ran the script that is below, and got an unexpected result.
var o2 = Object.create(null);
o2.number = 1;
console.log(o2.number.toString()); // "1"
When I ran this code, I was thinking that the .toString was not going to work. I am bit confused or may not understand how things are working here. I was wondering if anyone could clear things up for me. Any help will be appreciated, and thanks for the time for reading my problem. :)
You're calling toString on the number property, which is not the object itself. If you were to try o2.toString(), it would not work.
toString works in your example because you're running it on a number, not the object itself.
It works because it's no different than this:
var n = 1;
console.log(n.toString());
To see the results of no prototype, try this instead:
var o2 = Object.create(null);
console.log(o2.toString());
When you do ...
o2.number = 1
... you're creating a property named number and adding that property to your o2 object.
When you do ...
o2.number.toString()
... you're executing toString not on o2, but on property o2.number.
If you do...
console.log(typeof o2.number)
... you'll see that o2.number has type number, and thus has all methods associated with numbers.
If you do ...
console.log(typeof o2)
... you'll see that o2 has type object.
If you try executing o2.toString, you'll get an error and see that this object indeed doesn't have any method named toString.
Note :
In my experience, you probably don't ever want to do something like ...
var o2 = Object.create(null);
o2.number = 1;
What you probably want instead, is something like ...
var o2 = Object.create(Object.prototype);
o2.number = 1;
... which can can be written more elegantly like ...
var o2 = {
number : 1
};
There is little to no advantage with creating objects that do not inherit from Object.prototype. And if other people end up using your code, you're likely to confuse the heck out of other developers when they're trying to call eg. hasOwnProperty or toString on your object and they're getting an error (as they these methods expect to exist for any object).

Javascript Module Pattern doesn't give correct instanceof

Sometimes you think you know something, and then it turns out you really don't...
I've been doing a lot of research into the Javascript inheritance over the last few days for a talk I'm giving at a local tech group. No problem I figured, I know this stuff, I'll just brush up...
Turns out, I've lots still to learn. Here is the first thing that surprised me:
function Vehicle() {
function move() {
console.log('moving');
}
return {move: move}
}
function OtherVehicle() {
this.alsoMove = function() {
console.log('also moving')
}
}
The first method is what I've always understood the module pattern to be. The second, though I don't know it's name, I understood to be basically equivalent - just a minor syntactic variation.
Except:
(new Vehicle()) instanceof Vehicle \\ returns false
(new OtherVehicle()) instanceof OtherVehicle \\ returns true
new Vehicle() returns an 'Object'.
Looking at this, that makes sense, but it was not what I was expecting.
Can anyone explain what is going on here, why, and maybe point me at a really good resource that gets into the guts of this?
As a follow-up.
var Car = function() {
function drive() { console.log('driving') };
return {drive: drive}
}
Car.prototype = new Vehicle() //I know, Object.create preferred
(new Car).move() //undefined
// However...
var Car = function() {
this.drive = function () { console.log('driving') };
}
Car.prototype = new Vehicle();
(new Car()).move() //output 'moving'
So, the module pattern can't be used in inheritance?
Or have I just woken from the wrong side of the bed today and should go for a run before I next touch a keyboard?
I don't know of any particularly good resource, but here's some feedback anyway.
new Vehicle() returns an 'Object'.
The return {}, overrides the default return value this, which is the instantiated object. Calling such functions with new is pointless as this gets discarded. As far as OOP languages go, JavaScript is a bit odd in that it allows you to return another value for this in a constructor.
So yes, inheritance used that way won't work: {} itself is not in any way linked to a parent/base class, which is why
(new Car).move() //undefined
is undefined.

Javascript Dynamic object properties through functions returning strings

I'm building a Backbone Marionette Application. In Marionette you can do something like:
Marionette.Application.extend({
regions: {
mainRegion: function(){return someCondition?"#A":"#B"},
otherRegion: "#something"
}
})
I'm trying to implement this in my application with custom objects. What is the best way to achieve this?
Currently, I'm checking for every value:
if(typeof obj == "function") {
this.data.obj = obj();
}
else {
this.data.obj = obj;
}
or the corresponding ?: expression.
Is there an easier way to do this?
Underscore has a result method that does exactly what you want (see http://underscorejs.org/#result)
You can find the implementation here: http://underscorejs.org/docs/underscore.html#section-128
There is a potential solution (cue screaming) in adding value() [not to be confused with valueOf()] to every prototype you're interested in.
Function.prototype.value = function () { return this(); }; // Probably should be .call() so you can do arguments if necessary.
String.prototype.value = function () { return this; };
etc.
Then you can use this.data.obj = obj.value() for all calls.
If you're queasy about adding functions to prototypes, this isn't a solution you'd want to use. Otherwise you could write a wrapper function that takes obj as an argument and returns the right thing based on the type.
The duck typing idea proposed by dandavis is also good IMHO.

javascript create new method

using prototype method we can create new methods... like...
Object.prototype.newMethod=function(){
// do something
}
Here I am defining the newMethod with an anonymous function... now if I want to use this method, I have to use it like: <object>.newMethod();
But now I want to create a new method which I can use like: <object>.newMethod;... no brackets... How can I do that...??
please don't use any jQuery...
Erm, you can't. To call a method, you write parentheses after it. Otherwise you're just referencing it.
The only exception to this rule is when you write something like new Date, where the parentheses are implict due to the new keyword and only because there are no arguments given.
I can't really understand why you would want to do that, but it is possible, albeit with a nasty hacky workaround. What you're actually looking for, AFAIK, is a magic property (like the someArray.length property).
var foo = {val:'foo'};
foo.length = (function(that)
{
return function()
{
return that.val.length;
}
})(foo);
//at this point foo.length(); returns 3, but still requires parentheses
//so, build another closure, and assign a valueOf method to the lenth method:
foo.length.valueOf = (function(method)
{
return function()
{
return method();//call the length method
}
})(foo.length);
console.log(foo.length +1);//logs 4
foo.val += 'bar';
console.log(foo.length);//logs 6
//BUT:: be carefull!!
alert(foo.length);//coerces to string, we haven't redefined the toString method, so the function code will be alerted
alert(foo.length + '');//alerts 6
This is just to show you that, yes it is theoretically possible, but please, please, don't use this kind of overly polluted hacks... I haven't thoroughly tested this, but ATM, I've already noticed that console.log(foo.length); can return a different value, not sure why, yet:
foo = {val:'foo'};
foo.length = (function(that){return function(){ return that.val.length;};})(foo);
foo.length.valueOf = (function(method){return function(){return method();};})(foo.length);
foo.length;//returns 3, great
foo.val += 'bar';
console.log(foo.length);//logged 3 at first, now it's back to logging 6!<-- don't trust this is the conclusion
The only way to call a function without parenthesis would be to define it using getters and setters.
Note these are new to JavaScript 1.8 and are not supported by all browsers.

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