Overriding toString function of a function - javascript

I want to generate a GUID string via the answer.
'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
return v.toString(16);
});
Now, I want to put it into toString function, like: GUID.NewGuid().toString().
I've tried (not working):
let GUID = function () {};
GUID.NewGuid = function () {};
GUID.NewGuid.prototype.toString = function () {
let guid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
let r = Math.random() * 16 | 0, v = c === 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
return guid;
};
Uncaught TypeError: Cannot read property 'toString' of
undefined console.log(GUID.NewGuid().toString());
What I want to achieve: using syntax GUID.NewGuid().toString() to generate an id.
How to fix it?

You need an instance of the class.
var guid = new GUID.NewGuid;
let GUID = function () {};
GUID.NewGuid = function () {};
GUID.NewGuid.prototype.toString = function () {
let guid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
let r = Math.random() * 16 | 0, v = c === 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
return guid;
};
var guid = new GUID.NewGuid;
console.log(guid.toString());

To make #Nina's code act the way I would expect, and you want the late evaluation during toString,. One idea is to alter the object's toString after evaluation, basically create a late binding function on the object, rather than the prototype.
I use this technique often to create late binding methods, some methods could be expensive and doing init's during construction could be time consuming. In this case I'm not sure there is a massive performance boost, but it's a good example of doing it.
let GUID = function () {};
GUID.NewGuid = function () {};
GUID.NewGuid.prototype.toString = function () {
let guid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
let r = Math.random() * 16 | 0, v = c === 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
this.toString = function() { return guid; }; //add this..
return guid;
};
var guid = new GUID.NewGuid;
console.log(guid.toString()); //these two
console.log(guid.toString()); //want to equal the same
guid = new GUID.NewGuid;
console.log(guid.toString()); //now I want a new one.

window[Symbol.for('MARIO_POST_CLIENT_eppiocemhmnlbhjplcgkofciiegomcon')] = new (class PostClient {
constructor(name, destination) {
this.name = name;
this.destination = destination;
this.serverListeners = {};
this.bgRequestsListeners = {};
this.bgEventsListeners = {};
window.addEventListener('message', (message) => {
const data = message.data;
const isNotForMe = !(data.destination && data.destination === this.name);
const hasNotEventProp = !data.event;
if (isNotForMe || hasNotEventProp) {
return;
}
if (data.event === 'MARIO_POST_SERVER__BG_RESPONSE') {
const response = data.args;
if (this.hasBgRequestListener(response.requestId)) {
try {
this.bgRequestsListeners[response.requestId](response.response);
}
catch (e) {
console.log(e);
}
delete this.bgRequestsListeners[response.requestId];
}
}
else if (data.event === 'MARIO_POST_SERVER__BG_EVENT') {
const response = data.args;
if (this.hasBgEventListener(response.event)) {
try {
this.bgEventsListeners[data.id](response.payload);
}
catch (e) {
console.log(e);
}
}
}
else if (this.hasServerListener(data.event)) {
try {
this.serverListeners[data.event](data.args);
}
catch (e) {
console.log(e);
}
}
else {
console.log(`event not handled: ${data.event}`);
}
});
}
emitToServer(event, args) {
const id = this.generateUIID();
const message = {
args,
destination: this.destination,
event,
id,
};
window.postMessage(message, location.origin);
return id;
}
emitToBg(bgEventName, args) {
const requestId = this.generateUIID();
const request = { bgEventName, requestId, args };
this.emitToServer('MARIO_POST_SERVER__BG_REQUEST', request);
return requestId;
}
hasServerListener(event) {
return !!this.serverListeners[event];
}
hasBgRequestListener(requestId) {
return !!this.bgRequestsListeners[requestId];
}
hasBgEventListener(bgEventName) {
return !!this.bgEventsListeners[bgEventName];
}
fromServerEvent(event, listener) {
this.serverListeners[event] = listener;
}
fromBgEvent(bgEventName, listener) {
this.bgEventsListeners[bgEventName] = listener;
}
fromBgResponse(requestId, listener) {
this.bgRequestsListeners[requestId] = listener;
}
generateUIID() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
const r = Math.random() * 16 | 0, v = c === 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}
})('MARIO_POST_CLIENT_eppiocemhmnlbhjplcgkofciiegomcon', 'MARIO_POST_SERVER_eppiocemhmnlbhjplcgkofciiegomcon')

Related

How to create a class that has a property of another class in TypeScript?

