Javascript ES6 Classes composition - javascript

i'm struggling in what would be a good practice or better approach to communicate 'sibling classes in es6' quoted because they haven't a real parent class, by definition.
let me explain better:
class Car {
constructor(typeOfMotor){
this.motor = typeOfMotor;
this.mount();
this.addListener();
}
mount() {
// Some async logic here, and this will return true or false;
}
addListener(driver) {
// Here i want to listen this.mount method and,
// when return true, then call the ride method in the driver
// If true:
driver.ride();
}
}
class Driver {
constructor(driverName) {
this.name = driverName;
}
ride(){
console.log('Highway to hell!');
}
}
class Race {
constructor() {
this.init();
}
init() {
this.car = new Car('v8');
this.driver = new Driver('michael');
}
}
var race = new Race;
race.car.addListener(race.driver);
So basically, i have some environments where i don't need to extend classes, because i want to keep them as encapsulated as possible.
And i have this top Class (not parent because the others are not inheriting anything, though).
And the question is simple, what would be the best way to create this communication between the elements.

You can pass the Driver class instance to the Car constructor and invoke any method within this instance.
I would rethink the structure and business logic here and check what kind of responsibility each component should handle.
For example, i think it's up to the driver to decide when to drive but of course the car should signal when it is ready.
So the car shouldn't invoke driver.ride and instead just signal the driver i'm on and ready to go, and the driver should invoke the driving function.
But that's arguable of course.
Here is a running example of your code (a bit modified):
class Car {
constructor(typeOfMotor, driver) {
this.motor = typeOfMotor;
this.mounted = this.mount();
this.driver = driver;
}
mount = () => {
console.log('fetching data...');
setTimeout(() => {
this.drive()
}, 1500)
}
drive = () => {
// Here i want to listen this.mount method and,
// when return true, then call the ride method in the driver
// If true:
this.driver.ride();
}
}
class Driver {
constructor(driverName) {
this.name = driverName;
}
ride = () => {
console.log('Highway to hell!');
}
}
class Race {
constructor() {
this.init();
}
init = () => {
this.driver = new Driver('michael');
this.car = new Car('v8', this.driver);
}
}
var race = new Race();

Related

Objects duplicating every component mount. How can I make it run only once ? In react

My object is a independent js file that I created.
componentDidMount() {
const node = ReactDOM.findDOMNode(this);
const widgetBuild = new window.WidgetFormBuilder({
form: $(node).parents('#dynamic_form_wrapper')
});
widgetBuild.initForm();
}
It is a little hard to workout without knowing more about WidgetFormBuilder.
However as good practice I would suggest...
componentDidMount() {
const node = ReactDOM.findDOMNode(this);
// Assign to the class instance
this.widgetBuild = new window.WidgetFormBuilder({
form: $(node).parents('#dynamic_form_wrapper')
});
this.widgetBuild.initForm();
}
componentWillUnmount() {
// Cleanup
// Check if WidgetFormBuilder has a destroy method or something similar.
// See https://reactjs.org/docs/react-component.html#componentwillunmount
this.widgetBuild = null;
}
shouldComponentUpdate() {
// Stop further re-renders, given you're using the DOM directly this could help prevent a few performance issues
// See https://reactjs.org/docs/react-component.html#shouldcomponentupdate
return false;
}
Finally, take a look at the react docs on third party libs.
I already fixed i just added a .destroy() function in my WidgetFormBuilder. :)
WidgetFormBuilder.prototype.destroyBuilder = function () {
const self = this;
const destroyEvents = function () {
$(self.form).unbind();
};
destroyEvents();
return this;
};

Clear references to function

