How can I use one function for different JS classes? - javascript

Assume I have two classes ClassA and ClassB:
function ClassA(){
this.x = 1;
this.y = 'a';
this.z = false;
}
-
function ClassB(){
this.x = 0;
this.y = 'b';
this.z = true;
}
And I want to use one function for these two as prototype:
var foo = function(){
if(this.z){
window.alert(this.y + this.x);
}
}
Is it safe to use it like
ClassA.prototype.foo = foo;
ClassB.prototype.foo = foo;
because I assign same function object for different classes.
OR is there any way to define interface (like JAVA) and use inheritance somehow?

Is it safe to use it like...
Yes
This is perfectly fine. Unlike python methods, javascript functions know nothing of the class they belong to.

Related

Using bind to utilize another Javascript class's method

I have an old-style class in Javascript that I want to utilize another old-style class's behavior without a full subclassing. Something like this:
function Foo(x) {
this.x = x;
}
Foo.prototype.add1 = function() {
return this.x + 1
}
function Bar(n) {
this.x = 2*n;
}
Bar.prototype.add1 = function() {
// steal behavior from Foo.add1
return Foo.prototype.add1.call(this);
}
This works fine in a browser console:
> b = new Bar(3)
Bar {x: 6}
> b.add1()
7
Is there a way to use bind instead? Something like
function Bar(n) {
this.x = 2*n;
}
Bar.prototype.add1 = Foo.prototype.add1.bind(xyz);
except that there's no "this" object to use for xyz before the object actually exists.
The following code works, but seems wrong....
function Bar(n) {
this.x = 2*n;
this.add1 = Foo.prototype.add1.bind(this);
}
Is there a way to use bind in this way when setting up an old-style class's prototype?
You didn't need to use bind, just assign Bar.prototype.add1 = Foo.prototype.add1. bind method is useful for instances not for classes.

How to handle several instance on the same Class in a plugin?

I have a JS plugin using es6 class syntax. I'm not sure on the way to handle several instances of the class versus once instance with a several element inside.
This plugin can have an array an unlimited number of image nodes as parameters.
This is the class syntax I have so far
(function(window) {
function handle(element, options) {
let handles = [];
if (element.length) {
for (var i = 0; i < element.length; i++) {
handles.push(new Plugin(element[i], options));
}
} else {
handles.push(new Plugin(element, options));
}
return handles;
}
class Plugin {
constructor(element, options) {
this.element = element;
this.init();
}
init() {
//get its translated value
this.methodA();
//apply its translation even if not visible for the first init
this.methodB();
}
methodA() {
this.element.classList.add('test');
}
}
return handle;
});
I would like to get rid of this handle function. What is the other way to have an instance of plugin for every element? and to be able to have the classPlugin at the top level without the need for this handle function.
I don't see any other way that having several instances of the class, because each instance get specified info for each image (height, offset, etc). Maybe I am missing something obvious here...
You can't actually instantiate an instance of a class without a loop. You may try eval. But it's not recommended. It's a bad practice.
Now let me explain why it is not possible.
JavaScript does not have classes and instances, it has only objects, which can delegate to other objects.
To create two objects based on a single object, but behind the scenes, there aren’t really two ‘instances’ of the Point object, there are just two objects that delegate to the original one. When you use new, JavaScript is actually just creating an object and setting its prototype to the object returned by the constructor function. Imagine if the example had been expanded to include a shared method like this:
function Point(x, y) {
this.x = x;
this.y = y;
}
Point.prototype.logCoords = function () {
console.log(this.x, this.y);
};
var a = new Point(1, 2);
console.log(a.x); // logs '1'
a.logCoords(); // logs '1 2'
Behind the scenes, what’s happening is something more like this:
var Point = function (x, y) {
this.x = x;
this.y = y;
};
Point.prototype.logCoords = function () {
console.log(this.x, this.y);
};
var a = {};
a.__proto__ = Point.prototype; // see note below about this
a.constructor = Point;
a.constructor(1, 2);
console.log(a.x); // logs '1'
a.logCoords(); // logs '1 2'

Is there a way to use a function parameter as a getter in a prototype?