I am creating a web application that has a Competitor, hence the class Competitor, and a poll that will join 2 Competitors, hence the class VotingPoll. Here are the classes in JS:
export class Competitor {
constructor(_id, _name, easy, hard, tematicas, random_score, min1, min2, deluxe, replica) {
this._id = _id;
this._name = _name;
this.easy = easy;
this.hard = hard;
this.tematicas = tematicas;
this.random_score = random_score;
this.min1 = min1;
this.min2 = min2;
this.deluxe = deluxe;
this.replica = replica;
}
get id() {
return this._id;
}
get name() {
return this._name;
}
get_sum(mode) {
if (mode === '_name' || mode === '_id') {
throw new Error("mode can't be equal to 'name' nor 'id'");
}
let i = 0;
this[mode].forEach((j) => {
if (j !== 9) {
i += j;
}
});
return i;
}
get_total() {
return (this.get_sum('easy') +
this.get_sum('hard') +
this.get_sum('tematicas') +
this.get_sum('random_score') +
this.get_sum('min1') +
this.get_sum('min2') +
this.get_sum('deluxe'));
}
serialize() {
return JSON.stringify({
id: this._id,
name: this._name,
easy: this.easy,
hard: this.hard,
tematicas: this.tematicas,
random_score: this.random_score,
min1: this.min1,
min2: this.min2,
deluxe: this.deluxe,
replica: this.replica,
});
}
static unserialize(data) {
const newData = JSON.parse(data);
return new Competitor(newData.id, newData.name, newData.easy, newData.hard, newData.tematicas, newData.random_score, newData.min1, newData.min2, newData.deluxe, newData.replica);
}
}
export class VotingPoll {
constructor(_id, comp_1, comp_2) {
this._id = _id;
this.comp_1 = comp_1;
this.comp_2 = comp_2;
}
get id() {
return this._id;
}
get_winner(replica = false) {
const comp_1 = this.comp_1;
const comp_2 = this.comp_2;
// Case replica
if (replica) {
if (comp_1.get_sum('replica') === comp_2.get_sum('replica') ||
Math.abs(comp_1.get_sum('replica') - comp_2.get_sum('replica')) < 6) {
return 'Réplica';
}
const max_num = Math.max(comp_1.get_sum('replica'), comp_2.get_sum('replica'));
return max_num === comp_1.get_sum('replica') ? comp_1.name : comp_2.name;
}
// Normal case
if (comp_1.get_total() === comp_2.get_total() || Math.abs(comp_1.get_total() - comp_2.get_total()) < 6) {
return 'Réplica';
}
const max_num = Math.max(comp_1.get_total(), comp_2.get_total());
return max_num === comp_1.get_total() ? comp_1.name : comp_2.name;
}
serialize() {
return JSON.stringify({
id: this._id,
comp_1: this.comp_1,
comp_2: this.comp_2,
});
}
static unserialize(data) {
const newData = JSON.parse(data);
return new VotingPoll(newData.id, newData.comp_1, newData.comp_2);
}
}
The problem is that, when calling poll.get_winner(), JS doesn't know that comp_1 and comp_2 are of type Competitor, and that they do have the function get_total(). Consequently, I get an error that says:
Uncaught (in promise) TypeError: comp_1.get_total is not a function
at VotingPoll.get_winner (classes.ts:111)
at fillTable (end.ts:35)
at HTMLInputElement.<anonymous> (add_listeners.ts:25)
If anyones have any idea on how to do this, or if you have another approach, please help me. Thanks!

Javascript Test file returning undefined values

I have to make a Javascript version of the LET language and im making a test file. But each time i call a function its coming back undefined. There's an AST file, an interpreter file and finally my test file. There's also an Environment file but my test file for that works just fine.
Can any of you guys help me out and tell me why its returning undefined?
This is the test file for the AST.js/Interp.js files
var main = function(){
//console.log(valueOf(AST.DiffExp(5,3)))
var env1=Env.Env(null,null,null)
var env1=Env.extendEnv(env1, "x", 250);
console.log(AST.ConstExp(8))
}
//var modules = require('./modules.js');
var ConstExp = require('./Interp.js', './AST.js');
var AST=require('./AST.js', './Interp.js')
var valueOf=require('./Interp.js')
var Env= require("./Environment.js")
if(require.main === module) {
main();
}
This is the AST.js file
function ConstExp(i) {
this.Int = i;
}
function VarExp(id) {
this.Id = id;
}
function IsZeroExp (exp) {
this.Exp = exp;
}
function DiffExp (exp1, exp2) {
this.Exp1 = exp1;
this.Exp2 = exp2;
}
function IfExp (cond, cons, alt) {
this.Exp1 = cond; //Condition
this.Exp2 = cons; //Consequent
this.Exp3 = alt; //Alternative
}
//id is a strng not an expression
function LetExp (id, val, inExp) {
this.Id = id;
this.Exp1 = val
this.Exp2 = inExp
}
module.exports = {
ConstExp : ConstExp,
VarExp : VarExp,
IsZeroExp : IsZeroExp,
DiffExp : DiffExp,
IfExp : IfExp,
LetExp : LetExp
}
this is the Interpreter file (Interp.js)
function valueOf (e, p) {
switch(e.constructor){
case AST.ConstExp:
return Number(e.Int);
break;
case AST.VarExp:
return ENV.applyEnv(p, e.Id);
break;
case AST.IsZeroExp:
return valueOf(e.Exp, p) == 0;
break;
case AST.DiffExp:
return valueOf(e.Exp1, p) - valueOf(e.Exp2, p);
break;
case AST.LetExp:
var body = e.Exp2;
var v = valueOf(e.Exp1, p);
var pp = ENV.extendEnv(p, e.Id, v);
return valueOf(body, pp);
break;
case AST.IfExp:
if (valueOf(e.Exp1, p) == true){
return valueOf(e.Exp2, p);
} else {
return valueOf(e.Exp3, p);
}
break;
}
}
module.exports = {
valueOf: valueOf
}
AST = require("./AST.js");
ENV = require("./Environment.js");

