'hook' types out of anonymous functions - javascript

Is there any way to 'get' a class/function/variable that's declared inside a function? example:
() => {
class foo{
}
const bar = () =>
{
console.log("Can print from outside?")
}
}
//Any way to make this possible?:
console.log(new foo())
bar()
Note: Can't change the anonymous function (injection related)

JS is lexical scope, you can't access a local variable outside its function.
you may wanna check Closures
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures

This is really hacky!!, but if you don't mind another instance of the code you can just get the current source and wrap inside a function that exposes the foo & bar..
eg..
const anom = () => {
class foo{
}
const bar = () =>
{
console.log("Can print from outside?")
}
}
let code = anom.toString();
code =
code.slice(
code.indexOf('{') + 1,
code.lastIndexOf('}')
) + 'return {foo, bar}';
const f = new Function(code);
const {foo, bar} = f();
bar();
var fooInst = new foo();
console.log(fooInst);

Related

Generically apply context to method aliases

I an encountering a problem which I can't solve. I don't know whether it is a lack knowledge, or the fact that it is not even possible in Javascript, but I hope to get to know it.
I am trying to execute a list of function aliases in an object. When executing these functions, I would like to use them as if they were executed right from the instance itself, So I can use other methods and instance variables within that called method. To make my explaination a bit more clear, here is an example:
class Bar {
constructor() {
this.name = "Bar";
}
someMethod() {
console.log(this.name) // should log Bar
}
}
class Foo {
constructor() {
this.name = "Foo";
}
someOtherMethod() {
console.log(this.name) // should log Foo
}
}
const bar = new Bar();
const foo = new Foo();
const methodList = {
foo: bar.someMethod,
baz: foo.someOtherMethod,
}
for(let prop in methodList) {
methodList[prop](); // logs 2x undefined
}
for(let prop in methodList) {
methodList[prop].apply(foo); //logs 2x Foo
}
As can be seen in the example above, this.name is a variable in the instance of the class. When executing the second loop, a context is applied and logs correctly, as expected. I would like to see that context being applied automatically, since the function alias object is executed in a different file, not knowing about foo or bar and just receiving the list.
Is there any way to achieve this?
You could wrap your foo and bar methods in a function of their own. Within these methods you could then call the object's method someMethod()/someOtherMethod() on the object like so:
const methodList = {
foo: (...args) => bar.someMethod(...args),
baz: (...args) => foo.someOtherMethod(...args),
}
At the moment your first loop doesn't work because your this doesn't refer to the actual context of the object as that isn't what is used to invoke the method. It instead refers to your methodList
See example bellow:
class Bar {
constructor() {
this.name = "Bar";
}
someMethod() {
console.log(this.name) // should log Bar
}
}
class Foo {
constructor() {
this.name = "Foo";
}
someOtherMethod() {
console.log(this.name) // should log Foo
}
}
const bar = new Bar();
const foo = new Foo();
const methodList = {
foo: (...args) => bar.someMethod(...args),
baz: (...args) => foo.someOtherMethod(...args),
}
for(let prop in methodList) {
methodList[prop](); // correct logs
}
This happens because the contextual this when invoking methodList[prop]
is methodList, hence this in someMethod and someOtherMethod is actually:
{
foo: bar.someMethod,
baz: foo.someOtherMethod,
}
To solve the issue, you can wrap the methods in an anonymous function returning the invoked method, as shown below:
class Bar {
constructor() {
this.name = "Bar";
}
someMethod(a,b,c) {
console.log(a,b,c,this.name) // should log Bar
}
}
class Foo {
constructor() {
this.name = "Foo";
}
someOtherMethod(a,b,c) {
console.log(a,b,c,this.name) // should log Foo
}
}
const bar = new Bar();
const foo = new Foo();
const methodList = {
foo: (...args) => bar.someMethod(...args), // <-- anonymous function that, once invoked, returns `bar.someMethod()`, hence the contextual `this` of someMethod will be `bar`.
baz: function() { // <-- same as above, just written without the lambda notation.
return foo.someOtherMethod(...arguments);
}//^
}// | <-- that evaluation is actually calling the above code block.
// |-------------------------------------|
for(let prop in methodList) {// |
methodList[prop](1,4,'hello'); // <------|
}

