is there a better way to set scope to global variable functions? - javascript

so I'm having a problem with scope in javascript. I'm currently writing a little js app to allow me to create console-based(or looking) games on my website super quickly and have most of my utility and specific console-application functions stored within variables.
The problem occurs when I wanna add a "setTimeout" or Interval function and want to use my variable functions. I know about proxy but theres gotta be a better way than calling $.proxy every time I wanna refer to one of my functions, and calling proxy for everything im referring to WITHIN those functions.
jQuery(document).ready(function(){
let gameStart = $.proxy(game.start, game);
setTimeout(gameStart, 1000);
});
let options = {
"consoleOutputDiv":"#console-output",
"thisIsHowIFormatText":"something"
};
let utils = {
formattxt: function(str){
let formatted = str;
let toReplace = options.thisIsHowIFormatText;
//I need to refer to options.thisIsHowIFormatText now and thats not possible.
//format text here!
return formatted;
}
}
let consolApp = {
log: function(str){
let stringToBeLogged = str;
//ok so now I need to refer to formattxt which refers to options.thisIsHowIFormatText
let format = $.proxy(utils.formattxt, utils, str);
stringToBeLogged = format();
//print stringToBeLogged to my console div.
}
}
let game = {
start: function() {
let consol = $.proxy(consolApp.log, consolApp, 'please log me!');
consol();
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id='console-output'></div>
I just think there's gotta be a better way! That gets tedious and just looks gross to me constantly calling $.proxy everywhere to allow for my functions to work.

Here's a small OOP suggestion for your code, perhaps just enough to give you an idea of how this kind of app might be structured:
When the window is loaded a new game is created, after a 1 second timeout.
The game creates a console when it is started.
The console uses a static utils method.
class Utils {
static format(str){
let formatted = str + "!!!"
return formatted;
}
}
class Console {
log(str){
let stringToBeLogged = Utils.format(str);
console.log(stringToBeLogged)
}
}
class Game {
start() {
let consol = new Console()
consol.log('please log me...');
}
}
window.addEventListener("load", () => {
setTimeout(()=>{
let g = new Game()
g.start()
}, 1000)
})

Related

Spy function with elementary JavaScript syntax [duplicate]

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.
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.

How to access variables from a function inside executed inside another function?

I am refactoring my https://github.com/perdugames/cacau test library, which I did to learn a bit more about JavaScript and testing. The problem is that I'm not liking how FIXTURE are currently working on it, so I decided to refactor, and I wanted to get the result below, but I still do not know how to make the "addTest" functions have access to "x".
const runner = new Runner();
runner.addSuite(() => {
console.log('Suite 1');
runner.addFixture(() => {
console.log('Suite');
const x = 10;
});
runner.addTest(() => {
console.log('Test 1');
console.log(x);
});
runner.addTest(() => {
console.log('Test 2');
console.log(x);
});
});
runner.run();
Note: Of course without the use of globals, and without adding to the scope of "runner".
Actually, you should be using contexts. Please read more about contexts in javascript. There's plenty of sites.
In your case you can call a context
obj.funcA(() => {
let ctx = this;
console.log('A');
obj.funcA1(() => {
let ctxFncA1 = this // context of previous level... etc.
console.log('A1');
const x = 10;
});
// ... you get the point.
});
In general what you're trying to do is not "ok". If you go build object class, the JavaScript language might allow you to do really anything, but you must not.
Probably you should look into object programmation in JavaScript (book or training website).
Actually you have an example describing pretty much what you desire on : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let (Code is copy/pasted from there.)
var Thing;
{
let privateScope = new WeakMap();
let counter = 0;
Thing = function() {
this.someProperty = 'foo';
privateScope.set(this, {
hidden: ++counter,
});
};
Thing.prototype.showPublic = function() {
return this.someProperty;
};
Thing.prototype.showPrivate = function() {
return privateScope.get(this).hidden;
};
}
console.log(typeof privateScope);
// "undefined"
var thing = new Thing();
console.log(thing);
// Thing {someProperty: "foo"}
thing.showPublic();
// "foo"
thing.showPrivate();
// 1
I do not believe this is physically possible. You would have to pass the the variable to the function in order to access it if you do not want a global variable, or have it accessible in the scope of a class or object.
While this variable should be in your heap, there is no way to communicate its address to the scope of the new function without passing something to it, either a pointer or the value itself.
I found two ways to resolve the issue, the first was:
function test(){
console.log(this.x * 2);
}
function fixture() {
this.x = 5;
}
test.call(new fixture()) // 10
This is the worst way I found, since I will always have to use "this", and I will still have to deal with FIXTURE as a constructor function, otherwise it would be better to use a literal object in this case.
The second way I chose it is simpler, and it already fits in with what I have ready:
const runner = new Runner();
runner.addSuite(() => {
console.log('Suite 1');
var x;
runner.addFixture(() => {
console.log('Suite');
x = 1;
x++;
});
runner.addTest(() => {
console.log('Test 1');
console.log(x); // 2
});
runner.addTest(() => {
console.log('Test 2');
console.log(x); // 2
});
});

How function reference works in js?

Recently I've been trying to use pixi.js for some fun project and I come across a concept that I do not understand at all. Quoting some code:
PIXI.loader
.add([
"images/one.png",
"images/two.png",
"images/three.png"
])
.on("progress", loadProgressHandler)
.load(setup);
function loadProgressHandler(loader, resource) {
console.log(`loading: ${resource.url}`);
};
How these arguments (loader, resource) are passed to the function since we only pass the reference to it in the event listener? Can someone show a generic implementation beneath that concept?
Lets say we have a function called callMe that just prints a number that its given:
function callMe(number) {
console.log(`I'm number: ${number}`);
}
callMe(2);
We can create a new variable to that same function, and call the newly created variable. This is possible since it's pointing to the same function that we've created earlier.
const callMeAswell = callMe;
callMe(3);
callMeAswell(4);
In short, this is what's happing inside the PIXI loaders, except for that it's stored somewhere else for you. Lets create a class to store the numbers and the function that we want to call:
function SomeLoader(){
this.numbers = []; // list of numbers we want to store for later usage
this.func = null; // function that we want to call when we're done loading
}
SomeLoader.prototype.add = function(number) {
this.numbers.push(number); // add the number to the list of numbers
}
SomeLoader.prototype.on = function(func) {
this.func = func; // just store the function for now, but don't do anything with it
}
SomeLoader.prototype.pretendToLoad = function() {
for(const number of this.numbers) {
this.func(number); // now we're going to call the function that we've stored (callMe in the example below)
}
}
const loader = new SomeLoader();
loader.add(5);
loader.add(6);
loader.on(callMe);
loader.pretendToLoad();
Or fluently:
function SomeLoader(){
this.numbers = [];
this.func = null;
}
SomeLoader.prototype.add = function(number) {
this.numbers.push(number);
return this;
}
SomeLoader.prototype.on = function(func) {
this.func = func;
return this;
}
SomeLoader.prototype.pretendToLoad = function() {
for(const number of this.numbers) {
this.func(number);
}
}
new SomeLoader()
.add(7)
.add(8)
.on(callMe)
.pretendToLoad();
Looks almost the same as the PIXI loaders, doesn't it? :)
Arguments are passed to the function when it is called.
The code which calls that function isn't in the question. It is done somewhere behind the on function.
In short: The same way as normal, you just aren't looking at the point where it happens.
const show = value => console.log(value);
const call_callback_with_hello_world = callback => callback("Hello, world");
call_callback_with_hello_world(show);
What #Quentin said is correct - adding on to that however...
A generic concept beneath that implemention is called a callback and would look like so:
function Loop(callback, index){
callback(index);
}
function CallbackFunction(val){
console.log(val)
}
for(var i = 0; i < 5; i++){
Loop(CallbackFunction, i);
}

Javascript prototype function override when x

In my case, I'm using the Phaser framework.
So in this example I'm extending the Group class of phaser. Every 'actor' class (Sprite, Group, ...) calls upon the update() prototype every few miliseconds.
My idea was to extend this function only when the application runs on a desktop (so not on a phone).
for example:
var MousePointer = function (game, parent, name) {
Phaser.Group.call(this, game, parent, name);
this.init();
};
MousePointer.prototype = Object.create(Phaser.Group.prototype);
MousePointer.prototype.constructor = MousePointer;
MousePointer.prototype.init = function () {
// ... init
};
MousePointer.prototype.update = function () {
// Do something when on desktop
};
I can't possibly use an if clausule in the update() function to check whether the player is on dekstop/tablet/phone. So is there a way to actually override the prototype on initialisation?
for example (pseudocode):
if(onPhone)
MousePointer.prototype.update = parent.prototype.update;
else
MousePointer.prototype.update = this.update;
Well, you've kind of already written the answer for yourself, haven't you? This code (not inside the init method).
if(onPhone) {
MousePointer.prototype.update = function(){//Phone implementation};
} else {
MousePointer.prototype.update = function(){//Other implementation};
}
I advise against starting off with the "regular" function and then potentially overriding it, since you're just declaring it for nothing.
I think a better way to do this would be to write two different classes that shares the same parent, and then write different update() implementations for them. Then you can just do something like:
if(phone) {
var obj = new PhoneMousePointerObject();
} else {
var obj = new DesktopMousePointerObject();
}
// ... later
obj.update()

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