How to write JavaScript objects? [duplicate] - javascript

Is there any difference in how these functions operate? The first one is more typically of what I think about when thinking of a constructor.
Example 1: using this to name and set properties. Then using new to create a new Book object.
function Book(name, numPages) {
this.name = name;
this.numPages = numPages;
}
var myBook = new Book('A Good Book', '500 pages');
Example 2: returning a object by using new and just calling the function itself.
function Movie(name, numMinutes) {
return { name:name, numMinutes:numMinutes };
}
var best = new Movie('Forrest Gump', '150');
var other = Movie('Gladiator', '180');
I guess what I'm trying to figure out is if these are different in the way they create an object? If so is one better than the other? Are there different situations where one would work better over the other?

The first one is a constructor, and can therefore be extended by a prototype, and you can test via instanceof wether the result is an Instance of this type.
Downside: if you forget the new-keyword your code will blow up (unless you write a workaround for that into each constuctor)
And you can't really use apply() with a constructor to pass an array of arguments, when you instantiate a new Object; on the other hand, don't do that, even if you can/could.
The second one is a factory, not a constructor. Independant wether you use the new-keyword or not.
with this implementation it creates Objects that look the same but don't share a type or prototype (although the underlying JS-engine recognizes them as similar and so they share the same hidden Class as long as they have the same properties, added in the same order, ... different topic)
long story short, neither performance nor memory-footprint suffer from this approach (anymore)
But you can't check wether they are of the same type, and you don't have a shared prototype that may affect all instances (maybe a pro or a con.)
My goto-approach If I need inheritance, is kind of a mix of both:
(if I just need a data-object I usually use a factory and plain objects).
function Book(conf) {
var book = Object.create(Book.prototype);
//a book like this usually has multiple configs/properties
if(typeof conf === "object"){
for(var k in conf) book[k] = conf[k];
}else if(conf){
//assuming that I get at least the name passed
book.name = String(conf);
}
return book;
}
//I have a prototype that can be extended
//with default-values for example; no idea for a good method
//to add to the prototype in this example ;)
Book.prototype.numPages = 0;
//but I can also use it like a plain function; no error if you
var myBook1 = Book("Peter Pan");
var myBook2 = Book({
name: "American Gods",
author: "Neil Gaiman"
});
If I add the following line to the top of the function I can also use that as a method to cast anything into an Instance of Book without cloning already existing instances
function Book(conf) {
//with this simple line I can also use this as a function to cast anything into a "Book"
if(conf instanceof Book) return conf;
var book = Object.create(Book.prototype);
//...
return book;
}
var data = [
"Peter Pan",
{name: "American Gods"},
//...
];
var books = data.map(Book);
In my opinion, I have the benefits of both worlds with this approach.

Basically, when you use new, the JS engine makes a brand new object for you and injects that as the value of this. It also automatically gives you any methods attach to the prototype of the constructor. Using a constructor also allows you to check if an object is an instanceof something more easily.
function MovieA(title) {
this.title = title;
}
MovieA.prototype.getTitle = function() {
return this.title;
};
function MovieB(title) {
return {
title: title
};
}
MovieB.prototype.getTitle = function() {
return this.title;
};
var a = new MovieA('A');
console.log(a instanceof MovieA); // true
console.log(a.getTitle()); // 'A'
var b = MovieB('B');
console.log(b instanceof MovieB); // false
console.log(b.getTitle()); // Uncaught TypeError: b.getTitle is not a function
Everything that new offers you can be attained through other methods but requires more manual labor.
The second method, factories, tend to work better for unit testing, custom object creation and functional programming. It works better for unit testing because if you have a factory producing all of your objects, you can just replace that factory with a mock-up to test different cases.
var Factory = {
makeThing: function() {
return { name: 'thing' };
}
};
// Want to test the case for if makeThing fails inside of some other code
var MockFactory = {
makeThing: function() {
return null;
};
};
As for when you use either, it all depends. Some people don't use new at all. Others exclusively use new. It all depends on if you need any of the things listed above, how much control you need over the creation of objects, when you want to use this or not, etc. In the end, it's all a matter of preference.

The difference is the constructor used to create the object returned.
new Book('A Good Book', '500 pages');
creates a Book object instance, with the instance inheriting properties from Book.prototype, including a constructor property value of Book. The Book.prototype object itself inherits from Object.prototype.
var other = Movie('Gladiator', '180');
uses Movie as a factory function (new not required) and returns an Object object instance, with the instance inheriting properties directly fromObject.prototype, including a constructor property value of Object.
More briefly stated, Object literal syntax creates an Object object.

