Referencing extra argument passed to function in JavaScript - function

I have a function that looks like this:
abc = function (func) {
let object = {};
return function() {
let arg = ???
if (*something*) {
object[arg] = func.apply(this, arg);
}
else {
return object[arg];
}
}
};
My problem is, how do I refer to arg if arg is an extra argument passed to abc?
Thank you!

Related

Casting fails when deserializing JSON

Please take into account that this question is about Typescript and not vanilla Javascript.
I am trying to deserialize a very simple JSON string into a Typescript object and then casting into the correct type.
After casting at const obj = <FooClass>JSON.parse(s) I would expect the typeof operator to return FooClass. Why the operator still returns object ?
Why does casting here fails? How can I deserialize and still have access to somefunc ?
Example code:
class FooClass {
public baz = 0
public somefunc() {
return this.baz * 2
}
}
const jsonData = {
baz: 1234,
}
test('deserialize example', () => {
const s = JSON.stringify(jsonData)
const obj = <FooClass>JSON.parse(s) // Cast here
console.log(typeof obj) // typeof still returns object
console.log(obj)
console.log(obj.somefunc())
})
Output:
console.log
object
at Object.<anonymous> (tests/deserialize.test.ts:15:11)
console.log
{ baz: 1234 }
at Object.<anonymous> (tests/deserialize.test.ts:17:11)
TypeError: obj.somefunc is not a function
In typescript you can cast any (return type of JSON.parse) to anything. The responsibility of ensuring if the casting is "correct", and the casted value indeed matches the type it's being casted to is yours.
Casting is only telling the type checker how to treat that value from the point of casting.
Turning that object to an instance of your class is also your responsibility. You could however do something like this:
type Foo = {
baz: number
}
class FooClass {
public baz: number = 0
constructor(input: Foo) {
this.baz = input.baz
}
public somefunc() {
return this.baz * 2
}
}
const rawFoo = JSON.parse(s) as Foo
const fooClassInstance = new FooClass(rawFoo)
// ready to be used as an instance of FooClass
Playground
For completion, I copy here a solution that I find both efficient and clean:
test('casting fails example', () => {
const s = JSON.stringify(jsonData)
const obj = Object.assign(new FooClass(), JSON.parse(s))
console.log(typeof obj)
console.log(obj)
console.log(obj.somefunc())
})
This could later be improved using generics
function deserializeJSON<T>(c: { new (): T }, s: string): T {
return Object.assign(new c(), JSON.parse(s))
}
const obj = deserializeJSON(FooClass, s)

How to call function indirectly in Kotlin

Assume I have a mutableMap:
val MM = mutableMapOf()
Now I define a function as a method for it:
MM["testF"] = fun () {
println("WOW")
}
Now I want to call it in another place:
val MMTF = MM["testF"] as Function<*>
MMTF() <-- NOT WORKING
Any help will be appreciated.
This code will print bar
fun main() {
val map = mutableMapOf<String, () -> Any>()
map["foo"] = {
println("bar")
}
run(map["foo"]!!)
}

Typescript infer return type from passed functions return type

I might be trying to achieve the impossible but here goes.
I want to define a function ( function A ) which will return the same type as a new function passed into the parameter of function A.
e.g.
export function test<T> ( arg:Function ):T {
return arg;
}
function a():string {
return 'a';
}
function b():number {
return 0;
}
let aVal:string = test(a);
let bVal:number = test(b);
Obviously this will allow me to strongly type my responses for some compile time errors.
Does anyone have any ideas or know if I'm just dreaming.
** Note: Code slapped together for demo **
Cheers
How about this?
function test<T>(arg: () => T): T {
return arg();
}
function a(): string {
return 'a';
}
function b(): number {
return 0;
}
let aVal: string = test(a);
let bVal: number = test(b);
Instead of using the Function interface we defined arg as a function that takes no arguments and returns something of type T. The actual type T then can be defined by the function that's passed in.

How to obtain arguments.callee.caller?