Is it possible to get name property of a function without using new using ES6 in strict mode? [duplicate]

I need the current function name as a string to log to our log facility. But arguments.callee.name only works in loose mode. How to get the function name under "use strict"?
For logging/debugging purposes, you can create a new Error object in the logger and inspect its .stack property, e.g.
function logIt(message) {
var stack = new Error().stack,
caller = stack.split('\n')[2].trim();
console.log(caller + ":" + message);
}
function a(b) {
b()
}
a(function xyz() {
logIt('hello');
});
You can bind function as its context then you can access its name via this.nameproperty:
function x(){
console.log(this.name);
}
x.bind(x)();
After little research here is a good solution :
function getFnName(fn) {
var f = typeof fn == 'function';
var s = f && ((fn.name && ['', fn.name]) || fn.toString().match(/function ([^\(]+)/));
return (!f && 'not a function') || (s && s[1] || 'anonymous');
}
function test(){
console.log(getFnName(this));
}
test = test.bind(test);
test(); // 'test'
Source : https://gist.github.com/dfkaye/6384439
Building on #georg solution, this one returns just the function name. Note though that it may fail if called from an anonymous function
function getFncName() {
const stackLine = (new Error())!.stack!.split('\n')[2].trim()
const fncName = stackLine.match(/at Object.([^ ]+)/)?.[1]
return fncName
}
function Foo() {
console.log(getFncName()) // prints 'Foo'
}
A simple solution to dynamically retrieve function names [like magic variables] is the use of scoped variables, and the Function.name property.
{
function foo() {
alert (a.name);
}; let a = foo
}
{
function foo2() {
alert(a.name)
}; let a = foo2
};
foo();//logs foo
foo2();//logs foo2
Note: Nested functions cease to be source elements, and are hence not hoisted. Also, this technique cannot work with anonymous functions.
If (like me) you want to define this elsewhere and call it generically, you can store the code as a string somewhere global or import it, then eval() it wherever to access the current function name. (Using eval keeps the context at the point of invocation.)
There's gotta be a way to do this without using a string, but whatever.
SomeObject.whatFunc =
'const s = new Error().stack;' +
"const stackLine = new Error().stack.split('\\n')[2].trim();" +
'const fncName = stackLine.match(/(?<=at )(.*)(?= \\()/gm)[0];' +
'console.log(fncName);'
// Whereever you want the func name
function countBananas('weeee') {
eval(SomeObject.whatFunc)
// blah blah blah
}
countBananas() // logs 'countBananas'
just an update to get the full name :
function logIt(message) {
var stack = new Error().stack,
// update is on this line
caller = stack.split('\n')[2].trim().split(/\s+/)[1];
console.log(caller.trim().split(/\s+/)[1];);
}
function a(b) {
b()
}
a(function xyz() {
logIt('hello');
});

How to pass a function to a class that later modifies said class

I am trying to create a class that is modified by a function that is set upon construction.
The problem is, how do I get this function to modify the private fields of the class it's assigned to.
I have created a simplified code to explain:
https://jsfiddle.net/9zjc0k9e/ (same code as below):
The class to be modified:
foo = function(options) {
let {func} = options; //The function we send on construction
let a = []; //The variable we are trying to modify with the function
function executer(v) {
func(v);
}
return {executer};
};
Main:
//The function we will send when constructing:
let funk = function(v) {
a.push(v); // <- this 'a' is the private member of the class we wanna modify
}
//Construct:
let bar = new foo({
func: funk
});
//Run the function we sent through the public class function assigned to that
bar.executer(1); //<-- Uncaught ReferenceError: a is not defined
The error I'm getting is: Uncaught ReferenceError: a is not defined.
I hope I have cleared the problem enough, is there a way to get this done? Hack-ish is acceptable.
There is no way for the outer function to see the local variable a without passing. The function tries to find the variables in that place where it is defined, means that the outer funk has no access any variable of foo implicitly. If a was an object variable you could access it via context binding.
You need to pass the reference of a too to the function.
let funk = function(v, array) {
array.push(v);
}
And call via
function executer(v) {
func(v, a);
}
Your Code
foo = function(options) {
let {func} = options;
let a = [];
function executer(v) {
func(v, a);
}
return {executer};
};
let funk = function(v, array){
array.push(v);
}
let bar = new foo({
func: funk
});
bar.executer(1);

When is an object completely defined?

I'm learning javascript and want to define 2 classes inside an object. The second class is derived from the first class.
It looks like:
let foo = {
bar: (function () {
let bar_msg = '';
class bar {
constructor(msg) {
bar_msg = msg;
}
}
return bar;
}()),
baz: (function () {
let baz_msg = '';
class baz extends foo.bar {
constructor(msg) {
super();
baz_msg = msg;
}
}
return baz;
}())
};
Error message:
Uncaught ReferenceError: foo is not defined
Then, I've tried to split the classes to multiple parts:
let foo = {};
foo.bar = (function () {
let bar_msg = '';
class bar {
constructor(msg) {
bar_msg = msg;
}
}
return bar;
}());
foo.baz = (function () {
let baz_msg = '';
class baz extends foo.bar {
constructor(msg) {
super();
baz_msg = msg;
}
msg() {
return baz_msg;
}
}
return baz;
}());
let b = new foo.baz('hi!');
console.log(b.msg());
It works.
So, my question is: Why do I get the difference? I cannot show some google search results because I have no idea about the keywords.
An object is 'completely' defined when you declared it and assign it a value like so:
var foo = 'bar';
You may declare a variable but not assign it to any value:
var foo;
and when you try to access it, it will give you undefined. You may also assign a value to an undeclared variable:
foo = 'bar';
And the javascript will automatically create a global variable foo. If you try to access a variable that has never been declared or implicitly declared (e.g foo = 'bar'). It will throw an error;
console.log(iDoNotExist); // will throw an error!
In your first code, the class baz, could not locate foo in its own scope, so it will go to the global scope. But since it's also not available in the global scope and it has neither been declared explicitly nor implicitly, it will throw an error.
In the second code, you have explicitly declared foo and assign it to an object and added a property bar right after it. Any code written after foo is declared would be able to access it, including when you assign the property bar to foo, in which a class called baz tries to extend foo.bar. If the piece of code that tries to extend foo or foo.bar is written after the definition of foo. It will throw an error. See snippet below for example:
class baz extends foo {
constructor(msg) {
super();
baz_msg = msg;
}
msg() {
return baz_msg;
}
}
let foo = {};
let b = new foo.baz('hi!');
In summary, you get the difference because the accessibility of foo. In the first variable you try to access it before it is both neither explicitly nor implicitly defined, resulting in an error. In the second variable, you've declared and assigned it to a value and try to access it after, which is perfectly legal.

Access function by dot path without disconnecting `this` (maintain `this` on destructure)

I have a function that executes functions in a scope. Super simplified case:
function exec(method_name, ...args) {
scope[method_name](...args);
}
Now i have a need to execute a method in an object in the scope. The object is named foo and I need to execute foo.bar().
When I do this:
class FooBar {
constructor() {
this.msg = 'hiii';
this.bar = this.bar.bind(this);
}
bar()
alert(this.msg);
}
}
var foo = new FooBar;
const deepAccessUsingString = (obj, dotpath) => dotpath.split('.').reduce((nested, key) => nested[key], obj);
function exec(mdotpath, ...args) {
deepAccessUsingString(scope, mdotpath)(...args);
}
exec('foo.bar');
I am getting disconnected from this. If I do foo.bar() it works perfectly.
Is there any way other then hard coding in different cases for number of arguments like this below:
let md = mdotpath.split('.');
switch(md.length) {
case 1: return scope[md[0]];
case 2: return scope[md[0]][md[1]]();
case 3: return scope[md[0]][md[1]][md[2]]();
default: throw new Error('not yet supported, you need to hard code in for length of ' + md.length)
}

Categories

Resources