Create a Logger for an object in Javascript - javascript

I want to write a logger that takes one object argument (build-in or user-defined) and returns new object which acts as argument and has the same methods, and also each method call is logged in browser console.
For example:
var a = [];
var b = myLogger(a);
b.push("foo");
< array.push("foo") -> 1;
b.push("bar");
< array.push("bar") -> 2;
As far as I understand I need to create a decorator to solve this. Is this right way to solve this task? Any other suggestions are also appreciated.

function myLogger (target) {
var handler = {
get(target, name){
var result = name in target? target[name] : undefined;
console.log(`< ${JSON.stringify(target)}.${name} -> ${result}`);
return result;
}
};
return new Proxy(target, handler);
}
var a = { x: 1};
var a_Proxy = myLogger(a);
a_Proxy.x; // logs < {"x":1}.x -> 1
use can use ES6 "Proxy" standard built-in object.
https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Proxy

Related

How to trigger a anynomous function with parameters Javascript

Today I was at job interview - and I had been presented with a task.
I have never encoutered such a function, so there it is:
Write down a function which after triggering like this:
console.log('hello'.repeatify(3))
returns
hellohellohello
I was trying to create an empty object and append a method repeatify, however i just don't know how to trigger it just with 'hello'.
Maybe i should change console.log method?
Thanks for the help :)
Wasn't that really hard. You have to make a new function for String.prototype and use repeat() function to multiply given string by given argument.
String.prototype.repeatify = function(count){
return this.repeat(count);
};
console.log('hello'.repeatify(3))
You can create your own prototype methods for every object, but you shouldn't do it with native objects:
String.prototype.repeatify = function(num) {
return this.repeat(num);
}
console.log('hello'.repeatify(3));
read more about this bad practice here
String.prototype.repeatify = function(amount)
{
var endString = "";
for(var i = 0; i < amount; ++i)
{
endString += this;
}
return endString;
}
Just modify String's prototype object:
String.prototype.repeatify = function (A) {
var i = 1;
var a = this;
while (i++ < A) {
a += this;
}
return a;
}
console.log('hello'.repeatify(3));
// outputs hellohellohello
There are mixed feelings on modifying the prototype of built in objects. I have both that it is just fine and that it is a bad practice. Personally I try to avoid it and prefer defining a standalone function to modifying the prototype of something I didn't create.
ES6 version
repeatify
String.prototype.repeatify = String.prototype.repeatify || function (times = 1) {
// ES5 this
return [...``.padStart(times, ` `)].map((item, i) => item = this).join(``);
};
`abx`.repeatify(3);
// "abxabxabx"

Implementing Ruby Refinements in Javascript

Ruby's refinements allow you to temporarily "upgrade" an object within a lexical scope. I'm trying to implement a similar idea in javascript. Here's some working code that does almost what I want:
function dateExtension() {
return {
day: function() { return this.getDate() }
}
}
function refine(ctor, mixin) {
return function() {
var ret = new (Function.prototype.bind.apply(ctor, arguments));
return Object.assign(ret, mixin);
}
}
function test() {
// Cant overwrite native Date function,
// so have to rename it.
var XDate = refine(Date, dateExtension());
var d = new XDate();
console.log(d.day()); // prints the day of the month to console
}
test();
What I really want to do is this:
function test() {
var Date = refine(Date, dateExtension());
var d = new Date();
console.log(d.day()); // Uncaught TypeError: Bind must be called on a function
}
The idea would be to make the local var Date overide the built in Date, within the body of test() only. So that, within test(), it would acquire the new method day(), but outside of test() Date would be unaffected. This apparently is not allowed.
Is there some workaround to make this idea work?
I made a tiny library called chill-patch to do exactly that. It enables you to use functions as methods, and to safely patch prototypes.
Here's an example of how to use it:
const chillPatch = require('chill-patch')
const lastFunc = arr => arr[arr.length - 1]
const array = [1, 2, 3]
// safely add a method to `Array`
const last = chillPatch(Array, lastFunc, 'last')
// call the new method!
array[last]() //=> 3
If you want to roll your own, the entire source code is as follows:
'use strict'
const chillPatch = (klass, func, optionalDescription) => {
const symbol = Symbol(optionalDescription)
klass.prototype[symbol] = function(){
const args = Array.prototype.slice.call(arguments)
args.unshift(this)
return func.apply(null, args)
}
return symbol
};
module.exports = chillPatch
I see you said in a comment that you do not want to modify prototypes, but your reason is probably that modifying prototypes is dangerous. However, the method above patches using Symbol, which is completely safe. The change will be invisible to other parts of the codebase unless someone is doing reflection with Object.getOwnPropertySymbols()
So I came up with something that works, although it's fairly hacky.
Here's a fiddle: https://jsfiddle.net/40cty4qa/
And here's the code
function lg() { console.log.apply(console, arguments) }
function extend(o, mixin) {
for (var k in mixin) o.prototype[k] = mixin[k]
}
function unextend(o, mixin) {
for (var k in mixin) delete o.prototype[k];
}
Function.prototype.refine = function(ctor, mixin) {
var self = this;
return function() {
extend(ctor, mixin);
var ret = self.apply(this, arguments);
unextend(ctor, mixin);
return ret;
}
}
function dateExtension() {
return {
day: function() { return this.getDate() }
}
}
function refine(ctor, mixin) {
return function() {
var ret = new (Function.prototype.bind.apply(ctor, arguments));
return Object.assign(ret, mixin);
}
}
function test() {
var d = new Date();
lg(d.day());
}
test = test.refine(Date, dateExtension());
test(); // This works, since were inside a refinement
var d = new Date();
lg(d.day()); // This doesnt work, as desired.