I am trying to find out the name of the function that called my Google Apps Script function, by using arguments.callee.caller as in How do you find out the caller function in JavaScript?, but it seems there's no such property exported. (However, arguments.callee exists.)
How can I get that calling function's name in Google Apps Script?
As a secondary question, why isn't arguments.callee.caller there?
I made this function:
function getCaller()
{
var stack;
var ret = "";
try
{
throw new Error("Whoops!");
}
catch (e)
{
stack = e.stack;
}
finally
{
var matchArr = stack.match(/\(.*\)/g);
if (matchArr.length > 2)
{
tmp = matchArr[2];
ret = tmp.slice(1, tmp.length - 1) + "()";
}
return ret;
}
}
It throws as Error() and then gets the function name from the stack trace.
Try vary the '2' in matchArr[2] when using wrappers.
caller is a non-standard extension to JavaScript (that is, many browsers have it but it's not part of the EcmaScript standard) and not implemented in Apps Script.
I made a function to get the call stack based on jgrotius's answer:
function getCallStack()
{
var returnValue = "";
var framePattern = /\sat (.+?):(\d+) \((.+?)\)/;
try
{
throw new Error('');
}
catch (e)
{
returnValue = e.stack
.split('\n')
.filter(function(frame, index) {
return !frame.isBlank() && index > 0;
})
// at app/lib/debug:21 (getCaller)
.map(function(frame) {
var parts = frame.match(framePattern);
return {
file: parts[1],
line: parseInt(parts[2]),
func: parts[3]
};
});
}
return returnValue;
}
This is my updated version of the other two proposed solutions:
const getStacktrace = () => {
try {
throw new Error('')
} catch (exception) {
// example: at getStacktrace (helper:6:11)
const regex = /\sat (.+?) \((.+?):(\d+):(\d+)\)/
return exception
.stack
.split('\n')
.slice(1, -1)
.filter((frame, index) => {
return frame && index > 0
})
.map((frame) => {
const parts = frame.match(regex)
return {
function: parts[1],
file: parts[2],
line: parseInt(parts[3]),
column: parseInt(parts[4])
}
})
}
}
P.S.: please not that the regex has changed and also we are ignoring the first element of the stacktrace, since it is the getStacktrace function itself.

AS3 arguments

Why do you think the code below does not work?
What would you change/add to make it work?
Any help is appreciated..
function TraceIt(message:String, num:int)
{
trace(message, num);
}
function aa(f:Function, ...args):void
{
bb(f, args);
}
aa(TraceIt, "test", 1);
var func:Function = null;
var argum:Array = null;
function bb(f:Function, ...args):void
{
func = f;
argum = args;
exec();
}
function exec()
{
func.apply(null, argum);
}
I get an ArgumentError (Error #1063):
Argument count mismatch on test_fla::MainTimeline/TraceIt(). Expected 2, got 1.
..so, the passed parameter (argum) fails to provide all passed arguments..
..Please keep the function structure (traffic) intact.. I need a solution using the same functions in the same order.. I have to pass the args to a variable and use them in the exec() method above..
regards
Ok, here is the solution.. after breaking my head : )
function TraceIt(message:String, num:int)
{
trace(message, num);
}
function aa(f:Function=null, ...args):void
{
var newArgs:Array = args as Array;
newArgs.unshift(f);
bb.apply(null, newArgs);
}
aa(TraceIt, "test", 1);
var func:Function = null;
var argum:*;
function bb(f:Function=null, ...args):void
{
func = f;
argum = args as Array;
exec();
}
function exec():void
{
if (func == null) { return; }
func.apply(this, argum);
}
This way, you can pass arguments as variables to a different function and execute them..
Thanks to everyone taking the time to help...
When TraceIt() eventually gets called, it's being called with 1 Array parameter, not a String and int parameters.
You could change TraceIt() to:
function TraceIt(args:Array)
{
trace(args[0], args[1]);
}
Or you could change exec() to:
function exec()
{
func.apply(null, argum[0].toString().split(","));
}
...as it appears when you pass "test", 1, you end up with array whose first value is "test,1". This solution doesn't work beyond the trivial case, though.
Change your bb function to look like this:
function bb(f:Function, args:Array):void
{
func = f;
argum = args;
exec();
}
As you have it now, it accepts a variable number of arguments, but you are passing in an array(of the arguments) from aa.