I need to clear memory in js, I have classes like this:
class A{
constructor(socket){
this.initSockets(socket);
}
classMethod(){
}
initSockets(socket){
socket.on('name', () => this.classMethod())
}
}
This class cannot be cleaned by the garbage collector, because as I understand socket saves the reference to a class method(memory snapshot point to socket.on), how properly I need "to null" this function, to delete the reference and let garbage collector delete this class? The project becomes a little big, so I can't change the way I use sockets.
Since 2018 some years have passed and now we write the year 2022;
By now we have stuff like WeakMap, WeakSet and WeakRefs... and the V8 Team has described how to accomplish exactly that with "Weak references and finalizers": https://v8.dev/features/weak-references
This is the procedure they suggest:
const gListenersRegistry = new FinalizationRegistry(({ socket, wrapper }) => {
socket.removeEventListener('message', wrapper); // 6
});
function addWeakListener(socket, listener) {
const weakRef = new WeakRef(listener); // 2
const wrapper = (ev) => { weakRef.deref()?.(ev); }; // 3
gListenersRegistry.register(listener, { socket, wrapper }); // 4
socket.addEventListener('message', wrapper); // 5
}
class MovingAvg {
constructor(socket) {
this.events = [];
this.listener = (ev) => { this.events.push(ev); }; // 1
addWeakListener(socket, this.listener);
}
}
For more details read the article above.

Better method for acting upon state change in JavaScript classes

I'm trying to move from procedural to object-oriented JavaScript and I'm coming up against an issue I'm sure there's an answer to, but I can't work it out.
Currently, each of my methods checks the state of a property, and then performs an action based on that state. What I'd rather do is update the state and those methods execute as a result of the state change. Is that possible, or am I missing the point?
Here's what I have currently:
class ClassExample {
constructor({state = false} = {}) {
this.state = state;
...
}
aMethod() {
if(this.state) {
//Do something
this.state = false;
} else {
//Do something else
this.state = true;
}
}
bMethod() {
if(this.state) {
//Do something
this.state = false;
} else {
//Do something else
this.state = true;
}
}
}
And:
const myObject = new ClassExample();
myObject.aMethod();
myObject.bMethod();
Given both methods are checking the same property, it's resulting in a lot of redundant if statements. Is there a better way to organise this class to achieve the same result?
I'd suggest you use an event driven system based on the EventEmitter() object built into node.js.
To keep track of state changes, you can define a setter for your state variables so that any time someone sets a new state, then your setter function will get called and it can then trigger an event that indicates the state changed. Meanwhile, anyone in your object out outside your object can register an event listener for state changes.
Here's a short example:
const EventEmitter = require('events');
class ClassExample extends EventEmitter {
constructor(state = 0) {
super();
// declare private state variable
let internalState = state;
// define setter and getter for private state variable
Object.defineProperty(this, "state", {
get: function() {
return internalState;
},
set: function(val) {
if (internalState !== val) {
internalState = val;
// send out notification
this.emit("stateChanged", val);
}
}
});
}
}
let e = new ClassExample(1);
console.log(e.state);
e.on("stateChanged", function(newVal) {
console.log("state has changed to ", newVal);
});
e.state = 3;
console.log(e.state);

What is the least-dirty way to expose private javascript vars for testing?

I've got a state machine in JS which (to simplify) has an initial state that is only set before anything happens.
define(function() {
var state = 'initial',
exports = {};
exports.getState = function() {
return state;
};
exports.doSomething = function() {
state = 'newState';
};
return exports;
});
Because the state is permanent until the app is reloaded, after the first test the state will never be 'initial' again, and so I need a way to reset it.
Which is the least dirty way of doing this? Should I...
a) simply make state public but mark it as private with _?
define(function() {
var exports = {};
exports._state = 'initial'
exports.getState = function() {
return this.state;
};
exports.doSomething = function() {
this.state = 'newState';
};
return exports;
});
b) make the state writable via a function?
define(function() {
var state = 'initial',
exports = {};
exports.getState = function() {
return state;
};
exports.doSomething = function() {
state = 'newState';
};
if(window.xxTests) {
window.xxTests.Module = {
setState: function(newState) {
state = newState;
}
};
}
return exports;
});
(where xx is the app prefix and xxTests is defined only as part of the test runner)
or
c) do something else entirely I didn't think of?
Your thoughts and suggestions are appreciated.
General answer: The better way of testing a component without exposing private data is putting test code inside that component. Of course this becomes quite dirty if your language doesn't support this in a clean way (like D does).
In your case I suggest the second way (I mean your option b), because it doesn't expose private data unless explicitly needed (only during tests):
if(youAreDoingATest)
{
exports.reset=function() { state='initial'; };
}
There's not a lot of context on how you're running your tests.
Most test runners have beforeEach(), beforeAll(), afterEach(), and afterAll() methods that can be used for setup and tear-down that run as their names suggest.
To solve your specific problem I would not change your "state machine" code at but instead I would create a new state machine in the beforeEach() function so that each test gets the new function object with the state set to 'initial'.