Equivalent of Function.prototype.apply for an ES6 generator

I'm trying to build a chainable JavaScript API. (I’m running this in a recent version of V8 with iterators and generators enabled.) In the example below, setState is chainable. It also allows you to call it without having to explicitly create a new Builder instance. The chain() helper function handles that and automatically returns that instance so setState doesn't have to worry about it. (First-class functions for the win!)
In addition to the chainable methods I want some "terminating" methods. The kicker is that these "terminators" are generators. The generators yield internal state of a Builder instance. The problem is that I can’t figure out an equivalent to f.apply(that, arguments) for a generator. I want to be able to call a generator and set its this context at runtime, just like you're able to do with Function.prototype.apply and Function.prototype.call.
The work-around, commented with Yuck!, is to expose both the delegated and the original generator on the Builder.prototype, calling the original from the delegated. Is there any way to implement the equivalent wrapping like the chain method without having to expose the _generate method on the Builder.prototype?
function Builder() { this.initialState = 'initialState'; };
Builder.prototype.setState = chain(function(k, v) { this[k] = v; });
Builder.prototype.generate = delegate(generate, '_generate'); // Yuck!
Builder.prototype._generate = generate;
function chain(f) {
return function() {
var that = (this instanceof Builder) ? this : new Builder();
f.apply(that, arguments); // Pass through arguments
return that;
}
}
function delegate(gen, _gen) {
return function*() {
var that = (this instanceof Builder) ? this : new Builder();
that.setState('delegated', true);
yield *that[_gen](); // Yuck!
}
}
function *generate(opts) {
var i = 0;
for(var i = 0; i < 10; i++) {
yield [Object.keys(this), opts, i].join(',');
}
}
// Set up a namespace
var ns = {};
ns.setState = Builder.prototype.setState;
ns.generate = Builder.prototype.generate;
var itr = ns
// .setState('a', 'A')
// .setState('b', 'B')
// .setState('c', 'C')
.generate('options');
var out = [];
for(var value of itr) { out.push(value); }
out;
Which returns
[
"initialState,delegated,,0",
"initialState,delegated,,1",
"initialState,delegated,,2",
"initialState,delegated,,3",
"initialState,delegated,,4",
"initialState,delegated,,5",
"initialState,delegated,,6",
"initialState,delegated,,7",
"initialState,delegated,,8",
"initialState,delegated,,9"
]
The problem is that I can’t figure out an equivalent to f.apply(that, arguments) for a generator.
Judging from the ES6 draft, you don't need an equivalent - you can just use the expression as is. Generator functions (that construct generator instances) are functions, and they inherit (via Generator.prototype) from Function.prototype; you can use .call and .apply on them as on any other function.
So the following should work:
function delegate(gen) {
return function() {
var that = (this instanceof Builder) ? this : new Builder();
that.setState('delegated', true);
return gen.apply(that, arguments); // Pass through arguments
}
}
The key was yield *gen.apply(that, arguments) in the anonymous generator wrapper.
function Builder() { this.initialState = 'initialState'; };
Builder.prototype.setState = chain(function(k, v) { this[k] = v; });
Builder.prototype.generate = delegate(generate);
// Reuses or creates a Builder instance and makes it `this` for calling `f`.
// Returns the Builder instance.
function chain(f) {
return function() {
var that = (this instanceof Builder) ? this : new Builder();
f.apply(that, arguments); // Pass through arguments
return that;
}
}
// Similar to `chain()` to create a Builder instance if it doesn't exist.
// Generators are terminal, though, so this returns the FunctionGenerator.
function delegate(gen) {
return function*() {
var that = (this instanceof Builder) ? this : new Builder();
that.setState('delegated', true);
yield *gen.apply(that, arguments);
}
}
function *generate(opts) {
var i = 0;
for(var i = 0; i < 10; i++) {
yield [Object.keys(this), opts, i].join(',');
}
}
// Set up a namespace
var ns = {};
ns.setState = Builder.prototype.setState;
ns.generate = Builder.prototype.generate;
var itr = ns
// .setState('a', 'A')
// .setState('b', 'B')
// .setState('c', 'C')
.generate('options');
var out = [];
for(var value of itr) { out.push(value); }
out;

