How to detect that getX is called, to trigger another function?
Limitations: module can be modified only after its declaration, because this object is received from a script loaded from a remote website. The goal is to tiger
A. This script is loaded from another website (<script src="//remote.com/script.js">)
var module = {
x: 42,
getX: function() {
return this.x;
}
}
B. This script is on my website <script>...</script>
when_getX_isExecuted function() {
console.log('getX was executed');
}
Use Object.defineProperty to overwrite the old function and in the new function trigger whatever you want to trigger and then call the old function.
var module = {
x: 42,
getX: function() {
return this.x;
}
};
function listenToFunction(object, propertyName, callBack) {
var oldProperty = object[propertyName];
if (typeof oldProperty !== "function") throw Error(`object.${propertyName} is not a function`);
Object.defineProperty(object, propertyName, {
value: function() {
var params = [].slice.call(arguments);
var result = oldProperty.apply(object, params);
callBack(object, propertyName, params, result);
return result;
}
});
}
console.log(module.getX()); // will not trigger
listenToFunction(module, "getX", function(object, propertyName, params, result) {
console.log(`The function '${propertyName}' was called on the object ${JSON.stringify(object)}, with arguments ${JSON.stringify(params)}. The result was ${JSON.stringify(result)}`);
});
console.log(module.getX()); // will trigger
console.log(module.getX(1, 2, 3)); // will trigger
Simply override the function and add a call to your when_getX_isExecuted function. Here is an example. Hope it helps
function when_getX_isExecuted () {
console.log('getX was executed');
}
var module = {
x: 42,
getX: function () {
return this.x;
}
}
//override the function getX()
module.getX = function () {
when_getX_isExecuted ();
return this.x;
}
//test by calling getX()
var x = module.getX ();
console.log (x)
I think you could use prototype to pimp up code that's imported from third party.
Prototype
Related
There is a function in a javascript library I want to override for my own use case, I want to use most of the code from the function but add some extra functionality. In my console I can access the function by doing, somelibrary.CharCounter.prototype.count this function takes an argument of text.
I have tried the following,
somelibrary.CharCounter.prototype.count = (function(_super, text) {
return function(_super, apply) {
console.log("overwriting", text);
return _super.apply(this, arguments);
};
})(somelibrary.CharCounter.prototype.count)
On the above I get the the console.log as I would expect, but I also get this error,
Uncaught typeerror: _super.apply is not a function
Obvioulsy I am doing something wrong, all I want to do is ovveride the function so it returns something different to it's original method.
You have to pass _super to the outer function only and make the inner function accept the "super" arguments:
Array.prototype.slice = (function(_super) {
return function(x, y) {
console.log("overwriting", x, y);
return _super.apply(this, arguments);
};
})(Array.prototype.slice);
console.log([1,2,3,4,5,6].slice(1,3))
To avoid repetitions, you might want to define a generic function:
function override(obj, method, fn) {
let prev = obj[method]
obj[method] = function (...args) {
return fn.call(
this,
prev.bind(this),
...args,
)
}
}
override(Array.prototype, 'slice', function (_super, x, y) {
console.log("overwriting", x, y);
return _super(x, y + 1)
})
console.log([1,2,3,4,5,6].slice(1,3))
You can use a Proxy for this. Here is a demo on proxying Math.sin:
Math.sin = new Proxy(Math.sin, {
apply: function(original, thisArg, args) {
console.log(`Executing ${original.name}(${args.join()})`);
return original.apply(thisArg, args);
}
});
console.log(Math.sin(2));
Maybe slightly more readable solution:
somelibrary.CharCounter.prototype.foo = (function () {
var _super = somelibrary.CharCounter.prototype.foo;
return function (text) {
console.log("overwriting", text);
return _super.apply(this, arguments);
}
})();
It is also possible to define generic extendFunction() function for overriding functions:
function extendFunction(superFunc, overridingFunc) {
return function () {
overridingFunc.call(this, superFunc, arguments);
}
}
somelibrary.CharCounter.prototype.foo = extendFunction(
somelibrary.CharCounter.prototype.foo,
function (superFunc, args) {
console.log("overwriting", args);
return superFunc.apply(this, args);
}
);
Let's say I have a function made up of private and public methods, like this:
(function () {
var private_var = "hey";
function private_function () {
// stuff
}
stuff = {
public_var: "hey",
public_function: function () {
// this can be called from the outside with no prob.
},
do_this_now_and_later: (function dothis() {
// i could call this from the namespace "dothis()"
// but not the method name, stuff.do_this_now_and_later()
})()
}
})(window.load = window.load || {});
i want to execute the function do_this_now_and_later() as soon as it's rendered, but again later as well.
if i wrote this example code correctly, one should be able to call that function by the namespace dothis(), but is it possible to call that function by its method?
Try to return dothis() in your function.
(function () {
var private_var = "hey";
function private_function () {
// stuff
}
stuff = {
public_var: "hey",
public_function: function () {
// this can be called from the outside with no prob.
},
do_this_now_and_later: (function dothis(v) {
alert(v);
return dothis;
// i could call this from the namespace "dothis()"
// but not the method name, stuff.do_this_now_and_later()
})('foo')
}
stuff.do_this_now_and_later('bar');
})(window.load = window.load || {});
I spent the better part of the day reading about the module pattern and its 'this' scope. Eventually I found a work-around for my problem, although with a feeling there's a better way of doing things.
The actual code is >200 lines, but I've boiled it down to the following:
objA has a method (publicA) that objB wants invoke by callback. The detail that complicates things is that publicA needs help from publicA_helper to do its job. (http://jsfiddle.net/qwNb6/2/)
var objA = function () {
var privateA = "found";
return {
publicA: function () {
console.log("privateA is " + this.publicA_helper());
},
publicA_helper: function () {
return privateA;
}
};
}();
var objB = function () {
return {
callback: function (callback) {
callback();
}
}
}();
objA.publicA(); // privateA is found
objB.callback(objA.publicA); // TypeError: Object [object global]
Fair enough – I've grasped that the caller's context tends to influence the value of 'this'. So I add measures to retain 'this' inside objA, of which none seems to work. I've tried the
var objA = (){}.call({}) thingy, setting var self = this; (calling self.publicA_helper() accordingly). No luck.
Eventually, I added a private variable var self;, along with a public method:
init: function() {self = this;},
...and by making sure I call objA.init(); before passing objA.publicA to objB.callback, things actually work.
I cannot stress the immensity of the feeling that there's a better way of doing this. What am I missing?
The generalized solution is extremely simple.
Write all the module's methods as private, then expose those that need to be public.
I write all my modules this way :
var objA = function () {
var privateA = "found";
var A = function () {
console.log("privateA is " + A_helper());
},
var A_helper = function () {
return privateA;
}
return {
publicA: A
//A_helper need not be exposed
};
}();
Thus, all methods are in the same scope, each one having direct access to all other methods in the same module, and the ambiguous this prefix is avoided.
objB.callback(objA.publicA); will now work as expected.
See fiddle
I've tried the var objA = (){}.call({}) thingy,
How? You want to use call on the callback that you want to invoke with a custom this, not on your module closure. It should be
var objB = {
callback: function (callback, context) {
callback.call(context);
}
};
objB.callback(objA.publicA, objA);
I've tried setting var self = this;
The self variable is supposed to be in a closure and point to the object on the methods are stored. That is only this when your module IEFE would be invoked on your module - it's not. Or if it was a constructor - it's not. You could change that with call as above:
var objA = function () {
var privateA = "found",
self = this;
this.publicA = function () {
console.log("privateA is " + self.publicA_helper());
};
this.publicA_helper = function () {
return privateA;
};
return this;
}.call({});
But that's ugly. In your case, the self variable simply needs to point to the object literal which you're returning as your module:
var objA = function () {
var privateA = "found",
self;
return self = {
publicA: function () {
console.log("privateA is " + self.publicA_helper());
},
publicA_helper: function () {
return privateA;
}
};
}();
Btw, since you're creating a singleton you don't need an explicit self, you could just reference the variable that contains your module (as long as that doesn't change):
var objA = function () {
var privateA = "found";
return {
publicA: function () {
console.log("privateA is " + objA.publicA_helper());
},
publicA_helper: function () {
return privateA;
}
};
}();
Another method would be to simply make all functions private and then expose some of them - by referencing them local-scoped you will have no troubles.
var objA = function () {
var privateA = "found";
function publicA() {
console.log("privateA is " + helper());
}
function helper() {
return privateA;
}
return self = {
publicA: publicA,
publicA_helper: helper // remove that line if you don't need to expose it
};
}();
The reason is that the context is getting changed when you are invoking the callback. Not a generalized solution, but shows that the code works by specifying the context while invoking callback.
var objA = function () {
var privateA = "found";
return {
publicA: function () {
console.log("privateA is " + this.publicA_helper());
},
publicA_helper: function () {
return privateA;
}
};
}();
var objB = function () {
return {
callback: function (callback) {
callback.call(objA);
}
}
}();
objA.publicA(); // privateA is found
objB.callback(objA.publicA); // privateA is found
Im working in a sub-module pattern code. Want to create sub-modules with objects literals, the problem is this for the objects inside the sub-module is MODULE and not my object literal. Any idea?
var MODULE.sub = (function () {
var myObject = {
key: value,
method: function () {
this.key // this = MODULE and not MyObject... :(
}
};
return myObject.method;
}(MODULE));
This works for me:
var MODULE = MODULE || {};
MODULE.sub = (function () {
return {
myObject : {
key : 10,
method : function() {
console.log(this.key);
}
}
};
})();
Then call it:
MODULE.sub.myObject.method();
You were only returning the method and not the key so "this" would be undefined. You could keep it private if you want like this and pass key in as a var:
var MODULE = MODULE || {};
MODULE.sub = (function () {
var key = 10,
return {
myObject : {
method : function() {
console.log(key);
}
}
};
})();
Solved... just return a function in MODULE.sub calling the public method. I don't know if is the best approach
var MODULE.sub = (function () {
var myObject = {
key: value,
method: function () {
this.key // this = myObject :)
}
};
return function () {
myObject.method();
}
}(MODULE));
The this keywords value depends on how the function is called. So if you assign that function to MODULE.sub, and then invoke it as MODULE.sub(…), then this will point to the MODULE of course. If you had invoked it as myObject.method(…), then this would point to that object.
So you either should expose the whole myObject (like in #BingeBoys answer), or do not export that function and expect it to be a method of myObject. Instead, you could use a bound one:
return myObject.method.bind(myObject);
or the explicit equivalent of that
return function() {
return myObject.method();
};
or you would not put the function as method on that object at all:
…
var myObject = {
key: value,
};
return function() {
myObject.key // no `this` here
…
};
…
I have the following piece of code:
function initValidation()
{
// irrelevant code here
function validate(_block){
// code here
}
}
Is there any way I can call the validate() function outside the initValidation() function? I've tried calling validate() but I think it's only visible inside the parent function.
function initValidation()
{
// irrelevant code here
function validate(_block){
console.log( "test", _block );
}
initValidation.validate = validate;
}
initValidation();
initValidation.validate( "hello" );
//test hello
Hope that you are looking for something like this
function initValidation()
{
// irrelevant code here
this.validate = function(_block){
// code here
}
}
var fCall = new initValidation()
fCall.validate(param);
This will work.
Hope this addresses your problem.
You can call validate from within initValidation. Like this.
function initValidation()
{
// irrelevant code here
function validate(_block){
// code here
}
return validate(someVar);
}
validate is not visible to anything outside of initValidation because of its scope.
Edit: Here's my suggestion of a solution.
(function() {
function validate(_block){
// code here
}
function initValidation()
{
// irrelevant code here
return validate(someVar);
}
function otherFunctions() {
// ...
}
// initValidation = function
}());
// initValidation = undefined
All of your functions will be hidden to anything outside the function wrapper but can all see each other.
This invocation will return function statement, which is function validate.
So you can invoke directly after the first invocation.
function initValidation() {
// irrelevant code here
return function validate(_block) {
// code here
}
}
initValidation()();
I know this is an old post but if you wish to create a set of instances that you wish to work with that reuse the code you could do something like this:
"use strict";
// this is derived from several posts here on SO and ultimately John Resig
function makeClassStrict() {
var isInternal, instance;
var constructor = function(args) {
if (this instanceof constructor) {
if (typeof this.init == "function") {
this.init.apply(this, isInternal ? args : arguments);
}
} else {
isInternal = true;
instance = new constructor(arguments);
isInternal = false;
return instance;
}
};
return constructor;
}
var MyClass = makeClassStrict();// create "class"
MyClass.prototype.init = function(employeeName, isWorking) {
var defaultName = 'notbob';
this.name = employeeName ? employeeName : defaultName;
this.working = !!isWorking;
this.internalValidate = function() {
return {
"check": this.working,
"who": this.name
};
};
};
MyClass.prototype.getName = function() {
return this.name
};
MyClass.prototype.protoValidate = function() {
return {
"check": this.working,
"who": this.name
};
};
var instanceBob = MyClass("Bob", true);// create instance
var instanceFred = MyClass("Fred", false);// create instance
var mything = instanceFred.internalValidate();// call instance function
console.log(mything.check + ":" + mything.who);
var myBobthing = instanceBob.protoValidate();
console.log(myBobthing.check + ":" + myBobthing.who);
I know this thread's been here for quite some time but I thought I'd also leave my 0.02$ on how to call inner functions from outside their scope (might benefit somebody).
Note that in any place, a better design decision should be taken into consideration rather than some hackish workaround which will bite you back later.
How about using function expressions instead of function statements and making use of the global scope.
var innerFn;
function outerFn() {
innerFn = function(number) {
return number ** 2;
}
}
outerFn();
console.log(innerFn(5));
// if there's more complex code around and you could write this defensively
if (typeof innerFn !== 'undefined') {
console.log(`we are squaring the number 5 and the result is: ${innerFn(5)}`);
} else {
console.log('function is undefined');
}
Or, you can make use of closures:
function outer() {
// initialize some parameters, do a bunch of stuff
let x = 5, y = 10;
function inner() {
// keeps references alive to all arguments and parameters in all scopes it references
return `The arithmetic mean of the 2 numbers is: ${(x + y) / 2}`;
}
return inner;
}
innerFn = outer(); // get a reference to the inner function which you can call from outside
console.log(innerFn());
Create a variable outside the parent function, then in the parent function store your required function in the variable.
Var Store;
Function blah() {
Function needed() {
#
}
Store = needed;
}
As a minor variation of Esailija's answer, I did this:
function createTree(somearg) {
function validate(_block) {
console.log( "test", _block );
}
if (somearg==="validate") { return validate; } // for addNodes
// normal invocation code here
validate(somearg);
}
function addNodes() {
const validate = createTree("validate");
//...
validate( "hello" );
}
createTree("create");
addNodes();
//validate("illegal");
so validate() is now perfectly shared between createTree() and addNodes(), and perfectly invisible to the outside world.
Should work.
function initValudation() {
validate();
function validate() {
}
}
Function definition:
function initValidation() {
// code here
function validate(_block){
// code here
console.log(_block);
}
return validate;
}
Call it as below:
initValidation()("hello");
function initValidation()
{
function validate(_block){
console.log(_block)
// code here
}
// you have to call nested function
validate("Its Work")
}
// call initValidation function
initValidation()