Im trying to code pacman at the moment, and a came across a problem:
Since all the Ghosts use the same pathfinding and are generally pretty simular, I want to use a prototype for them. The only property in which they really differ, is the way, they choose their target position. I'd like to give a function to the prototype and use it as a getter. Is that possible?
function Ghost(color,x,y,getterFunction){
this.color = color;
this.x = x;
this.y = y;
this.direction = "up";
this.move = function(){
//Pathfind towards this.target
}
this.target = getterFunction; //or something like this...
}
Thanks for your help :^)
#Bergi is right. You don't want to use it as a getter. If you tried to add it to the prototype it would be overwritten by every new ghost you create, since the prototype is a shared object.
The prototype is for shared functionality. Instance functionality belongs in the instance, i.e. In your constructor function.
Your move function should be on the prototype. But target should be an instance method. You could set a default method for target on the prototype. Any instance method would be called before looking to the prototype.
Example
function Ghost(color, x, y, target){
// everything in here is instance specific
this.color = color;
this.x = x;
this.y = y;
this.direction = "up";
if (typeof target === 'function') {
this.target = target;
}
}
// this is the prototype
Ghost.prototype.move = function() {
//Pathfind towards this.target
this.target()
}
Ghost.prototype.target = function() {
// default target to use if no target provided at creation
}
So now, when you do this:
var redGhost = new Ghost('red', 0, 0, function() {
//do something unique
})
You'll have a ghost that's red and has a custom target function. But if you do this:
var yellowGhost = new Ghost('yellow', 0, 0)
You'll have a ghost that uses the default target function you added to the prototype.

how to do `var self = this` inside es6 class?

I am running the below code in nodejs
this.x = 'global x';
class Point {
constructor(x) {
this.x = x;
}
toString() {
return this.x;
}
}
var obj = new Point(1);
obj.toString();// 1 as expected
var a = obj.toString;// Here I can do something like var a = obj.toString.bind(obj); to get rid of the situation. But I am curious to know how can we write `var self = this`;
a();// TypeError: Cannot read property 'x' of undefined
a(); throws the error.
How can we do like var self = this; as we used to do in es5 to prevent such a situation?
How can we do like var self = this; as we used to do in ES5?
You can do it exactly like you did in ES5 - ES6 is completely backward-compatible after all:
class Point {
constructor(x) {
this.x = x;
var self = this;
this.toString = function() {
return self.x;
};
}
}
However, that's really not idiomatic ES6 (not talking about const instead of var). You'd rather use an arrow function that has a lexical-scoped this, so that you can avoid this self variable completely:
class Point {
constructor(x) {
this.x = x;
this.toString = () => {
return this.x;
};
}
}
(which could even be shortened to this.toString = () => this.x;)
If you don't want to create all your class methods inside the constructor as Bergi suggests (which seems ugly to me) then you can enable ES7 features and define your method using arrow syntax:
class Point
{
constructor(x)
{
this.x = x;
}
toString = () =>
{
return this.x;
}
}
This has the same effect as saying:
constructor(x)
{
this.toString = this.toString.bind(this);
}
But it still doesn't allow you to access the dynamic this and the lexical this (self) in the same function. So this is not a complete answer.
I hope someone can edit this answer to show how we can access both types of this in a class method without defining every method in the class constructor.

Javascript object design

In Javascript I would like to create two classes: A node, and a node list. A node contains some trivial properties; a node list contains pointers to a node, and multiple node lists can contain the same nodes. Would the following be correct (simplistic) design?
function Node(name, x, y) {
this.name = name;
this.x = x;
this.y = y;
}
Node.prototype.setX = function(x) {
this.x = x;
};
Node.prototype.setY = function(y) {
this.y = y;
};
function Nodelist() {
this.list = [];
}
Nodelist.prototype.addNode = function(node) {
this.list.push(node);
};
var a = new Node('stack', 0, 0);
var b = new Node('overflow', 0, 0);
var l = new Nodelist();
var m = new Nodelist();
l.addNode(a);
l.addNode(b);
m.addNode(a);
Do I even need these .prototype.set functions? Playing around in the console it seems I can just do a node.x = 10. Thanks.
not sure what your intention is (setters with no getters?), but you might be interested in private variables. to achieve the effect of private variables, you would start with the following:
function Guy(name) {
var _name = name;
this.getName = function(){ return _name; }
this.setName = function(n) { _name = n; }
}
var g = new Guy("Bob");
alert(g.getName()); // works
alert(g._name); // doesn't work
(In fact in this simple example, you don't even need the variable _name; getName and setName can close over the function argument name);
No, you don't need those functions, unless you need some sort of callback-based system where a function should be executed when the value changes. You can access and assign to the properties directly, as you discovered.
Javascript objects properties are accessible from anywhere ie. there are no real private variables so defining getter setter methods in this way is kind of pointless. If you want private variables or similar behaviour, read this http://javascript.crockford.com/private.html
It depends on if you're trying to enforce the encapsulation of x and y in an OOP manner. One way that javascript differs from - for example - Java is that it doesn't inherently enforce private variables. Usually, the common way to declare that some variable/method SHOULD be private is to name it with an underscore. So if you're actually trying to enforce OOP concepts here, then declare x and y like this:
function Node(name, x, y) {
this.name = name;
this._x = x;
this._y = y;
}
And then keep your setters. If you aren't trying to enforce some kind of encapsulation of x and y to your Node, then go ahead and don't provide them and just use the node.x/node.y when you need to get/set x or y.
Just keep in mind that this is simply a naming convention and when this script is running, _x is just as visible as x. It will be up to you and any programmers you work with to enforce this.

Categories

Resources