How can I call another object's function in JavaScript? - javascript

In the code below, I want to use One's reference to Two to call its saySomething() function. When I try it this way, I get this error:
Uncaught ReferenceError: other is not defined.
How can I change my code to make it work?
class One
{
constructor (other)
{
this.other = other;
}
doSomething ()
{
this.other.saySomething();
}
}
class Two
{
saySometing ()
{
console.log("hi");
}
}
const t = new Two();
const o = new One(t);
o.doSomething();

You have a typo in your saySometing() declaration. It should be saySomething().

Not sure what would be the best pattern with JavaScript classes but prototypes (which is what classes use under the hood anyway) will allow you to do so:
var One = function() {
Two.prototype.saySomething();
}
One.prototype = {
}
var Two = function() {
}
Two.prototype = {
saySometing: function() {
console.log("hi");
}
}
const t = new One();

Related

Javascript - dependency injection?

I'm looking to create a new object then call various methods against it. The idea is simply to group the code and make it tidier rather than have separate methods, all with the same required parameter.
In C# this would be easy - just a case of declaring a new instance of a class and passing the object into the constructor, but I'm unsure about how to go about this in javascript - if it's possible at all. Here's a visual (non working):
let wrapperMethods = function ($wrapper) {
let isOkay = function () {
return $wrapper.is("is something");
};
// more functions
};
// Initiate and call
let $wrapper2 = wrapperMethods($wrapper);
if ($wrapper2.isOkay()) {
alert("is okay");
}
As you can see, there's a bit of jquery ($wrapper) in there too.
Of course, this may not be the correct approach at all. Any advice would be appreciated.
The following code copies the input instance and inject the function with no modification in the original instance.
let wrapperMethods = function ($wrapper) {
let isOkay = function () {
return $wrapper.is("is something");
// note that you can use `this` like so: this.is("is something")
};
Object.assign(
Object.create(
Object.getPrototypeOf($wrapper).constructor
),
$wrapper,
{isOkay /*, other function names */}
)
// more functions
return
};
// Initiate and call
let $wrapper2 = wrapperMethods($wrapper);
if ($wrapper2.isOkay()) {
alert("is okay");
}
If you don't need to preserve the original instance you can inject the method in the class just like the following
let wrapperMethods = function ($wrapper) {
$wrapper.isOkay = function () {
return $wrapper.is("is something");
// same as above, you can use this.is("is something")
}
// more functions
return
};
If you need to inject properties or functions in the constructor of an object, then you can do the following
class MyReciver {
constructor(method){
this.method = method
}
}
$wrapper = new MyReciver(function() {alert('ok')})
If you don't need the this reference you can also use arrow functions
You're so close, just return the { isOkay } as an object.
let wrapperMethods = function ($wrapper) {
let isOkay = function () {
return $wrapper.is("is something");
};
let isNotOkay = function () {
return !$wrapper.is("is something");
};
return { isOkay, isNotOkay }
};
// Initiate and call
let $wrapper2 = wrapperMethods($wrapper);
if ($wrapper2.isOkay()) {
alert("is okay");
}

Execute "static" method of a parent of a constructor accessed from a constructor array in Javascript