How can I count the instances of an object?

If i have a Javascript object defined as:
function MyObj(){};
MyObj.prototype.showAlert = function(){
alert("This is an alert");
return;
};
Now a user can call it as:
var a = new MyObj();
a.showAlert();
So far so good, and one can also in the same code run another instance of this:
var b = new MyObj();
b.showAlert();
Now I want to know, how can I hold the number of instances MyObj?
is there some built-in function?
One way i have in my mind is to increment a global variable when MyObj is initialized and that will be the only way to keep track of this counter, but is there anything better than this idea?
EDIT:
Have a look at this as suggestion here:
I mean how can I make it get back to 2 instead of 3
There is nothing built-in; however, you could have your constructor function keep a count of how many times it has been called. Unfortunately, the JavaScript language provides no way to tell when an object has gone out of scope or has been garbage collected, so your counter will only go up, never down.
For example:
function MyObj() {
MyObj.numInstances = (MyObj.numInstances || 0) + 1;
}
new MyObj();
new MyObj();
MyObj.numInstances; // => 2
Of course, if you want to prevent tampering of the count then you should hide the counter via a closure and provide an accessor function to read it.
[Edit]
Per your updated question - there is no way to keep track of when instances are no longer used or "deleted" (for example by assigning null to a variable) because JavaScript provides no finalizer methods for objects.
The best you could do is create a "dispose" method which objects will call when they are no longer active (e.g. by a reference counting scheme) but this requires cooperation of the programmer - the language provides no assistance:
function MyObj() {
MyObj.numInstances = (MyObj.numInstances || 0) + 1;
}
MyObj.prototype.dispose = function() {
return MyObj.numInstances -= 1;
};
MyObj.numInstances; // => 0
var a = new MyObj();
MyObj.numInstances; // => 1
var b = new MyObj();
MyObj.numInstances; // => 2
a.dispose(); // 1 OK: lower the count.
a = null;
MyObj.numInstances; // => 1
b = null; // ERR: didn't call "dispose"!
MyObj.numInstances; // => 1
Create a static property on the MyObj constructor called say count and increment it within the constructor itself.
function MyObj() {
MyObj.count++;
}
MyObj.count = 0;
var a = new MyObj;
var b = new MyObj;
alert(MyObj.count);
This is the way you would normally do it in say Java (using a static property).
var User = (function() {
var id = 0;
return function User(name) {
this.name = name;
this.id = ++id;
}
})();
User.prototype.getName = function() {
return this.name;
}
var a = new User('Ignacio');
var b = new User('foo bar');
a
User {name: "Ignacio", id: 1}
b
User {name: "foo bar", id: 2}
Using ES6 Classes MDN syntax - we can define a static method:
The static keyword defines a static method for a class. Static methods are called without instantiating their class and cannot be called through a class instance. Static methods are often used to create utility functions for an application.
class Item {
static currentId = 0;
_id = ++Item.currentId; // Set Instance's this._id to incremented class's ID
// PS: The above line is same as:
// constructor () { this._id = ++Item.currentId; }
get id() {
return this._id; // Getter for the instance's this._id
}
}
const A = new Item(); // Create instance (Item.currentId is now 1)
const B = new Item(); // Create instance (Item.currentId is now 2)
const C = new Item(); // Create instance (Item.currentId is now 3)
console.log(A.id, B.id, C.id); // 1 2 3
console.log(`Currently at: ${ Item.currentId }`); // Currently at: 3
PS: if you don't want to log-expose the internal currentId property, make it private:
static #currentId = 0;
_id = ++Item.#currentId;
Here's an example with constructor and without the getter:
class Item {
static id = 0;
constructor () {
this.id = ++Item.id;
}
getID() {
console.log(this.id);
}
}
const A = new Item(); // Create instance (Item.id is now 1)
const B = new Item(); // Create instance (Item.id is now 2)
const C = new Item(); // Create instance (Item.id is now 3)
A.getID(); B.getID(); C.getID(); // 1; 2; 3
console.log(`Currently at: ${ Item.id }`); // Currently at: 3
what about such method?
var Greeter = (function ()
{
var numInstances;
function Greeter(message)
{
numInstances = (numInstances || 0) + 1;
this.greeting = message;
}
Greeter.prototype.greet = function ()
{
return "Hello, " + this.greeting;
};
Greeter.prototype.getCounter = function ()
{
return numInstances;
};
return Greeter;
})();
var greeter = new Greeter("world");
greeter.greet();
greeter.getCounter();
var newgreeter = new Greeter("new world");
newgreeter.greet();
newgreeter.getCounter();
greeter.getCounter();
Keeping a global count variable and incrementing every time is an option. Another option is to call counter method after each instance creation by hand (the worst thing I could imagine). But there is another better solution.
Every time we create an instance, the constructor function is being called. The problem is the constructor function is being created for each instance, but we can have a count property inside __proto__ which can be the same for each instance.
function MyObj(){
MyObj.prototype.addCount();
};
MyObj.prototype.count = 0;
MyObj.prototype.addCount = function() {
this.count++;
};
var a = new MyObj();
var b = new MyObj();
This is our a and b variables after all:
Eventually, JS is going to have built-in proxy capability, which will have low-level access to all kinds of things which happen in the background, which will never be exposed to front-end developers (except through the proxy -- think magic-methods in languages like PHP).
At that time, writing a destructor method on your object, which decrements the counter might be entirely trivial, as long as support for destruction/garbage-collection as a trigger is 100% guaranteed across platforms.
The only way to currently, reliably do it might be something like creating an enclosed registry of all created instances, and then manually destructing them (otherwise, they will NEVER be garbage-collected).
var Obj = (function () {
var stack = [],
removeFromStack = function (obj) {
stack.forEach(function (o, i, arr) {
if (obj === o) { arr.splice(i, 1); }
makeObj.count -= 1;
});
};
function makeObj (name) {
this.sayName = function () { console.log("My name is " + this.name); }
this.name = name;
this.explode = function () { removeFromStack(this); };
stack.push(this);
makeObj.count += 1;
}
makeObj.checkInstances = function () { return stack.length; };
makeObj.count = 0;
return makeObj;
}());
// usage:
var a = new Obj("Dave"),
b = new Obj("Bob"),
c = new Obj("Doug");
Obj.count; // 3
// "Dave? Dave's not here, man..."
a.explode();
Obj.count; // 2
a = null; // not 100% necessary, if you're never going to call 'a', ever again
// but you MUST call explode if you ever want it to leave the page's memory
// the horrors of memory-management, all over again
Will this pattern do what you want it to do?
As long as:
you don't turn a into something else
you don't overwrite its explode method
you don't mess with Obj in any way
you don't expect any prototype method to have access to any of the internal variables
...then yes, this method will work just fine for having the counter work properly.
You could even write a general method called recycle, which calls the explode method of any object you pass it (as long as its constructor, or factory, supported such a thing).
function recycle (obj) {
var key;
obj.explode();
for (key in obj) { if (obj.hasOwnProperty(key)) { delete obj[key]; } }
if (obj.__proto__) { obj.__proto__ = null; }
}
Note - this won't actually get rid of the object.
You'll just have removed it from the closure, and removed all methods/properties it once had.
So now it's an empty husk, which you could reuse, expressly set to null after recycling its parts, or let it be collected and forget about it, knowing that you removed necessary references.
Was this useful?
Probably not.
The only time I really see this as being of use would be in a game where your character might only be allowed to fire 3 bullets at a time, and he can't shoot a 4th until the 1st one on screen hits someone or goes off the edge (this is how, say, Contra worked, in the day).
You could also just shift a "disappeared" bullet off the stack, and reuse that bullet for any player/enemy by resetting its trajectory, resetting appropriate flags, and pushing it back onto the stack.
But again, until proxies allow us to define "magic" constructor/destructor methods, which are honoured at a low-level, this is only useful if you're going to micromanage the creation and destruction of all of your own objects (really not a good idea).
My solution is creating an object store instance count and a function to increase them in prototype.
function Person() {
this.countInst();
}
Person.prototype = {
constructor: Person,
static: {
count: 0
},
countInst: function() {
this.static.count += 1;
}
};
var i;
for (i = 0; i < 10; i++) {
var p = new Person();
document.write('Instance count: ');
document.write(p.static.count);
document.write('<br />');
}
Here is my plunker: https://plnkr.co/edit/hPtIR2MQnV08L9o1oyY9?p=preview
class Patient{
constructor(name,age,id){
Object.assign(this,{name, age, id});
}
static patientList = []; // declare a static variable
static addPatient(obj){
this.patientList.push(...obj); // push to array
return this.patientList.length; // find the array length to get the number of objects
}
}
let p1 = new Patient('shreyas',20, 1);
let p2 = new Patient('jack',25, 2);
let p3 = new Patient('smith',22, 3);
let patientCount = Patient.addPatient([p1,p2,p3]); // call static method to update the count value with the newly created object
console.log(Patient.patientList);
console.log(patientCount);

