How can I get this code to work. I want to intercept all missing method calls on my function, and redirect them to a "catch all" kind of method on said function.
var foo=function(){
this.bar=function(){
return "found!";
}
this.not_found=function(){
return "method not found.";
}
}
var p = new Proxy(foo, {
get: function (target, prop) {
if (Object.keys(target).indexOf(prop) !== -1) {
// should call existing method.
//return target[prop]; <-- does not work.
}else{
// here i want to call "not_found() on foo() if prop doesnt exist
}
}
});
console.log(p.bar()); // should print out: found!;
console.log(p.foo()); // should print out: method not found;
thanks in advance!
foo is a function. As deepak said, if you create an object from it, it will work:
var Foo = function () {
this.bar = function () {
return "found!";
}
this.notFound = function () {
return "method not found.";
}
};
var p = new Proxy(new Foo, {
get: function (target, prop) {
if (Object.keys(target).indexOf(prop) !== -1) {
return target[prop];
} else {
return target['notFound'];
}
}
});
console.log(p.bar()); // prints: found!;
console.log(p.foo()); // prints: method not found;
Since Foo is acting like a constructor, I wrote it with a capital letter. Also, the convention is to use camel case for names. Took the liberty to change these.
A slightly cleaner version (using in):
var Foo = function () {
this.bar = function () {
return "found!";
}
this.notFound = function () {
return "method not found.";
}
};
var foo = new Foo();
var p = new Proxy(foo, {
get: function (target, prop) {
if (prop in target) {
return target[prop];
} else {
return target['notFound'];
}
}
});
console.log(p.bar()); // prints: found!;
console.log(p.foo()); // prints: method not found;
Related
In the below code, How do I get access to the name of the function attempted to be called, and any params, in the catching function, in this example how can p.foo() (which is handled by the notFound function) print out the 'one','two','three' params as well.
the amount of parameters should not be hardcoded as in this example 3.
I have tried replacing:
return target['notFound'];
with a bunch of combinations of () and [] and passing 'arguments' and even 'prop', no luck.
also tried using .apply() still didnt get it to work.
var Foo = function () {
this.bar = function () {
return "found!";
}
this.notFound = function () {
return "method not found.";
}
};
var p = new Proxy(new Foo, {
get: function (target, prop) {
if (Object.keys(target).indexOf(prop) !== -1) {
return target[prop];
} else {
return target['notFound'];
}
}
});
console.log(p.bar()); // prints: found!;
console.log(p.foo("one","two","three")); // prints: method not found;
thanks in advance!
I think you're looking for
class Foo {
bar() {
return "found!";
}
notFound(name, args) {
return `method '${name}' not found, was called with [${args.join(', ')}].`;
}
}
var p = new Proxy(new Foo, {
get: function (target, prop) {
if (prop in target) {
return target[prop];
} else {
return function(...args) { return target.notFound(prop, args); };
}
}
});
console.log(p.bar()); // prints: found!;
console.log(p.foo("one","two","three")); // prints: method 'foo' not found, was called with [one, two, three]
I want to check that my object properties and method or anything else is called or not? for example,
// functions
function app(){
return {
name : 'Md Tahazzot',
info : function(){
return this.name;
}
};
}
Now if I call this like app(), I mean In this case I am not called any of the object properties or methods. So, Is it possible to check this that I am called only the function nothing else like this app().name ?
You could return a Proxy. If the proxy's getters (or setters?) are ever called, then you know that something has been done other than simply call the function - something attempted to get or set a property on the returned object:
function app() {
const target = {
name: 'Md Tahazzot',
info: function() {
return this.name;
}
};
return new Proxy(target, {
get(target, prop) {
console.log('Get attempted');
return target[prop];
},
set(target, prop, newVal) {
console.log('Set attempted');
return target[prop] = newVal;
}
});
}
console.log('Creating "a":');
const a = app();
console.log('Creating "b":');
const b = app();
b.name;
console.log('Creating "c":');
const c = app();
c.foo = 'foo';
console.log(c.foo);
If you have to do this from outside the app, then apply the same logic after the object has been returned:
function app() {
return {
name: 'Md Tahazzot',
info: function() {
return this.name;
}
};
}
const obj = new Proxy(app, {
get(target, prop) {
console.log('Get attempted');
return target[prop];
},
set(target, prop, newVal) {
console.log('Set attempted');
return target[prop] = newVal;
}
});
console.log('Proxy created');
obj.name;
As functions are nothing but objects in JavaScript, you can create property on function itself to store any info at function level.
You could do something like this:
function app(){
app.callsCount = app.callsCount || 0;
app.callsCount++;
return {
name : 'Md Tahazzot',
info : function(){
return this.name;
}
};
}
And can be used like this:
app().name
app.callsCount // 1
app()
app.callsCount //2
Keep in mind, once function is called, the count is increased, if you want to increase count on inner function call you could do that too. However it would not be straight forward to know if a property is called after app function call.
Not exactly sure what exactly you are trying to achieve.
I'm using functions as representations of classes.
function ClassOne()
{
this.doFunc = function() {
console.log("doFunc output");
}
}
function ClassTwo()
{
this.one = ClassOne();
console.log(this.one); // == undefined ???
this.init = function() {
this.one.doFunc();
}
this,init();
}
ClassTwo();
But I'm struggling to use one function inside another.
For example, the above code returns "Cannot read property 'doFunc' of undefined"
Why is this.one == undefined?
If you assign to a property of this inside a function, generally that indicates that the function is intended to be called as a constructor with new, eg:
this.one = new ClassOne();
Otherwise, if the function doesn't return anything... then, well, nothing gets returned (=> undefined)
function ClassOne()
{
this.doFunc = function() {
console.log("doFunc output");
}
}
function ClassTwo()
{
this.one = new ClassOne();
console.log(this.one);
this.init = function() {
this.one.doFunc();
}
this.init();
}
ClassTwo();
Or, you can have ClassOne explicitly return an object with a doFunc property, allowing it to be called without new:
function ClassOne()
{
return {
doFunc() {
console.log("doFunc output");
}
}
}
function ClassOne() {
return {
doFunc() {
console.log("doFunc output");
}
}
}
function ClassTwo() {
this.one = ClassOne();
console.log(this.one);
this.init = function() {
this.one.doFunc();
}
this.init();
}
ClassTwo();
I am trying to create my object through a function, but I am unable to figure out the syntax for the getter function.
var myObject =
{
0:123,
get a()
{
return this[0];
}
}
console.log("This works: " + myObject.a);
function test()
{
this[0] = 123;
// error
this.a = get function()
{
return this[0];
};
}
var myTest = new test();
console.log(myTest.a);
Within the test function, the assignment of the get function throws a missing semicolon error and if I remove the keyword "function", it says that get is not defined.
How can I assign a getter function to the current object within my function?
You could try something like this:
var myObject =
{
0:123,
get a()
{
return this[0];
}
}
console.log("This works: " + myObject.a);
function test()
{
this[0] = 123;
Object.defineProperties(this, {"a": { get: function () {
return this[0];
}}});
}
var myTest = new test();
console.log(myTest.a);
Maybe this will work for you :
function test()
{
this[0] = 123;
Object.defineProperty(this, "a", { get: function () { return this[0]; } });
}
Is there a way to make any function output a console.log statement when it's called by registering a global hook somewhere (that is, without modifying the actual function itself) or via some other means?
Here's a way to augment all functions in the global namespace with the function of your choice:
function augment(withFn) {
var name, fn;
for (name in window) {
fn = window[name];
if (typeof fn === 'function') {
window[name] = (function(name, fn) {
var args = arguments;
return function() {
withFn.apply(this, args);
return fn.apply(this, arguments);
}
})(name, fn);
}
}
}
augment(function(name, fn) {
console.log("calling " + name);
});
One down side is that no functions created after calling augment will have the additional behavior.
As to me, this looks like the most elegant solution:
(function() {
var call = Function.prototype.call;
Function.prototype.call = function() {
console.log(this, arguments); // Here you can do whatever actions you want
return call.apply(this, arguments);
};
}());
Proxy Method to log Function calls
There is a new way using Proxy to achieve this functionality in JS.
assume that we want to have a console.log whenever a function of a specific class is called:
class TestClass {
a() {
this.aa = 1;
}
b() {
this.bb = 1;
}
}
const foo = new TestClass()
foo.a() // nothing get logged
we can replace our class instantiation with a Proxy that overrides each property of this class. so:
class TestClass {
a() {
this.aa = 1;
}
b() {
this.bb = 1;
}
}
const logger = className => {
return new Proxy(new className(), {
get: function(target, name, receiver) {
if (!target.hasOwnProperty(name)) {
if (typeof target[name] === "function") {
console.log(
"Calling Method : ",
name,
"|| on : ",
target.constructor.name
);
}
return new Proxy(target[name], this);
}
return Reflect.get(target, name, receiver);
}
});
};
const instance = logger(TestClass)
instance.a() // output: "Calling Method : a || on : TestClass"
check that this actually works in Codepen
Remember that using Proxy gives you a lot more functionality than to just logging console names.
Also this method works in Node.js too.
If you want more targeted logging, the following code will log function calls for a particular object. You can even modify Object prototypes so that all new instances get logging too. I used Object.getOwnPropertyNames instead of for...in, so it works with ECMAScript 6 classes, which don't have enumerable methods.
function inject(obj, beforeFn) {
for (let propName of Object.getOwnPropertyNames(obj)) {
let prop = obj[propName];
if (Object.prototype.toString.call(prop) === '[object Function]') {
obj[propName] = (function(fnName) {
return function() {
beforeFn.call(this, fnName, arguments);
return prop.apply(this, arguments);
}
})(propName);
}
}
}
function logFnCall(name, args) {
let s = name + '(';
for (let i = 0; i < args.length; i++) {
if (i > 0)
s += ', ';
s += String(args[i]);
}
s += ')';
console.log(s);
}
inject(Foo.prototype, logFnCall);
Here's some Javascript which replaces adds console.log to every function in Javascript; Play with it on Regex101:
$re = "/function (.+)\\(.*\\)\\s*\\{/m";
$str = "function example(){}";
$subst = "$& console.log(\"$1()\");";
$result = preg_replace($re, $subst, $str);
It's a 'quick and dirty hack' but I find it useful for debugging. If you have a lot of functions, beware because this will add a lot of code. Also, the RegEx is simple and might not work for more complex function names/declaration.
You can actually attach your own function to console.log for everything that loads.
console.log = function(msg) {
// Add whatever you want here
alert(msg);
}