Phew, even the question was hard to write. Here's the problem: I have a "game", more like a random simulator, which needs to choose a random action from an array of actions, like this one:
actions = [ Action1, Action2, Action3 ]
I have actions written as classes inheriting from the Action parent class:
function Action() {
this.targets = [];
this.used = [];
this.execute = function(player) {
doStuff();
return whatever;
};
}
//btw the below I've seen in a JS OOP tutorial but it doesn't work and I have to implement init() in every child action
Action.init = function(player) {
var a = new this.constructor();
return a.execute(player);
};
Action.checkRequirements = function() {
return true;
};
Action1.prototype = new Action();
Action1.prototype.constructor = Action1;
function Action1 {
this.execute = function(player) {
doStuff();
return whatever;
}
}
Action1.init = function(player) {
var a = new Action1();
return a.execute(player);
}
So what I'm doing to execute an action and get its results is var foo = actions.getRandomVal().init(); (getRandomVal is a simple custom script that returns a random value from the array) It works well, creates the object instance which properly inherits all properties and methods, executes the exec() method and returns its results... but now I have a checkRequirements() method which I want to implement in like 10% of the 100+ actions I wish to do, and I want it to simply be inherited from the Action class so that when it is not implemented in the child class it simply returns true and I don't have an idea how. If I do var a = actions.getRandomVal(); and then a.checkRequirements(); it throws an exception that a.checkRequirements is not a function.
PS: this is a relatively small non-profit project for a (large) group of friends, I don't need it to work in every browser, it needs to work in Chrome and I can just tell them to use Chrome for it.
Since you only need to work with Chrome, I'd suggest to use ES6 class syntax which does all the inheritance properly, without the chance to mess up. This includes your Action1 constructor to inherit properties ("static class members") from the Action constructor as you'd expect.
class Action {
constructor() {
this.targets = [];
this.used = [];
}
execute(player) {
doStuff();
return whatever;
}
static init(player) {
var a = new this(); // no .constructor
return a.execute(player);
}
static checkRequirements() {
return true;
}
}
class Action1 {
execute(player) {
doOtherStuff();
return whateverelse;
}
}
It looks to me like you're calling checkRequirements() on an instance:
a.checkRequirements();
But it's implemented statically:
Action.checkRequirements = function() {
return true;
};
You probably want to bind this function to the prototype, so change the code above to this:
Action.prototype.checkRequirements = function() {
return true;
};
Then when you want to override this in a derived type, like Action1, you can do this:
Action1.prototype.checkRequirements = function () {
return (whatever);
}
As per comments, my guess is you want something like this...
// base Action type providing basic implementation
// Wrapped in an IIFE to prevent global scope pollution
// All functions are prototype bound to allow prototypical inheritance.
var Action = (function () {
function Action() {
this.targets = [];
this.used = [];
};
Action.prototype.doStuff = function () {
return;
}
Action.prototype.execute = function (player) {
this.doStuff();
return "whatever";
}
Action.prototype.checkRequirements = function () {
return "foo";
}
return Action;
})();
var Action1 = (function () {
Action1.prototype = new Action();
Action1.prototype.constructor = Action1;
function Action1() {
}
Action1.prototype.checkRequirements = function () {
// Super call
return Action.prototype.checkRequirements.call(this);
}
return Action1;
})();
var Action2 = (function () {
Action2.prototype = new Action();
Action2.prototype.constructor = Action2;
function Action2() {
}
Action2.prototype.checkRequirements = function () {
return "bar";
}
return Action2;
})();
// Set up array.
var array = [Action1, Action2];
// Create instances (this is where you would pick at random)
var a1 = new array[0]();
var a2 = new array[1]();
// var aofn = new array[rnd]();
// Tests
alert(a1.checkRequirements()); // Should "foo" because it called super (Action).
alert(a2.checkRequirements()); // Should "bar" because it's overridden.
Check it out on TypeScript Playground

Is it more efficient to use a common empty function instead of creating a new one in each class instance?

Let's say I have a class that is designed to have some callbacks added to it later on.
function myclass() {
this.onSomething = function () {};
this.onOtherThing = function () {};
this.something = function () {
// stuff
this.onSomething();
};
this.otherThing = function () {
// other stuff
this.onOtherThing();
};
}
I can't have this.onSomething and this.onOtherThing being undefined or null because when they are called in something() and otherThing(), an error will be thrown, stating that their type is not a function.
Since those empty functions are needed, but they use memory, is the class going to be more memory efficient if I did this?
function myclass() {
this.onSomething = empty;
this.onOtherThing = empty;
...
}
function empty() {
}
This way each class instance's properties point to the same empty function, instead of creating new functions every time. I assume defining an empty method doesn't take a lot of memory, but still... is this technically better?
You are right about the fact that a new function is created for every instance of your class. In order to have this shared across all instances you can declare it on the prototype of the class:
var MyClass = function() {
this.something = function () {
// stuff
this.onSomething();
};
this.otherThing = function () {
// other stuff
this.onOtherThing();
};
}
MyClass.prototype.onSomething = function() {};
MyClass.prototype.onOtherThing = function() {};
This way, the methods will be shared by all instances.
why don't you try to return true or return false instead of returning empty functions.
or best you can use :
function myclass() {
this.onSomething = false;
this.onOtherThing = false;
...
}
as per your comment you can try :
function myclass() {
this.onSomething = empty();
this.onOtherThing = empty();
... }
function empty() {
//return something
return true;
}