Javascript: Extend a Function

The main reason why I want it is that I want to extend my initialize function.
Something like this:
// main.js
window.onload = init();
function init(){
doSomething();
}
// extend.js
function extends init(){
doSomethingHereToo();
}
So I want to extend a function like I extend a class in PHP.
And I would like to extend it from other files too, so for example I have the original init function in main.js and the extended function in extended.js.
With a wider view of what you're actually trying to do and the context in which you're doing it, I'm sure we could give you a better answer than the literal answer to your question.
But here's a literal answer:
If you're assigning these functions to some property somewhere, you can wrap the original function and put your replacement on the property instead:
// Original code in main.js
var theProperty = init;
function init(){
doSomething();
}
// Extending it by replacing and wrapping, in extended.js
theProperty = (function(old) {
function extendsInit() {
old();
doSomething();
}
return extendsInit;
})(theProperty);
If your functions aren't already on an object, you'd probably want to put them there to facilitate the above. For instance:
// In main.js
var MyLibrary = {
init: function init() {
}
};
// In extended.js
(function() {
var oldInit = MyLibrary.init;
MyLibrary.init = extendedInit;
function extendedInit() {
oldInit.call(MyLibrary); // Use #call in case `init` uses `this`
doSomething();
}
})();
But there are better ways to do that. Like for instance, providing a means of registering init functions.
// In main.js
var MyLibrary = (function() {
var initFunctions = [];
return {
init: function init() {
var fns = initFunctions;
initFunctions = undefined;
for (var index = 0; index < fns.length; ++index) {
try { fns[index](); } catch (e) { }
}
},
addInitFunction: function addInitFunction(fn) {
if (initFunctions) {
// Init hasn't run yet, remember it
initFunctions.push(fn);
} else {
// `init` has already run, call it almost immediately
// but *asynchronously* (so the caller never sees the
// call synchronously)
setTimeout(fn, 0);
}
}
};
})();
Here in 2020 (or really any time after ~2016), that can be written a bit more compactly:
// In main.js
const MyLibrary = (() => {
let initFunctions = [];
return {
init() {
const fns = initFunctions;
initFunctions = undefined;
for (const fn of fns) {
try { fn(); } catch (e) { }
}
},
addInitFunction(fn) {
if (initFunctions) {
// Init hasn't run yet, remember it
initFunctions.push(fn);
} else {
// `init` has already run, call it almost immediately
// but *asynchronously* (so the caller never sees the
// call synchronously)
setTimeout(fn, 0);
// Or: `Promise.resolve().then(() => fn());`
// (Not `.then(fn)` just to avoid passing it an argument)
}
}
};
})();
There are several ways to go about this, it depends what your purpose is, if you just want to execute the function as well and in the same context, you can use .apply():
function init(){
doSomething();
}
function myFunc(){
init.apply(this, arguments);
doSomethingHereToo();
}
If you want to replace it with a newer init, it'd look like this:
function init(){
doSomething();
}
//anytime later
var old_init = init;
init = function() {
old_init.apply(this, arguments);
doSomethingHereToo();
};
The other methods are great but they don't preserve any prototype functions attached to init. To get around that you can do the following (inspired by the post from Nick Craver).
(function () {
var old_prototype = init.prototype;
var old_init = init;
init = function () {
old_init.apply(this, arguments);
// Do something extra
};
init.prototype = old_prototype;
}) ();
Another option could be:
var initial = function() {
console.log( 'initial function!' );
}
var iWantToExecuteThisOneToo = function () {
console.log( 'the other function that i wanted to execute!' );
}
function extendFunction( oldOne, newOne ) {
return (function() {
oldOne();
newOne();
})();
}
var extendedFunction = extendFunction( initial, iWantToExecuteThisOneToo );
2017+ solution
The idea of function extensions comes from functional paradigm, which is natively supported since ES6:
function init(){
doSomething();
}
// extend.js
init = (f => u => { f(u)
doSomethingHereToo();
})(init);
init();
As per #TJCrowder's concern about stack dump, the browsers handle the situation much better today. If you save this code into test.html and run it, you get
test.html:3 Uncaught ReferenceError: doSomething is not defined
at init (test.html:3)
at test.html:8
at test.html:12
Line 12: the init call, Line 8: the init extension, Line 3: the undefined doSomething() call.
Note: Much respect to veteran T.J. Crowder, who kindly answered my question many years ago, when I was a newbie. After the years, I still remember the respectfull attitude and I try to follow the good example.
This is very simple and straight forward. Look at the code. Try to grasp the basic concept behind javascript extension.
First let us extend javascript function.
function Base(props) {
const _props = props
this.getProps = () => _props
// We can make method private by not binding it to this object.
// Hence it is not exposed when we return this.
const privateMethod = () => "do internal stuff"
return this
}
You can extend this function by creating child function in following way
function Child(props) {
const parent = Base(props)
this.getMessage = () => `Message is ${parent.getProps()}`;
// You can remove the line below to extend as in private inheritance,
// not exposing parent function properties and method.
this.prototype = parent
return this
}
Now you can use Child function as follows,
let childObject = Child("Secret Message")
console.log(childObject.getMessage()) // logs "Message is Secret Message"
console.log(childObject.getProps()) // logs "Secret Message"
We can also create Javascript Function by extending Javascript classes, like this.
class BaseClass {
constructor(props) {
this.props = props
// You can remove the line below to make getProps method private.
// As it will not be binded to this, but let it be
this.getProps = this.getProps.bind(this)
}
getProps() {
return this.props
}
}
Let us extend this class with Child function like this,
function Child(props) {
let parent = new BaseClass(props)
const getMessage = () => `Message is ${parent.getProps()}`;
return { ...parent, getMessage} // I have used spread operator.
}
Again you can use Child function as follows to get similar result,
let childObject = Child("Secret Message")
console.log(childObject.getMessage()) // logs "Message is Secret Message"
console.log(childObject.getProps()) // logs "Secret Message"
Javascript is very easy language. We can do almost anything. Happy JavaScripting... Hope I was able to give you an idea to use in your case.
as I understand it, you are trying to fetch the applications connected to the user account. You can do this by making a request on the API, I don't know if discord.js covers this part of the API
endpoint: https://discord.com/api/users/#me/connections
Request type: GET Header:
Authorization: "Beareryou token"
response: [
{...}
]
Use extendFunction.js
init = extendFunction(init, function(args) {
doSomethingHereToo();
});
But in your specific case, it's easier to extend the global onload function:
extendFunction('onload', function(args) {
doSomethingHereToo();
});
I actually really like your question, it's making me think about different use cases.
For javascript events, you really want to add and remove handlers - but for extendFunction, how could you later remove functionality? I could easily add a .revert method to extended functions, so init = init.revert() would return the original function. Obviously this could lead to some pretty bad code, but perhaps it lets you get something done without touching a foreign part of the codebase.

Categories

Resources