So JavaScript is a functional language, classes are defined from functions and the function scope corresponds to the class constructor. I get it all now, after a rather long time studying how to OOP in JavaScript.
What I want to do is not necessarily possible, so I first want to know if this is a good idea or not. So let's say I have an array and a class like the following:
var Entry = function(name, numbers, address) {
this.name = name;
if(typeof numbers == "string") {
this.numbers = [];
this.numbers.push(numbers);
}
else this.numbers = numbers;
this.address = address;
};
var AddressBook = [];
And I add contacts with the following function:
function addContact(name, numbers, address) {
AddressBook.push(new Entry(name, numbers, address));
}
Can't I make it so new Entry() would put itself into AddressBook? If I can't do this on create, it would be interesting to do it with a method in the Entry prototype as well. I couldn't figure out a way to do anything similar.
You could try passing the AddressBook array reference to the function like such:
var Entry = function(name, numbers, address, addressBook) {
this.name = name;
if(!(numbers instanceof Array)) {
this.numbers = [numbers];
}
else this.numbers = numbers;
this.address = address;
addressBook.push(this);
};
var addressBook = [];
function addContact(name, numbers, address) {
new Entry(name, numbers, address, addressBook)
}
Reconsider the design approach. The "Entry" object's primary role is Information Holder. You should encapsulate the AddToAddressBook functionality in some sort of a controller or eventHandler.
Details
You've got more than 1 responsibility and it's generally not a good idea to tightly couple the 2 concerns. (e.g. Design principles involved Single Responsibility Principle and Separation of Concerns.)
Information holder – an object designed to know certain information and provide that information to other objects.
Structurer – an object that maintains relationships between objects and information about those relationships.
I'd suggest reading up on SOLID principles and try to keep each object's responsibilities narrowly focused. Your code will be less complex and easier to maintain and extend going forward.
Check out - http://aspiringcraftsman.com/series/solid-javascript/
There's a example of products and cart which is pretty close to your scenario above.
Related
Read about constructors in functions:
function Animal(name) {
this.name = name;
this.canWalk = true;
}
var animal = new Animal("Hedgehog");
and also about prototypes:
Animal.prototype.draw = function () {
}
But until the end I did not understand exactly how they reduce the code and, in principle, improve the life of programmers. Why? Because it is better understood on real examples from sites and not on examples of animal or "hedgehogs" of all sorts.
An example from my personal experience: I started the cycles well when I needed to prescribe a function for 30 images, but instead of 30 functions I passed one function into a cycle and reduced it the way the code, so I understood the whole essence of the cycle, and not just memorized its anatomy. That would be for learning resources to make examples of real projects beginners would not ask 100 questions of the same type.
Therefore, I have such questions:
Can you write here how the code would look at first without a prototype and then with a prototype on some small example from the site? Or an example that could be implemented on which site.
Can you write here how the code would look at first without a constructor and then with a prototype on some small example from the site? Or an example that could be implemented on which site.
But do not post in the responses or comments a link from the GitHuB with a large code. Just give a small example here. And it is desirable not an example from the game, but from the site
Using an object constructor is a way to initialize an instance with a specific functionality. In most cases it is used to initialize properties with values (like in your code), but can be used for other things as well.
Let use more realistic example - I can initialize a few users object simply by object literals:
const user1 = {
id: 'usr123',
name: 'Max',
questions: 4
}
const user2 = {
id: 'usr124',
name: 'Danny',
questions: 2
}
But there are few problems with this approach.
First, it can be tedious when used a lot.
Second, it's harder to distinguish it from other objects.
Both of these issues can be solved with construction function:
function User(id, name, questions) {
this.id = id;
this.name = name;
this.questions = questions ? questions : 0;
}
const user1 = new User('usr123', 'Max', 4);
const user2 = new User('usr125', 'Ben'); // default questions value would be 0
const isUser = user1 instanceof User; // true
Prototype is a special object which can be used on Objects which has a constructor function (Well, all objects are descendant of Object, but let's leave this aside for a moment). The basic idea is - if I have 100 user objects - I might have some use for have a special properties or logic which relevant for all of them, and not specific for a single instance. For example, let's assume that in case of error, I would like to log all the data of the users.
I can create a special function which get and object and do this:
function userToString(user) {
return user.id + ':' + user.name + '[' + user.questions + ']'; // usr123:Max[4]
}
This would work, but harder to maintain, since it is not really part of "User".
I large projects I would probably put this function in a file with other utilities function, and call it every time i would like to use it.
Another option is to include it as part of the prototype:
User.prototype.toString() {
return this.id + ':' + this.name + '[' + this.questions + ']';
}
user1.toString(); // usr123:Max[4]
I would strongly suggest to using ES6 standard (at least). It's exist for several years, it looks much more intuitive and do some of the complex work for you.
In ES6 this code would look like this:
class User {
constructor(id, name, questions) {
this.id = id;
this.name = name;
this.questions = questions ? questions : 0;
}
toString() {
return this.id + ':' + this.name + '[' + this.questions + ']';
}
}
Look nicer isn't it? but it basically the same. This ES6 syntax is simply sugar coating for the older syntax you've included in your question.
I'm trying to improve my Javascript fundamentals so I can explore client-side frameworks (Knockout, Angular etc) and make progress in learning Node.js.
I've taken a simple problem which I use in teaching C# and I'm trying to solve it with Javascript.
The Problem
Create probability objects with an internal value for percentage of likelihood. For example, a 2/5 probability would be created with:
var firstOne = new Probability(40); // 2/5 is a 40% chance
That internal state should not be accessible through the instance variable. The purpose of the Probability function/object is to encapsulate the ability to compare one against another:
var secondOne = new Probability(30);
var areTheyEqual = firstOne.SameAs(secondOne); // returns false in this example
In C# this is relatively straight forward. The value of probability is stored in a member variable with private scope, and the SameAs function is public scope. Because each instance uses the same type, Probability, C#'s scoping allows the calling member to also 'see' the passed member's private state:
// C#
public class Probability
{
private int _value;
public Probability(int percent)
{
_value = percent;
}
public bool SameAs(Probability other)
{
return this._value == other._value; // works even though _value is private
}
}
I wondered if this kind of encapsulation could be achieved with Javascript. As a secondary question, perhaps what I'm trying to do is driven from a C# and OO perspective, where Javascript may offer alternative approaches to solve the problem that take advantage of Javascript's functional abilities. I'm open to both types of response.
You can work JavaScript closures to get close to what you're use to in other object oriented languages, e.g. something like:
function Probability() {
// private field
var _value = 0;
this.getValue = function() {
return _value;
};
this.setValue = function(newValue) {
_value = newValue;
};
this.sameAs = function(compare) {
return _value === compare.getValue();
};
}
var probability = new Probability();
probability.setValue(10);
var newProbability= new Probability();
newProbability.setValue(11);
console.log(probability.sameAs(newProbability)); // false
newProbability.setValue(10);
console.log(probability.sameAs(newProbability)); // true
You can find a lot of referencess when googling for Object-oriented JavaScript, I can recommend this site
I've read pages and pages about JavaScript prototypal inheritance, but I haven't found anything that addresses using constructors that involve validation. I've managed to get this constructor to work but I know it's not ideal, i.e. it's not taking advantage of prototypal inheritance:
function Card(value) {
if (!isNumber(value)) {
value = Math.floor(Math.random() * 14) + 2;
}
this.value = value;
}
var card1 = new Card();
var card2 = new Card();
var card3 = new Card();
This results in three Card objects with random values. However, the way I understand it is that each time I create a new Card object this way, it is copying the constructor code. I should instead use prototypal inheritance, but this doesn't work:
function Card(value) {
this.value = value;
}
Object.defineProperty( Card, "value", {
set: function (value) {
if (!isNumber(value)) {
value = Math.floor(Math.random() * 14) + 2;
}
this.value = value;
}
});
This doesn't work either:
Card.prototype.setValue = function (value) {
if (!isNumber(value)) {
value = Math.floor(Math.random() * 14) + 2;
}
this.value = value;
};
For one thing, I can no longer call new Card(). Instead, I have to call var card1 = new Card(); card1.setValue(); This seems very inefficient and ugly to me. But the real problem is it sets the value property of each Card object to the same value. Help!
Edit
Per Bergi's suggestion, I've modified the code as follows:
function Card(value) {
this.setValue(value);
}
Card.prototype.setValue = function (value) {
if (!isNumber(value)) {
value = Math.floor(Math.random() * 14) + 2;
}
this.value = value;
};
var card1 = new Card();
var card2 = new Card();
var card3 = new Card();
This results in three Card objects with random values, which is great, and I can call the setValue method later on. It doesn't seem to transfer when I try to extend the class though:
function SpecialCard(suit, value) {
Card.call(this, value);
this.suit = suit;
}
var specialCard1 = new SpecialCard("Club");
var specialCard2 = new SpecialCard("Diamond");
var specialCard3 = new SpecialCard("Spade");
I get the error this.setValue is not a function now.
Edit 2
This seems to work:
function SpecialCard(suit, value) {
Card.call(this, value);
this.suit = suit;
}
SpecialCard.prototype = Object.create(Card.prototype);
SpecialCard.prototype.constructor = SpecialCard;
Is this a good way to do it?
Final Edit!
Thanks to Bergi and Norguard, I finally landed on this implementation:
function Card(value) {
this.setValue = function (val) {
if (!isNumber(val)) {
val = Math.floor(Math.random() * 14) + 2;
}
this.value = val;
};
this.setValue(value);
}
function SpecialCard(suit, value) {
Card.call(this, value);
this.suit = suit;
}
Bergi helped me identify why I wasn't able to inherit the prototype chain, and Norguard explained why it's better not to muck with the prototype chain at all. I like this approach because the code is cleaner and easier to understand.
the way I understand it is that each time I create a new Card object this way, it is copying the constructor code
No, it is executing it. No problems, and your constructor works perfect - this is how it should look like.
Problems will only arise when you create values. Each invocation of a function creates its own set of values, e.g. private variables (you don't have any). They usually get garbage collected, unless you create another special value, a privileged method, which is an exposed function that holds a reference to the scope it lives in. And yes, every object has its own "copy" of such functions, which is why you should push everything that does not access private variables to the prototype.
Object.defineProperty( Card, "value", ...
Wait, no. Here you define a property on the constructor, the function Card. This is not what you want. You could call this code on instances, yes, but note that when evaluating this.value = value; it would recursively call itself.
Card.prototype.setValue = function(){ ... }
This looks good. You could need this method on Card objects when you are going to use the validation code later on, for example when changing the value of a Card instance (I don't think so, but I don't know?).
but then I can no longer call new Card()
Oh, surely you can. The method is inherited by all Card instances, and that includes the one on which the constructor is applied (this). You can easily call it from there, so declare your constructor like this:
function Card(val) {
this.setValue(val);
}
Card.prototype...
It doesn't seem to transfer when I try to extend the class though.
Yes, it does not. Calling the constructor function does not set up the prototype chain. With the new keyword the object with its inheritance is instantiated, then the constructor is applied. With your code, SpecialCards inherit from the SpecialCard.prototype object (which itself inherits from the default Object prototype). Now, we could either just set it to the same object as normal cards, or let it inherit from that one.
SpecialCard.prototype = Card.prototype;
So now every instance inherits from the same object. That means, SpecialCards will have no special methods (from the prototype) that normal Cards don't have... Also, the instanceof operator won't work correctly any more.
So, there is a better solution. Let the SpecialCards prototype object inherit from Card.prototype! This can be done by using Object.create (not supported by all browsers, you might need a workaround), which is designed to do exactly this job:
SpecialCard.prototype = Object.create(Card.prototype, {
constructor: {value:SpecialCard}
});
SpecialCard.prototype.specialMethod = ... // now possible
In terms of the constructor, each card IS getting its own, unique copy of any methods defined inside of the constructor:
this.doStuffToMyPrivateVars = function () { };
or
var doStuffAsAPrivateFunction = function () {};
The reason they get their own unique copies is because only unique copies of functions, instantiated at the same time as the object itself, are going to have access to the enclosed values.
By putting them in the prototype chain, you:
Limit them to one copy (unless manually-overridden per-instance, after creation)
Remove the method's ability to access ANY private variables
Make it really easy to frustrate friends and family by changing prototype methods/properties on EVERY instance, mid-program.
The reality of the matter is that unless you're planning on making a game that runs on old Blackberries or an ancient iPod Touch, you don't have to worry too much about the extra overhead of the enclosed functions.
Also, in day-to-day JS programming, the extra security from properly-encapsulated objects, plus the extra benefit of the module/revealing-module patterns and sandboxing with closures VASTLY OUTWEIGHS the cost of having redundant copies of methods attached to functions.
Also, if you're really, truly that concerned, you might do to look at Entity/System patterns, where entities are pretty much just data-objects (with their own unique get/set methods, if privacy is needed)... ...and each of those entities of a particular kind is registered to a system which is custom made for that entity/component-type.
IE: You'd have a Card-Entity to define each card in a deck.
Each card has a CardValueComponent, a CardWorldPositionComponent, a CardRenderableComponent, a CardClickableComponent, et cetera.
CardWorldPositionComponent = { x : 238, y : 600 };
Each of those components is then registered to a system:
CardWorldPositionSystem.register(this.c_worldPos);
Each system holds ALL of the methods which would normally be run on the values stored in the component.
The systems (and not the components) will chat back and forth, as needed to send data back and forth, between components shared by the same entity (ie: the Ace of Spade's position/value/image might be queried from different systems so that everybody's kept up to date).
Then instead of updating each object -- traditionally it would be something like:
Game.Update = function (timestamp) { forEach(cards, function (card) { card.update(timestamp); }); };
Game.Draw = function (timestamp, renderer) { forEach(cards, function (card) { card.draw(renderer); }); };
Now it's more like:
CardValuesUpdate();
CardImagesUpdate();
CardPositionsUpdate();
RenderCardsToScreen();
Where inside of the traditional Update, each item takes care of its own Input-handling/Movement/Model-Updating/Spritesheet-Animation/AI/et cetera, you're updating each subsystem one after another, and each subsystem is going through each entity which has a registered component in that subsystem, one after another.
So there's a smaller memory-footprint on the number of unique functions.
But it's a very different universe in terms of thinking about how to do it.
I am learning more advanced OO tactics for javascript coming from a C# background and am wondering about how to or if its even a good idea to implement prototype based validation. For instance when an object or function requires one of its parameters to satisfy a certain interface, you could check its interface like so,
var Interface = function Interface(i) {
var satisfied = function (t, i) {
for (var key in i) {
if (typeof t !== 'object') {
return false;
}
if (!(key in t && typeof t[key] == i[key])) {
return false;
}
}
return true;
}
this.satisfiedBy = function (t) { return satisfied(t, i); }
}
// the interface
var interfacePoint2D = new Interface({
x: 'number',
y: 'number'
});
// see if it satisfies
var satisfied = interfacePoint2D.satisfiedBy(someObject);
I came up with this strategy to validate an object by its interface only, ignoring the internal implementation of the object.
Alternatively say you are using prototype-based inheritance, should you or should not validate parameters based on their prototype functions? I understand that you'd use a prototype to implement default functionality whereas an interface doesn't specify any default functionality. Sometimes the object you are passing into a function might need certain default functionality in order for that function to work. Is it better to only validate against an interface, or should you ever validate against a prototype, and if so, whats the best way to do it?
EDIT -- I am providing some more context as to why I am asking this,
Say for instance in online game design (games written mostly in javascript). There are 2 main reasons I am interested in validation within this context,
1) Providing a strong public API for modding the game if desired
2) Preventing (or atleast discouraging greatly) potential cheaters
Which requires a balance between customizability and abuse. Specifically one situation would be in designing physics engine where objects in the game react to gravity. In a realistic system, users shouldn't be able to add objects to the system that do not react to gravity. The system has a function that expresses the global effect of gravity at any given point:
function getGravityAt(x, y) {
// return acceleration due to gravity at this point
}
And objects which react have a method that uses this to update their acceleration:
function update() {
this.acceleration = getGravity(this.position);
}
The minimum thing to do might be to ensure that any object added to the system has an 'update' method, but you still aren't ensuring that the update() method really is intended to react to gravity. If only objects that inherit from a prototypical update() method are allowed, then you know at least to some degree everything in the system reacts realistically.
This is a pretty subjective question. I'll pass on the question of whether it's a good idea to do interface-based validation in Javascript at all (there may well be good use-cases for it, but it's not a standard approach in the language). But I will say that it's probably not a good idea to validate objects based on their prototypes.
If you're validating by interface at all, you're probably working with objects created by other programmers. There are lots of ways to create objects - some rely on prototypes, some do not, and while they each have their proponents, they're all valid and likely approaches. For example:
var Point = function(x,y) {
return {
x: function() { return x },
y: function() { return y }
};
};
var p = new Point(1,1);
The object p conforms to an interface similar to yours above, except that x and y are functions. But there's no way to validate that p satisfies this interface by inspecting its constructor (which is Object()) or Point.prototype. All you can do is test that p has attributes called x and y and that they are of type "function" - what you're doing above.
You could potentially insist that p has a specific ancestor in its prototype chain, e.g. AbstractPoint, which would include the x and y functions - you can use instanceof to check this. But you can't be sure that x and y haven't been redefined in p:
var AbstractPoint = function() {};
AbstractPoint.prototype.x = function() {};
AbstractPoint.prototype.y = function() {};
var Point = function(x,y) {
var p = new AbstractPoint(x,y);
p.x = "foo";
return p;
}
var p = new Point(1,1);
p instanceof AbstractPoint; // true
p.x; // "foo"
And perhaps more importantly, this makes it harder to drop in custom objects that also satisfy the interface but don't inherit from your classes.
So I think what you're currently doing is probably the best you can hope for. In my experience, Javascript programmers are much more likely to use on-the-fly duck-typing than to try to mimic the capabilities of statically typed languages:
function doSomethingWithUntrustedPoint(point) {
if (!(point.x && point.y)) return false; // evasive action!
// etc.
}
I'll reiterate, type checking is not idiomatic javascript.
If you still want type checking, Google's closure compiler is the implementation I recommend. Type checking is done statically :) It has conventions for interfaces as well as (proto)type checking.
I understand how to instantiate objects and call them, but I just cannot find a reason to use them in my script. I could do
var obj = {
hi: function() {
return "Hello";
}
};
but why can't I just do it the same way like:
function hi() {
return "Hello";
}
I've never understood the reasons why I should use prototyping either. Most of the things I do in JavaScript I can do well without objects. But I want to use objects. What are objects for and what are the reasons why I should use them?
Objects are useful for example for making a single unit out of values that belong together. Example:
function Person(firstName, lastName, gender, age) {
this.firstName = firstName;
this.lastName = lastName;
this.gender = gender;
this.age = age;
}
Person.prototype = {
getFullName: function() { return this.firstName + ' ' + this.lastName; },
isMale: function() { return this.gender == 'Male'; },
isFemale: function() { return this.gender == 'Female'; }
};
var amanda = new Person('Amanda', 'Smith', "Female", 42);
var john = new Person('John', 'Doe', 'Male', 72);
alert(amanda.getFullName());
alert(john.isMale());
Compared to the less structured:
function getFullName(firstName, lastName) {
return firstName + ' ' + lastName;
}
function isMale(gender) {
return gender == 'Male';
}
function isFemale(gender) {
return gender == 'Female';
}
var amandaFirstName = 'Amanda';
var amandaLastName = 'Smith';
var amandaGender = 'Female';
var amandaAge = 42;
var johnFirstName = 'John';
var johnLastName = 'Doe';
var johnGender = 'Male';
var johnAge = 72;
alert(getFullName(amandaFirstName, amandaLastName));
alert(isMale(johnGender));
Objects are useful because
They are stateful.
They can store relations between strings and data.
It can be easier to decompose a problem by breaking it up into objects that collect related operations and state.
If you don't need non-global state, have no need of lookup tables, and your problem is small or more easily decomposed functionally then don't use objects.
Without what you are referring to as objects, you are going to have loose functions all over the place. This very often will result in code that is very difficult to maintain. At a bare minimum objects give you the ability to lump functions together in order to simulate namespaces-- and that's at a bare minimum.
In your simple example, it makes indeed no sense to write a semi "class" / object to hold that method. But when your code grows, you're getting more and more functions and methods, you don't really want to have them all in one big (global) namespace. That is just so impossible to maintenain, no one will understand that code including you at some later point.
That is the first good reason to wrap methods together in an object/"class". Another good reason is re-usabilty. If you're writting objects which are able to inherit their methods, you can re-create another object and abstract it from there on. Most simple concept, but you want to use it if you're describing "things" in your application as module/object.
It tries to simulate the OOP paradigm that's all. There are various ways of doing this. But ask yourself, doe 'hi' belong in 'obj' or can it be a standalone function? Its all about how closely related is the function to the object. Does the function needs to access the objects private variables and such?
This is less of a "objects in Javascript" and more of an objects in general" question.
I'd say the most relevant Javascript The only thing Javascript specific about objects is their neat use when namespacing. For example, most Javascript libraries pack all their stuff in a single object to avoid namespace collision:
dojo.create( ... )
dojo.connect( ... )
As for the other questions of why OOP, there are 2 basic things I think OOP excels at (generic, dumb, examples follow):
Dynamic dispatching - get rid of "ifs" and put responsabilitty where it belongs
When you look at a code that has tons of "switchs":
function doStuff(animal){
if animal is a tiger:
print_tiger_roar();
else if animal is a cow
print_cow_moo();
if animal is a tiger:
print_tiger_wants_meat();
else if animal is a cow
print cow_wants_grass();
It might be a good idea to bundle each different kind of behaviour in a different kind of object and use dynamic dispatching instead:
function doStuff(animal):
animal.print_speak();
animal.print_food_type();
Now, if you come up with another kind of animal in the future, you don't need to go looking around your code to add it - all you need to do is create a new class with the appropriate print_speack and print_food_type methods and the rest of the code won't notice a thing.
Inheritance + reusing methods
In a normal OO language each object stores (and spends memory) for its instance variables, while all methods + static variables are stored in a single place by the class. Javascript doesn't have classes, but it has prototypes and they serve the same basic function in the end.
Some generic thoughts concerning "Why" part:
Objects exist to communicate. It is a common vocabulary for everyone involved in a project. People are used to operate with things (objects) and their operations (messages or methods), rather than just with disconnected actions (functions).