UnCaught TypeError - Nested objects in Javascript? Why is this not allowed? Object literal notation works

Playing around with some JS tests and I'm trying to instantiate some nested objects in my v namespace. As you'll see below, ClassA and ClassB work as expected. When I try and nest some objects under another property (myCustomProperty) I start running into issues! Could someone explain?
Below is the original code:
var v = (v) ? v : {};
v.someClassA = (function() {
this.hello = function() {
console.log("Class A Hello!");
}
});
v.someClassB = (function() {
this.hello = function() {
console.log("Class B Hello!");
}
});
// this all works!
var myClassA = new v.someClassA();
var myClassB = new v.someClassB();
v.myCustomProperty = (function() {
function someClassC() {
this.hello = function() {
console.log('C');
}
}
function someClassD() {
this.hello = function() {
console.log('D');
}
}
return {
someClassC: someClassC,
someClassD: someClassD
}
});
// Uncaught TypeError: v.myCustomProperty.someClassC is not a function! Why?
var myClassC = new v.myCustomProperty.someClassC();
var myClassD = new v.myCustomProperty.someClassD();
myClassA.hello();
myClassB.hello();
myClassC.hello();
myClassD.hello();
If I change my declaration of v.myCustomProperty to use object literal notation, then it ALL WORKS! :
v.myCustomProperty = {
someClassC: function() {
this.hello = function() {
console.log('C');
}
},
someClassD: function() {
this.hello = function() {
console.log('D');
}
}
}
I guess my question really is how would I make this work using the notation in my original snippet? Possible? Horrible practice to do it that way?
Thanks!
v.myCustomProperty is a function that returns an object. You have to call the function first:
new (v.myCustomProperty().someClassC)();
// ^^
Otherwise, v.myCustomProperty.someClassC() tries to access the property someClassC of the function, and we all know (hopefully) that functions don't have such a property.
Or maybe you intended to execute the function immediately and assign the object to myCustomProperty?
v.myCustomProperty = (function() {
// ...
}()); // <- call function

Calling method using JavaScript prototype