Dynamically firing a named-spaced method via JavaScript

I have multiple external JavaScripts that are namespaced based on the section of the site. I am trying to dynamically fire methods, but am unable to get the methods to fire. Can anyone tell me what the problem is?
If I add this, the method fires:
Namespace.Something.init()
But when I try to do it like this, nothing happens (note: namespace equals Namespace.Something and functionname equals init):
namespace[functionname]();
Unless you want to use eval which I am sure you don't the following works.
This assumes that all your methods are the same level deep i.e namespace.somename.somemethod
var Namespace = {
Something: {
init: function() {
console.log('init called');
}
}
};
Namespace.Something.init();
var namespace = "Namespace";
var section = "Something";
var method = "init";
this[namespace][section][method]();
as Namespace is part of the global scope you can access it from this[namespace]
I asked the same question a few weeks ago, though I think I phrased it slightly differently. See this.
Basically, you need to parse the string functionname one piece at a time.
By the way, using the walk_path code from that answer, here's a general purpose function I wrote to run a function from a string including arguments.
// run an arbitrary function from a string. Will attempt to parse the args from parenthesis, if none found, will
// use additional arguments passed to this function.
utils.runFunction = function (funcdef) {
var argPos = funcdef.indexOf('(');
var endArgPos = -1;
var args = undefined;
var func = funcdef;
if (argPos > 0) {
endArgPos = funcdef.indexOf(')', argPos);
if (endArgPos > 0) {
args = funcdef.substring(argPos + 1, endArgPos).split(',');
func = funcdef.substring(0, argPos - 1);
}
} else {
args = Array.prototype.slice.call(arguments, 1);
}
var func = walk_path(window, func);
return !args ? func() : func.apply(null, args);
};
var methodName = 'Namespace.Something.init';
var methodParts = methodName.split('.');
var method = this;
for (var i=0; i < methodParts.length; i++) {
method = method[methodParts[i]];
};
method(the arguments you want);

Categories

Resources