This may be a non-problem, but I have a feeling learning about proper practices will help me learn proper javascript techniques! I'm just starting with using objects and attaching functions to them. Here is the current setup I am using for a little combat simulator:
var standardAttack = function(attacker,target){
if(!target.alive) return false;
var damage = r(attacker.damage)+1-target.def;
if(damage>0) {
target.hp -= damage;
sendMessage(attacker.name+" hits "+target.name+" for "+damage.toString());
if(target.hp<1){
sendMessage(target.name+[" is torn asunder!"," has it's head ripped off!"," is trampled into the dirt!"," is sliced in half!"," is smashed to pieces!"," falls to the ground, gurgling!"," flails and dies on the ground!"].sample()+" by "+attacker.name);
target.alive = false;
}
} else {
sendMessage(attacker.name+" hits "+target.name+" but no damage is dealt");
}
}
While the Creature object looks like this:
class Creature {
constructor() {
this.name = getName();
this.alive = true;
this.hp = 6;
this.def = 0;
this.damage = 6;
this.attack = standardAttack;
}
}
There are various different types of attacks in a similar format to standardAttack, and when needed, creature.attack is changed.
From this, attacks are started with:
creature1.attack(creature1,creature2);
or something along those lines. Looking at this, I feel like there is a more efficient way to access creature1.name and creature1.damage than passing itself into it's own function, a needless duplication. In addition, I don't think I am wrong in saying that it just looks bad! I feel that a more suitable format would be:
creature1.attack(creature2);
But currently, the standardAttack function is unable to find the damage or name values of the creature1 object. My question is this - is there any way to access the details of creature1 without passing the whole object into it's own function?
Please let me know if there are any changes I need to make to the question as well.
You have a few options. For a SO post on "this": How does the "this" keyword work?
Option 1, minimal code change:
You can bind your attack function to the current class so that your attack function has access to the "this" context. e.g.:
class Creature {
constructor() {
this.attack = standardAttack.bind(this)
}
}
In your standardAttack definition:
function standardAttack(target) {
console.log(this.attack)
}
Alternatively, using the same bind approach, whenever you call creature.attack you can make sure it's called with the correct context, e.g.: creature.attack.call(creature, target).
Option 2, better OOP pattern:
Define a method of the class "attack" so that "attack" semantically belongs to the Creature rather than some generic function. In JavaScript this is nothing more than semantics since you'll still need to make sure the method is called with the correct context -- or bind the method to the right context via the approach mentioned above.
class Creature {
attack(target) {
console.log(this.attack)
}
}
If you're using babel with the right rule enabled (I think class fields? / property initializers) you can do this shorthand which will automatically bind the method to the class instance. Word of caution, it doesn't add it to the prototype chain.
class Creature {
attack = target => {
console.log(target)
}
}
If "attack" is shared by multiple entities, you can define the method in some base class and inherit it:
class AggressiveEntity {
attack() {}
}
class Creature extends AggressiveEntity {}
Related
I'm just beginning to learn the use cases for the ES6 WeakMap feature. I've read a lot about it, but I haven't been able to find an answer for this particular question.
I'm implementing a Node.js Minesweeper game for the terminal - just for fun and practice. I've created a class called MineBoard that will store all the necessary data and methods for the game to operate. I want some members, such as _uncoveredCount (number of squares uncovered) and _winningCount (number of squares uncovered needed to win) to remain unaccessible to the user. Although this game isn't going into production, I'd still like it to be uncheatable ;) - and the naming convention of the _ prefix to signal private members is not enough.
To do this - I've implemented a WeakMap to store the two above examples in, and other private members.
METHOD 1:
let _mineBoardPrivateData = new WeakMap();
class MineBoard {
constructor(size, difficulty) {
this.size = size || 10;
this.difficulty = difficulty || 1;
_mineBoardPrivateData.set(this, {});
_mineBoardPrivateData.get(this).winningCount = someMethodForDeterminingCount();
_mineBoardPrivateData.get(this).isGameOver = false;
_mineBoardPrivateData.get(this).uncoveredCount = 0;
//more code
}
generateNewBoard() {
//code
}
uncoverSquare() {
//more code
_mineBoardPrivateData.get(this).uncoveredCount++;
}
//more code
}
It is much easier for me to do it this way above - and also much easier on the eyes. However, most of the examples of WeakMap implementations I've seen follow the style below.
METHOD 2:
let _winningCount = new WeakMap();
let _isGameOver = new WeakMap();
let _uncoveredCount = new WeakMap();
//more instantiations of WeakMap here
class MineBoard {
constructor(size, difficulty) {
this.size = size || 10;
this.difficulty = difficulty || 1;
_winningCount.set(this, someMethodForDeterminingWinningCount() );
_isGameOver.set(this, false);
_uncoveredCount.set(this, 0);
//more private data assignment here
}
generateNewBoard() {
//code
}
uncoverSquare() {
//more code
_uncoveredCount.set(this, _uncoveredCount.get(this) + 1);
}
//more code
}
So my question is - are there any drawbacks to using Method 1 that I am not seeing? This makes for the simpler solution and IMO easier to read and follow code.
Thank you!
You can (and should) use the first method. There are no drawback to using the first method and it probably is more efficient anyways since you're only creating a single object per MineBoard instance. It also means that adding/removing private properties is much easier. Additionally, from inside your MineBoard instance you would be able to easily iterate over all the private properties just using Object.keys(_mineBoardPrivateData.get(this)) (try doing that with the second method).
In order to emulate classical, Java-like classes in JavaScript I have a function called
"createClass":
It has 3 arguments:
* Name and path of the constructor function, that should be created.
* Path of the superclass.
* JavaScript object with methods of the class.
For example:
myApp.createClass("myapp.core.JString", "myapp.core.BaseString", {
abc: function () {
...
First I create a constructor function
Cf = function () {
...
If there is a super class ("Base" is the constructor function of the super class):
protoObj = new Base();
protoObj.constructor = Cf;
Now, method by method of the new class, I put them on to the protoObj:
("protos" is the object with the "class" methods)
for (name in protos) {
????????????????????
protoObj[name] = protos[name]
But before putting the methods to the protoObj, I want to create convenience methods for
calling superclass methods from overwritten methods:
init: function () {
this.jstring_super_init();
...
So, where the question marks are, I want to place the following code:
(classnameLast in this case is "jstring" => last part of class path => lowercase)
if ((typeof protos[name] === "function") &&
(protoObj[name]) &&
(typeof protoObj[name] === "function")) {
supername = classnameLast + "_super_" + name;
protoObj[supername] = XXXXXXXXXXXXX
In the place, where the multiple X are, I tried several things, but nothing worked. It should call the method of the overwritten superclass.
Many thanks in advance for your help
Maybe you could do something like this:
for (name in protos) {
var super_function = ...; //wherever it comes from
protoObj[name] = protos[name];
protos[name]._super = super_function;
}
Then, from within the function, you should have access to the super function via this._super. You can even do this._super.call(this, ...) to ensure that the super function is called in the context of this.
Hopefully I'm understanding you correctly. Also, if I can make a suggestion, there might be an easier way to handle classical objects and inheritance. If you don't want to use Typescript, at least try the inheritance model that they use (which is quite common).
http://pastebin.com/Z2kaXqEv
EDIT: What helped me was using the Typescript playground (http://www.typescriptlang.org/Playground/). Play around with it and the class features it has, and see how it compiles to Javascript. That'll help you better understand exactly how you can accomplish classical inheritance in Javascript.
I tried this for XXXXXXXXXXXX, and it worked:
(function(name1, Base1){
return function() {
Base1.prototype[name1].apply(this, arguments);
};
})(name, Base);
I debugged a "jstring_super_init" function call in Firefox 19, Firebug 1.11.2.
Firebug behaved very strangely, jumping to wrong places of the code!!
Then, I inserted "console.log(this.cid);" after the superinit-call.
The cid, which is placed on to "this" in the init method of the super class, was there!!
When debugging with Google Chrome Version 25, it jumps to the right function!
I have been looking into the possibility of reflection in JavaScript. I already have a simple reflector which can list the members of an object/function, like so:
window["Foo"] = {
"Bar": {
"Test": function () {
this.x = 32;
this._hello = "Hello World";
this._item = 123.345;
this.hello = function() {
alert("hello");
};
this.goodbye = function() {
alert("goodbye");
}
}
}
}
$(document).ready(function () {
var x = new Foo.Bar.Test();
Reflect(new Foo.Bar.Test());
});
function Reflect(obj) {
for (var item in obj) {
$("body").append(item + "(" + typeof obj[item] + ") = " + obj[item] + "<br />");
}
}
Results:
x(number) = 32
_hello(string) = Hello World
_item(number) = 123.345
hello(function) = function () { alert("hello"); }
goodbye(function) = function () { alert("goodbye"); }
The next part of my challenge is to build something which can reflect back (if possible) an objects name, and the path to the object.
using this example:...
var x = new Foo.Bar.Test();
How can I reflect back "Test", from x? For example:
ReflectName(x); //returns "Test";
Also how can I reflect back the path to x? For example:
ReflectPath(x) //returns Foo.Bar.Test
Is is possible to do these two things using JavaScript? I have researched this, and so far have not managed to come up with any viable solutions.
I do not want a solution that requires hard coding the name and path of the object/function, as this would defeat the point of using reflection.
There are no classes in JavaScript (although due to code style which for reasons unknown to me imitates Java you could think there are some). Foo.Bar.Test does not mean class Test registered in namespace Foo.Bar, but function which is assigned as attribute Test of some object which is assigned as attribute Bar of some object known as Foo.
You can't do reflection like "give me all variables to which number 7 is assigned", consequently you can't list all the objects which hold Test in one of their attributes.
This is actually good and opens new possibilities, but might be confusing in the beginning.
BTW Since there are no classes in JavaScript, I believe term reflection is not very fortunate. And new Foo() does not mean "create new instance of Foo", but "create a new object and execute function Foo in context of that object, and finally return it. Yeah, the new keyword is very confusing, if you want to do anything more advanced in JavaScript, never trust your Java/C# experience. JavaScript fakes Java (I suppose to not scare newcomers and allow them to do easy things quickly), but it's very different.
This is not possible in JavaScript. (To get a deeper understanding of JavaScript's type system, I recommend reading this.)
The best approximation you can do is querying over a static JSON structure.
Answer to your first question
function ReflectName(obj) { return obj.__proto__.constructor.name }
Second question is a bit more difficult and would require more setup with the definitions.
It is answered a bit better here: Javascript objects: get parent
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'm relatively new to Javascript. I was wondering if it supports components and objects like Python does. If it does, what would the syntax look like?
For instance, I know an object look like this:
function Foo(a, b) {
this.a = a;
this.b = b;
}
Now, is there a way to declare some components, pick one of those, and add it to the object? For instance, let's say I have a object Item. Could I declare some different components, such as Weapon, Magical, Legendary, etc. and them add them to the object? Using this approach I could end up with a Magical Weapon, or a Legendary Item, or even a Legendary Magical Weapon.
I thought about using parenting for this but for what I want to do, it seems like that would be rather limited. For instance, my heirarchy would look like Item/Weapon or Item/Legendary, so I couldn't have a Legendary Weapon.
So, are components possible in Javascript?
What you describe as a 'component' is more commonly called a class. What you describe as 'parenting' is more commonly called inheritance. You are spot on about the class hierarchy :)
Ok, so your base class in an Item. This item will have the basic attributes which all items in your game world must have. All objects in your game world will inherit from Item.
A Weapon is an Item. A MagicalItem is an Item. A LegendaryItem is an item. These three classes are all subclasses of Item.
Things get a little bit more tricky when you want a LegendaryMagicalWeaponItem. This is the essence of your question: Is multiple inheritance possible in JavaScript?
To paraphrase the Boondock Saints, you do not want multiple inheritance unless you are absolutely, positively sure that you need it. Why? It quickly leads to complications. For example, what if two superclasses have a method or an attribute with the same name? What if they inherit from two different base classes, and one of those classes causes a name collision? You can see where this is going.
Fortunately, JavaScript, like Python, is a very flexible language. You are not forced to use multiple inheritance or even interfaces to generalise behaviour across heterogeneous objects.
Let's say MagicalItem has a mana property and LegendaryItem has a legacy() method. Let's say a weapon object has a damage. Let's say Item has important physical attributes and a bunch of physics methods; it is clearly the 'dominant' superclass. There is nothing stopping you from doing this:
// Base classes
function Item() {
// some default values...
}
Item.prototype.physics = function (t) {/* physics stuff */}
function Magical(mana) {
this.mana = mana;
}
function Weapon(damage) {
this.damage = damage;
}
function Legendary(legacy) {
this.legacy = function () {return legacy;};
}
// Actual world item class
function MyLegendaryMagicalSword(x,y) {
this.x = x;
this.y = y;
Weapon.call(this, MyLegendaryMagicalSword.DAMAGE);
Legendary.call(this, MyLegendaryMagicalSword.LORE);
Magical.call(this, MyLegendaryMagicalSword.START_MANA);
}
// actual prototypal inheritance
MyLegendaryMagicalSword.prototype = new Item();
// class attributes
MyLegendaryMagicalSword.DAMAGE = 1000;
MyLegendaryMagicalSword.START_MANA = 10;
MyLegendaryMagicalSword.LORE = "An old sword.";
// Sword instance
var sword = new MyLegendaryMagicalSword(0, 0);
sword.physics(0);
sword.mana;
sword.legacy();
// etc
// probe object for supported interface
if (sword.hasOwnProperty("damage")) {
// it's a weapon...
}
This is a down and dirty way to do what you describe.
> sword
{ x: 0,
y: 0,
damage: 1000,
legacy: [Function],
mana: 10 }
I have no idea what you mean by components. The term is too generalized. In Delphi, a component is a non-visible code module which introduces some special functionality to the application. A "timer" is one such example of a component (in Delphi).
Guessing from your description, you seem to want to add properties dynamically? Or is it about overloading?
In the latter case, you can't do this by design, as in, it lifts the limitations you mentioned.
Example (mixing):
function mixItems(weapon,legend){
return {
"damage":legend.damage+weapon.damage,
"name":legend.name+"' "+weapon.name
};
}
var weapon={ "damage":45, "name":"sword"};
var legend={ "name":"Goliath", "damage":34 };
var LegendaryWeapon = mixItems(weapon,legend);
console.log( LegendaryWeapon );
// output:- name: "Goliath's sword", damage: 79
Example (extending):
function clone(old){ // non-deep cloning function
var res={};
for(i in old)
res[i]=old[i];
return res;
}
var sword = {
"damage":50
"hit": function(){ // returns the percentage hit chance
return Math.round(Math.random()*100);
}
};
var bigsword=clone(sword);
bigsword.damage=60;
bigsword.hit=function(){ // returns the percentage hit chance
return Math.round(Math.random()*80)+20;
};
an object in javascript looks like this:
var Foo = {
a: null,
b: null,
init: function(a,b){
this.a = a;
this.b = b;
}
}
//call the init:
Foo.init(12,34);
almost the same as you have in the question.
And this object is extendable
you code example is a Function object which is intended to be used as a constructor function i.e. call it with the new keyword and it returns an instance of an object that has an a property and a b property (amongst other inherited properties).
Function objects inherit from Object like all other objects in JavaScript.
Usually, objects are created using object literal syntax, i.e. var x = { a: 'a', b: 'b' }; although they can also be created by using the new keyword with Object.
It looks like your question is referring to inheritance with JavaScript. Well, there are many ways to perform inheritance. One example is
function A() { }
function B() { }
B.prototype = new A;
Here both A and B are constructor functions. Functions have a prototype property which is an object and can contain members that can be shared by all object instances constructed by the function. We assign an instance of an object returned by the constructor function A to B's prototype, giving B all members available on an instance of A. This is just one way to perform inheritance in JavaScript.
The Mozilla Developer Center article on the Object Model is worth a read.