Code flow through callback in java script

-----------------File1.html-------------------------
<body>
<div id="tooltip"></div>
<script src="lib/d3.js"></script>
<script src="lib/underscore.js"></script>
<script src="js/mapper.js"></script>
<script>
d3.json('data/readme.json', function (error, data) {
var mpr = chordMpr(data);
_.each(data, function (elem) {
mpr.addToMap(name(elem.name))
})
mpr.setFilter(function (row, a, b) {
/* alert(JSON.stringify(a) +"-------"+JSON.stringify(row)+"-------"+JSON.stringify(b));
alert(a.name + "--" + row.name + "--" + b.name); */
return (name(row.name) === a.name)
})
.setAccessor(function (recs, a, b) {
if (!recs[0]) return 0;
var n = 0;
_.each(recs, function (r) {
//alert(r.imports)
_.each(r.imports, function (i) {
// alert(JSON.stringify(b) + "----" + i);
if (name(i) === b.name) n++;
});
});
return n;
});
alert(/* "*****" + mpr.getMatrix() + "-----" + */ JSON.stringify(mpr.getMap()));
drawChords(mpr.getMatrix(), mpr.getMap());
});
function name(name) {
return name.substring(0, name.lastIndexOf(".")).substring(6);
}
---------------------------File1.html-----------------------------
------------------------------mapper.js---------------------------
//*******************************************************************
// CHORD MAPPER
//*******************************************************************
function chordMpr (data) {
alert(data + "kimi is faster than you");
var mpr = {}, mmap = {}, n = 0,
matrix = [], filter, accessor;
mpr.setFilter = function (fun) {
alert("inside filter");
filter = fun;
return this;
},
mpr.setAccessor = function (fun) {
accessor = fun;
return this;
},
mpr.getMatrix = function () {
matrix = [];
_.each(mmap, function (a) {
if (!matrix[a.id]) matrix[a.id] = [];
_.each(mmap, function (b) {
var recs = _.filter(data, function (row) {
return filter(row, a, b);
})
matrix[a.id][b.id] = accessor(recs, a, b);
});
});
return matrix;
},
mpr.getMap = function () {
return mmap;
},
mpr.printMatrix = function () {
_.each(matrix, function (elem) {
console.log(elem);
})
},
mpr.addToMap = function (value, info) {
if (!mmap[value]) {
mmap[value] = { name: value, id: n++, data: info }
}
},
mpr.addValuesToMap = function (varName, info) {
alert("inside addValuesToMap " + varName + info);
var values = _.uniq(_.pluck(data, varName));
alert(values);
//values is the list of countries in the importer[i] column in CSV form
_.map(values, function (v) {
//v is individual country in the importer[i] column
if (!mmap[v]) {
mmap[v] = { name: v, id: n++, data: info }
}
});
return this;
}
return mpr;
}
//*******************************************************************
// CHORD READER
//*******************************************************************
function chordRdr (matrix, mmap) {
return function (d) {
var i,j,s,t,g,m = {};
if (d.source) {
i = d.source.index; j = d.target.index;
s = _.where(mmap, {id: i });
t = _.where(mmap, {id: j });
m.sname = s[0].name;
m.sdata = d.source.value;
m.svalue = +d.source.value;
m.stotal = _.reduce(matrix[i], function (k, n) { return k + n }, 0);
m.tname = t[0].name;
m.tdata = d.target.value;
m.tvalue = +d.target.value;
m.ttotal = _.reduce(matrix[j], function (k, n) { return k + n }, 0);
} else {
g = _.where(mmap, {id: d.index });
m.gname = g[0].name;
m.gdata = g[0].data;
m.gvalue = d.value;
}
m.mtotal = _.reduce(matrix, function (m1, n1) {
return m1 + _.reduce(n1, function (m2, n2) { return m2 + n2}, 0);
}, 0);
return m;
}
}
I am having difficulty in analysing the code flow in the above code.
In the mpr.setFilter(function (row, a, b)) call, what are row, a and b? I can't find any variables by this name. Also how are the calls translating from one function to other.
Please help.
setFilter is a function which takes an argument of a function that is stored to a "member" variable filter. When the user calls setFilter and passes their function they must know the contract that it takes three arguments. These are your row, a, and b arguments, they aren't assigned here, just there to make the function match later on.
If you trace this a little further that anonymous function passed into setFilter and stored in the variable filter is then called in the getMatrix function in mapper.js. You'll see when it is called the arguments of row, a and b are passed in.
Ain't JavaScript fun?