Related

Crockford Constructor: As Own Property versus Attached to `__proto__`

The title may sound a bit confusing. Please allow me to cast Crockford's constructor into the following simple example and create objects using two different ways. (Browser is FireFox.)
var car = function(carSpec) {
var maker = carSpec.maker;
var year = carSpec.year;
var that = {};
that.getMaker = function () {
return maker;
};
that.getYear = function () {
return year;
};
return that;
};
One way to create an object, as Crockford pointed out, is to use Object.create method,
myCar = Object.create(car({maker: 'Nissan', year: 2004}));
console.log(myCar); // Object {}, on FireFox console.
and the methods getMaker and getYear are attached to the __proto__.
The other way is to invoke car and let it return an object
yourCar = car({maker: 'Ford', year: 2010});
console.log(yourCar); // Object { getMaker: car/that.getMaker(), getYear: car/that.getYear() }
and methods getMaker and getYear becomes the own properties of object yourCar.
My questions is: What are the pros and cons of these two ways of object creation from this "Crockford constructor"?
It makes no sense to call Object.create when you already have the complete object that you want. Inheritance is only useful when you have multiple objects that are supposed to share common properties, but in your example getMaker and getYear are own properties of each car instance.
The advantage of having methods in __proto__ or prototype is multiple copies of created objects will point to the same methods. Meaning only one copy of each method will be created. Less(relatively) usage of memory. If the methods are attached to the objects itself then each object will have its own copy of the methods.

JS Object composition via functions adding prototype functions

I have been fiddling around with object building via composition in Javascript (specifically NodeJS) and I have come up with a way of building up my objects but I need to know if this is an insane way of doing things.
The simple version is this:
I have two objects, both have two properties, one holding a number and the other holding a string.
File: Cat.js
function Cat() {
this.name = 'Fuzzy Whiskerkins';
this.owner = 'James';
}
module.exports = Cat;
File: Car.js
function Car() {
this.color = 'blue';
this.owner = 'James';
}
module.exports = Car;
I would like to now add a basic getter/setter function for all properties in both of these objects. I would also like to be able to check that the value passed into these setters matches the type. Instead of writing four prototype functions for each of these properties I have done the following:
File: StringProperty.js
module.exports = function(newObject, propertyName) {
newObject.prototype[propertyName] = function( newString ) {
if ( typeof newString !== 'undefined' ) {
if ( typeof newString !== 'string' ) {
return;
}
this.properties.[propertyName] = newString;
return this;
}
return this.properties.[propertyName];
}
}
File: Cat.js
var StringProperty = require('./StringProperty.js');
function Cat() {
this.properties.name = 'Fuzzy Whiskerkins';
this.properties.owner = 'James';
}
StringProperty( Cat, 'name' );
StringProperty( Cat, 'owner' );
module.exports = Cat;
File: Car.js
var StringProperty = require('./StringProperty.js');
function Car() {
this.properties.color = 'blue';
this.properties.owner = 'James';
}
StringProperty( Car, 'color' );
NumberProperty( Car, 'owner' );
module.exports = Car;
Now both objects have all the basic functionality they need and I was able to do it with a minimal amount of code and whenever I need to add another string property the amount of code I will have to add will be minimal.
Am I crazy? Is this an insane thing to/is there a better way to be doing this?
EDIT:
What I am trying to accomplish with this is the application I am working on has 100+ objects and each with 10+ properties and the idea of having to write almost the exact same code for every single one of those properties does not set well with me. I would prefer to be able to have a bit of code that adds the property and creates the getter/setter functions (with adding options for divergence in property restrictions such as different length restrictions on string properties). I have looked at multiple examples of object construction via composition in JS but nothing I tried fit into the NodeJS module structure.
Your solution will not work. You're shadowing the accessor method as soon as you set a value. Also, why are you testing for typeof !== "number" on in a method that expects a string?
Resolving those issues, your type checking just silently exits. You'll hate that once you try to set a value and can't figure out why it's not setting. I'd use TypeScript if you want a stronger type system.
I think you'd be better off trying to write idiomatic JS code. Use the features the language provides in their simplest and most direct manner. Don't try to be too clever with these constructs. Before JS had all its new features, people tried stuff like this, and it never seemed to go that well.

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