Is it possible to call the base method from a prototype method in JavaScript if it's been overridden?
MyClass = function(name){
this.name = name;
this.do = function() {
//do somthing
}
};
MyClass.prototype.do = function() {
if (this.name === 'something') {
//do something new
} else {
//CALL BASE METHOD
}
};
I did not understand what exactly you're trying to do, but normally implementing object-specific behaviour is done along these lines:
function MyClass(name) {
this.name = name;
}
MyClass.prototype.doStuff = function() {
// generic behaviour
}
var myObj = new MyClass('foo');
var myObjSpecial = new MyClass('bar');
myObjSpecial.doStuff = function() {
// do specialised stuff
// how to call the generic implementation:
MyClass.prototype.doStuff.call(this /*, args...*/);
}
Well one way to do it would be saving the base method and then calling it from the overriden method, like so
MyClass.prototype._do_base = MyClass.prototype.do;
MyClass.prototype.do = function(){
if (this.name === 'something'){
//do something new
}else{
return this._do_base();
}
};
I'm afraid your example does not work the way you think. This part:
this.do = function(){ /*do something*/ };
overwrites the definition of
MyClass.prototype.do = function(){ /*do something else*/ };
Since the newly created object already has a "do" property, it does not look up the prototypal chain.
The classical form of inheritance in Javascript is awkard, and hard to grasp. I would suggest using Douglas Crockfords simple inheritance pattern instead. Like this:
function my_class(name) {
return {
name: name,
do: function () { /* do something */ }
};
}
function my_child(name) {
var me = my_class(name);
var base_do = me.do;
me.do = function () {
if (this.name === 'something'){
//do something new
} else {
base_do.call(me);
}
}
return me;
}
var o = my_child("something");
o.do(); // does something new
var u = my_child("something else");
u.do(); // uses base function
In my opinion a much clearer way of handling objects, constructors and inheritance in javascript. You can read more in Crockfords Javascript: The good parts.
I know this post is from 4 years ago, but because of my C# background I was looking for a way to call the base class without having to specify the class name but rather obtain it by a property on the subclass. So my only change to Christoph's answer would be
From this:
MyClass.prototype.doStuff.call(this /*, args...*/);
To this:
this.constructor.prototype.doStuff.call(this /*, args...*/);
if you define a function like this (using OOP)
function Person(){};
Person.prototype.say = function(message){
console.log(message);
}
there is two ways to call a prototype function: 1) make an instance and call the object function:
var person = new Person();
person.say('hello!');
and the other way is... 2) is calling the function directly from the prototype:
Person.prototype.say('hello there!');
This solution uses Object.getPrototypeOf
TestA is super that has getName
TestB is a child that overrides getName but, also has
getBothNames that calls the super version of getName as well as the child version
function TestA() {
this.count = 1;
}
TestA.prototype.constructor = TestA;
TestA.prototype.getName = function ta_gn() {
this.count = 2;
return ' TestA.prototype.getName is called **';
};
function TestB() {
this.idx = 30;
this.count = 10;
}
TestB.prototype = new TestA();
TestB.prototype.constructor = TestB;
TestB.prototype.getName = function tb_gn() {
return ' TestB.prototype.getName is called ** ';
};
TestB.prototype.getBothNames = function tb_gbn() {
return Object.getPrototypeOf(TestB.prototype).getName.call(this) + this.getName() + ' this object is : ' + JSON.stringify(this);
};
var tb = new TestB();
console.log(tb.getBothNames());
function NewClass() {
var self = this;
BaseClass.call(self); // Set base class
var baseModify = self.modify; // Get base function
self.modify = function () {
// Override code here
baseModify();
};
}
An alternative :
// shape
var shape = function(type){
this.type = type;
}
shape.prototype.display = function(){
console.log(this.type);
}
// circle
var circle = new shape('circle');
// override
circle.display = function(a,b){
// call implementation of the super class
this.__proto__.display.apply(this,arguments);
}
If I understand correctly, you want Base functionality to always be performed, while a piece of it should be left to implementations.
You might get helped by the 'template method' design pattern.
Base = function() {}
Base.prototype.do = function() {
// .. prologue code
this.impldo();
// epilogue code
}
// note: no impldo implementation for Base!
derived = new Base();
derived.impldo = function() { /* do derived things here safely */ }
If you know your super class by name, you can do something like this:
function Base() {
}
Base.prototype.foo = function() {
console.log('called foo in Base');
}
function Sub() {
}
Sub.prototype = new Base();
Sub.prototype.foo = function() {
console.log('called foo in Sub');
Base.prototype.foo.call(this);
}
var base = new Base();
base.foo();
var sub = new Sub();
sub.foo();
This will print
called foo in Base
called foo in Sub
called foo in Base
as expected.
Another way with ES5 is to explicitely traverse the prototype chain using Object.getPrototypeOf(this)
const speaker = {
speak: () => console.log('the speaker has spoken')
}
const announcingSpeaker = Object.create(speaker, {
speak: {
value: function() {
console.log('Attention please!')
Object.getPrototypeOf(this).speak()
}
}
})
announcingSpeaker.speak()
No, you would need to give the do function in the constructor and the do function in the prototype different names.
In addition, if you want to override all instances and not just that one special instance, this one might help.
function MyClass() {}
MyClass.prototype.myMethod = function() {
alert( "doing original");
};
MyClass.prototype.myMethod_original = MyClass.prototype.myMethod;
MyClass.prototype.myMethod = function() {
MyClass.prototype.myMethod_original.call( this );
alert( "doing override");
};
myObj = new MyClass();
myObj.myMethod();
result:
doing original
doing override
function MyClass() {}
MyClass.prototype.myMethod = function() {
alert( "doing original");
};
MyClass.prototype.myMethod_original = MyClass.prototype.myMethod;
MyClass.prototype.myMethod = function() {
MyClass.prototype.myMethod_original.call( this );
alert( "doing override");
};
myObj = new MyClass();
myObj.myMethod();

Categories

Resources