Type signature for a TypeScript HOF

The following JavaScript function adds a before and after advice for a given function. I am trying to add TypeScript type signature for this function.
function wrap(fn, before, after) {
var id = function(x) { return x };
before = before || id;
after = after || id;
return function() {
var args = Array.prototype.slice.call(arguments);
var modifiedArgs;
try {
modifiedArgs = before.apply(this, args);
} catch (e) {
console.log(e);
}
var result = undefined;
try {
result = fn.apply(this, modifiedArgs || args);
} finally {
try {
after.apply(this, args);
} catch (e) {
console.log(e);
}
}
return result;
}
}
The types I could come up with are:
fn is of type Function
after is of type (_:any[]) => any[]
return type is Function
What should the type of before be? It takes an any[] and returns either void or any[]. Also, is it possible to encode the fact that the return type has the same type signature as fn?
before could be (_:any[]) => any[]
If you want to encode the return type in your function signature just do something like this:
function wrap(fn, before, after) : Function { ...function... }
I ended up writing this as:
module Foo {
export interface Wrappable extends Function {
(...rest) : any;
}
export function wrap<U extends Wrappable>(fn: U,
before: (...args) => any[],
after: (...args) => void): U {
var id = function(x) { return x };
before = before || id;
after = after || id;
return <U> function() {
var args = Array.prototype.slice.call(arguments);
var modifiedArgs;
try {
modifiedArgs = before.apply(this, args);
} catch (e) {
console.log(e);
}
var result = undefined;
try {
result = fn.apply(this, modifiedArgs || args);
} finally {
try {
after.apply(this, args);
} catch (e) {
console.log(e);
}
}
return result;
}
}
}
var orig = function(s: string): void {
console.log("Hello!");
};
var before = function (s: string): any[] {
console.log("before calling orig(" + s + ")");
return [s];
};
var after = function (s: string): void {
console.log("after calling orig(" + s + ")");
};
var f = Foo.wrap(orig, before, after);
f("1");
// f(); // ERROR
// f(1); // ERROR
// f("1", "1"); // ERROR
Notice that the return value of Foo.wrap is the a function of the same type as the first argument, which was impressive feat by the TS type inference!

JS: How to return 'undefined' instead of throwing error 'cannot read property x of undefined'

What is the best way to have js return undefined rather than throw an error when a parent property does not exist?
Example
a = {}
b = a.x.y.z
// Error: Cannot read property 'value' of undefined
// Target result: b = undefined
You have to check for the existence of each property:
var b;
if (a.x && a.x.y && a.x.y.z) {
b = a.x.y.z
}
Or, simliar to another poster's "safeGet" function:
var get = function (obj, ns) {
var y = ns.split('.');
for(var i = 0; i < y.length; i += 1) {
if (obj[y[i]]) {
obj = obj[y[i]];
} else {
return;
}
}
return obj;
};
Use:
var b = get(a, 'x.y.z');
try {
a = {}
b = a.x.y.z
}
catch (e) {
b = void 0;
}
I would go for slightly verbose:
var b = ((a.x || {}).y || {}).z
you could write a safeGet helper function, something like:
edited for drilldown as suggested in comments by arcyqwerty
var getter = function (collection, key) {
if (collection.hasOwnProperty(key)) {
return collection[key];
} else {
return undefined;
}
};
var drillDown = function (keys, currentIndex, collection) {
var max = keys.length - 1;
var key = keys[currentIndex];
if (typeof collection === 'undefined') {
return undefined;
}
if (currentIndex === max) {
return getter(collection, key);
} else {
return drillDown(keys, currentIndex + 1,
getter(collection, key));
}
};
var safeGet = function (collection, key) {
if (key.indexOf(".") !== -1) {
return drillDown(key.split("."), 0, collection);
} else {
return getter(collection, key);
}
};
a = { x: 1 };
b = safeGet(a, 'x.y.z');
http://jsfiddle.net/YqdWH/2/

Categories