Have one function as following
function JsFunction(){
//some logic already done by framework library...
}
Now, I want to add extra login on that JsFunction
when I call it will perform its logic done before + the logic I added in it.
I don't want to duplicate same logic from library and then add my own code.
so, how can I achieve that with same function name JsFunction()??
If the work the function does is synchronous, it's really easy to wrap it (see below). If it does its work asynchronously, you may or may not still be able to wrap it, the details will vary depending on the implementation of the function.
Wrapping a function that works synchonrously:
var original = JsFunction;
JsFunction = function JsFunction() {
// Do stuff before
// ...
// Call it
var result = original.apply(this, arguments);
// Do stuff after
// ...
return result; // Or something else if you prefer
};
The meat of that is
var result = original.apply(this, arguments);
...which uses Function#apply to call the original function with the same this that your replacement was called with and all arguments it was called with (arguments is a special pseudo-array in JavaScript containing the arguments used when calling a traditional function or method).
With ES2015+ features, you could replace the use of arguments with a rest parameter:
var original = JsFunction;
JsFunction = function JsFunction(...args) {
// Do stuff before
// ...
// Call it
var result = original.apply(this, args);
// Do stuff after
// ...
return result; // Or something else if you prefer
};
Copy the old function, then create a new function which calls it (passing in any arguments and the right context), captures the return value, does something else, then returns the return value.
(function () { // In an IIFE to avoid creating a global variable
let oldJsFunction = JsFunction;
JsFunction = function JsFunction() {
let return_value = oldJsFunction.apply(this, arguments);
console.log("… and another thing");
return return_value;
}
)());
Related
Background
I want a function keeping track of its own state:
var myObject = {
myFunction: function () {
var myself = this.myFunction;
var firstTime = Boolean(!myself.lastRetry);
if (firstTime) {
myself.lastRetry = Date.now();
return true;
}
// some more code
}
}
The problem with the above code is that the value of this will depend on the site of the function call. I want the function to be able to refer to itself without using:
myObject.myFunction
.bind()
.apply()
.call()
Question
Is it possible to give a function this kind of self awareness independent of its call site and without any help from external references to it?
If you want to store that state on the function instance, give the function a name, and use that name within it:
var myObject = {
myFunction: function theFunctionName() {
// ^^^^^^^^^^^^^^^--------------------- name
var firstTime = Boolean(!theFunctionName.lastRetry);
// ^--------------------------- using it
if (firstTime) {
theFunctionName.lastRetry = Date.now();
// ^------------------------------------------------ using it
return true;
}
// some more code
}
};
You'd do that whenever you want to use a function recursively as well. When you give a name to a function that way (putting the name after function and before (), that name is in-scope within the function's own code. (It's not in-scope for the code containing the function if it's a function expression, but it is if it's a function declaration. Yours is an expression.)
That's a named function expression (where previously you had an anonymous function expression). You may hear warnings about NFEs, but the issues various JavaScript implementations had with them are essentially in the past. (IE8 still handles them incorrectly, though: More in this post on my blog.)
You might consider keeping that state somewhere private, though, via an IIFE:
var myObject = (function(){
var lastRetry = null;
return {
myFunction: function() {
var firstTime = Boolean(!lastRetry);
if (firstTime) {
lastRetry = Date.now();
return true;
}
// some more code
}
};
})();
Now, nothing outside that outer anonymous function can see lastRetry at all. (And you don't have to worry about IE8, if you're supporting stubborn XP users. :-) )
Side note: The unary ! operator always returns a boolean, so your
var firstTime = Boolean(!theFunctionName.lastRetry);
...is exactly equivalent to:
var firstTime = !theFunctionName.lastRetry;
...but with an extra unnecessary function call. (Not that it hurts anything.)
Of course you can, simply give your function an internal named representation and it can refer to itself from there. For example...
var obj = {
doThings:function doThingsInternal(arg1, arg2) {
console.log(arg1, arg2);
for (var arg in doThingsInternal.arguments) {
console.log(arg);
}
}
};
obj.doThings('John', 'Doe');
You could use a simple Closure, if you are not too bent on keeping state existence knowledge within the function. But I guess you don't want that. Another way to do this could be changing the function itself on the first call. Benefits, no/less state variables needed and no costly checks on subsequent calls! -
var myObject = {
myFunction: function () {
// Whatever you wanna do on the first call...
// ...
// And then...
this.myFunction = function(){
// Change the definition to whatever it should do
// in the subsequent calls.
}
// return the first call value.
}
};
You can extend this model to any states by changing the function definition per your state.
My question is rather weird, it has to do with something i have seen in jQuery but so far i have been unable to recreate it.
in jQuery you can go like this
jQuery('div').append
or
jQuery.ajax
the application i am making would need a similar syntax, i notice if you use new like
var that=new function(){
}
you can call the function with just that, without the (), but in some cases i would need it.
The reason for this is some functions i have need to select a dom element just like jQuery so.
that('[data-something="this"]').setEvent('click',functin(){})
and some automatically do it so:
that.loadIt('this','[data-something="that"]')
the reason for this is that the dom elements are loaded externally and pushed, then the script waits for it to be ready before continuing. and doing it this way, to me anyway seems like the most cleanest way to get this functionality (i am coding a full javascript framework so i avoid libraries to keep the scripts fast)
Functions are objects.
Just get rid of new, and add properties directly to that.
var that = function() {
// do some work
}
that.loadit = function() {
// do other work
}
Since you're trying to achieve something like jQuery does, then have that call a constructor.
;(function(global) {
// function to be publicly exposed
var that = function(foo, bar) {
return new MyLibrary(foo, bar);
}
// publicly expose the function
global.that = that;
// use the function as a namespace for utilities
that.loadit = function() {
// do other work
}
// The actual constructor function, like the internal jQuery constructor
MyLibrary(foo, bar) {
// constructor function
}
// Prototypal inheritance of objects created from the constructor
MyLibrary.prototype.setEvent = function() {
// do some work
return this; // allows for method chaining
};
MyLibrary.prototype.otherMethod = function() {
// do something else
return this; // allows for method chaining
};
})(this);
Functions are objects and can have properties, just like other objects can. So, you can add a property to a function like this:
function myFunc(){}
myFunc.someFunc = function(){}
If you use new myFunc the resulting object won't have someFunc as it's not part of the prototype.
So, you can make something like this:
function myFunc(){
// This lets you do "myFunc()" instead of "new myFunc()"
if (!(this instanceof myFunc)) {
return new myFunc();
}
else{
this.val = 0;
this.setVal = function(x){
this.val = x;
// for function chaining
return this;
}
this.getVal = function(){
return this.val;
}
}
}
// This function is not part of the prototype
myFunc.test = function(){
alert('hi');
}
// Some tests
var obj = myFunc();
obj.setVal(12).getVal(); // 12
myFunc.test();
obj.test(); // Error: 'test' is not a function
myFunc.getVal(); // Error: 'getVal' is not a function
$.fn.loadIt=function(var1,var2) {
// $(this) is automatically passed
// do stuff
}
call it like this
$('#element').loadIt('a variable','another variable');
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
how does jquery chaining work?
This is a normal thing you would see in a jQuery code:
$("div.selected").html("Blah.");
So, in the above code, in the function $(), it has a function called html(). And what I don't understand is, what I normally will do is:
funcA("blah"); //normal function, cool.
funcA.funcB("blah"); //normal function in an object, still cool.
and now this is confusing:
funcA("blah").funcB("blah") //huh??
How can funcB knows the arguments in funcA?
How can jQuery achieve this?
Thanks.
//function returning an object is a possibility. bar has access to elem because of
// the shared scope
function foo ( elem ) {
return {
bar : function () {
return elem.id;
}
};
}
In this one, the foo function returns an object containing whatever methods you wish. So when you call foo, you receive this:
{
bar : function () {
return elem.id;
}
}
elem is present from your call to foo. If you were to add a console.log( elem ) at the top of bar, you'd see that it's the same thing as what you passed to foo.
//this is kinda how jQuery does it:
var foo = (function() {
function foo ( elem ) {
this.elem = elem;
}
foo.prototype.bar = function () {
return this.elem.id;
};
return function ( elem ) {
return new foo( elem );
};
}());
This is a little more complex, and actually divided into two.
function foo ( elem ) {
this.elem = elem;
}
foo.prototype.bar = function () {
return this.elem.id;
};
Who doesn't love prototypical inheritance mixed with classical inheritance names? Anyway...functions act as both regular functions and as constructors. Meaning, when called with the new keyword, two special things happen:
this inside of the foo refers to a freshly made copy of foo.prototype
foo.prototype is returned (unless foo returns an object)
Note that foo.prototype isn't a magic value. It's just like any other object property.
So, inside the foo function/constructor, we're merely setting foo.prototype.elem, but not directly. Think of it like this (a little inaccurate, but it'll do): foo.prototype is the blueprint of a product. Whenever you wish to make more, you use the blueprint - duplicate what's inside, pass it along. Inside of foo, this refers to such a replication of the blueprint.
However, by explicitly setting values on foo.prototype, we're altering the blueprint itself. Whenever foo is called, it'll be called with this altered blueprint.
Finally, once foo is finished, the replication (the duplicated blueprint, but after foo has done stuff with it) is returned. This replication contains the original blueprint, and everything else we might have added - in this example, elem.
var foo = (function() {
...
return function ( elem ) {
return new foo( elem );
};
}());
We create a nameless function and immediately execute it.
(function () {
console.log( 'meep' );
}());
//is the equivalent of:
var something = function () {
console.log( 'meep' );
};
something();
something = undefined; //we can no longer use it
//and of this
function () {
console.log( 'meep' );
}(); //<--notice the parens
//however, it's considered good practice to wrap these self-executing-anonymous-functions
// in parens
Like all other functions, they can return values. And these values can be captured into variables.
var answer = (function () {
return 42;
}());
answer ==== 42;
var counter = (function () {
var c = 0;
return function () {
return c++;
};
}());
//counter is now a function, as a function was returned
counter(); //0
counter(); //1
counter(); //2...
So:
var foo = (function () {
...
return function ( elem ) {
...
};
}());
Returns a function which receives an argument, and that function is now assigned to foo.
The insides of the function:
return new foo( elem );
Is to ensure the special conditions I've spoken about above - it ensures that a new copy of the blueprint is manufactured, by explicitly doing the new operation. This can actually be replicated like this:
function foo ( elem ) {
this.elem = elem;
}
foo.prototype.bar = function () {...};
As long as you always call foo with the new keyword.
When you do funcA("blah").funcB("blah"), then funcB is called on whatever funcA returns. So you have funcA return some object that has a funcB, which is then called.
In the case of jQuery, most jQuery functions return the jQuery object, so function calls can be chained as much as you like. Many jQuery functions are designed to modify the contents of the jQuery object that is returned. So in your example, it's not the case that the call to html() "knows about" what was passed to the $() function. Rather, the $() function returns a jQuery object that points to the DOM elements that match the given selector. Further calls to functions on that jQuery object, then, will affect those selected elements.
Most functions in jquery return a jquery object which contains a set of elements. html doesn't know the arguments of $() exactly, it's more that the result of $() has a set of elements which are created based on the parameter passed to $().
In your example of funcA and funcB though, you could easily have funcA return an object which has a function named funcB. This object could also contain the value passed to funcA and then a call to funcB could "know" that value as well.
http://jsfiddle.net/ScENm/
function funcA(arg1) {
var enclosedVariable= arg1;
return {
funcB: function () {
alert(enclosedVariable);
}
};
}
Here is a quick and dirty example. ^^
funcA takes an argument and saves it then returns an object containing a single function. It has been "enclosed" and now funcB has access to this.
Technically you don't even have to save it... arg1 is available to funcB as well.
You should research chaining, it's what you're describing. You can google "jQuery chaining" to get started. Also check out jQuery's pluging tutorial for some more info
A function isn't anything special, you can return a function inside an object. For a quick example:
function $() {
return {
html: function() {
}
};
}
$().html(); // You just called the function!
jQuery doesn't have anything special in it. When you call a function in jQuery that doesn't return a value, it usually returns the jQuery object it was called on, like so:
var obj = {
doSomething: function() {
return this;
},
doSomethingElse: function() {
alert('Hi!');
}
};
obj.doSomething().doSomethingElse(); // Alerts "Hi!"
because again, it's just an object.
Chaining is generally done on the basis of the object that a method should return. If object A be an instance of class A and a method in it returns object A then the returned object can again be applied to the same class and this can be arranged in a chaining fashion. Or say object of class A returns object of class B then, the returned object can be applied to the method of class B.
objectOfA->methodOfA(arg)->methodOfB(args);
In this case if objectOfA->methodOfA(arg) returns object of class B and hence the method of class B can be called upon it and chained as above.
In your case,
$('div.selected').html('Blah ..')
Here $('div.selected') return a jquery element object(or array of object); upon which the method .html() can be applied since the method is only applicable to element object of jquery. It is just chaining as other programming languages do.
In case of PHP this case looks like,
$class->method1(argument)->method(2)
In this case, if class A has two methods method1 and method2 and method1 return the instance of its own then method 2 is again applicable to it.
This can be related to a function as well. Lets us suppose I have a function as such;
def function1(name):
return name
def function2(arg):
print len(name)
Now, this two functions can be chained simply as,
function2(function1('My Name is blah ...'))
Since the function1 returns a value, the type of the value must match to the input argument of function2 and this is how object work.
In this code I created a function called someFunction. Then I modified Function.prototype.apply and call methods. So instead of my function code is working I am running my interception code (which shows an alert). But neither "call" nor "apply" intercepts direct method call. Is it possiple to intercept this?
Function.prototype.call = function(){alert("call");};
Function.prototype.apply = function(){alert("apply");};
function someFunction(){}
window.onload = function(){
someFunction.call(this); //call alert is shown
someFunction.apply(this); //apply alert is shown
someFunction(); //how can I intercept this?
}
You can only override a known function by setting another function in its place (e.g., you can't intercept ALL function calls):
(function () {
// An anonymous function wrapper helps you keep oldSomeFunction private
var oldSomeFunction = someFunction;
someFunction = function () {
alert("intercepted!");
oldSomeFunction();
}
})();
Note that, if someFunction was already aliased/referenced by another script before it was changed by this code, those references would still point to the original function not be overridden by the replacement function.
Function.prototype.callWithIntercept = function () {
alert("intercept");
return this.apply(null, arguments);
};
var num = parseInt.callWithIntercept("100px", 10);
It is worth noting that in newer versions of JS, there are Proxy objects you can use:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy
There is a chance you can intercept direct function call. This requires:
Either the function is created by Function.prototype.bind and you have to overwrite Function.prototype.bind before creating the function, or
The function is created from Function() (or new Function()) and you also have to overwrite Function function before creating the target function.
If neither of the above two can be met, the only way to intercept a direct call is to wrap the target function, which is the solution provided by AndyE https://stackoverflow.com/a/3406523/1316480
For a function that is created by function literal and is hidden in private scope, there is no way to intercept a direct call to it.
I have a blog post concludes all of these: http://nealxyc.wordpress.com/2013/11/25/intercepting-javascript-function/
You could iterate over the global scope and replace any objects of function type you find which aren't "yours".
Brilliant, love it :)
const originalApply = window.Function.prototype.apply;
window.Function.prototype.apply = function(){
console.log("INTERCEPTING APPLY", arguments);
return originalApply.call(this, ...arguments);
};
You can achieve this with a Proxy.
First define a handler with an apply trap that intercepts calls to the function. Then, using that handler, set the function to be a proxy onto itself. Example:
function add(a, b){
return a + b;
}
const handler = {
apply: function(target, thisArg, argumentsList) {
console.log('add was called with ' + argumentsList.join(' and '));
return target(...argumentsList);
}
};
add = new Proxy(add, handler);
var m = add(3, 5);
console.log('m = ', m);
var n = add(12, 8);
console.log('n = ', n);
I have a function I can't modify:
function addToMe() { doStuff(); }
Can I add to this function? Obviously this syntax is terribly wrong but it's the general idea...
function addToMe() { addToMe() + doOtherStuff(); }
You could store a reference to the original function, and then override it, with a function that calls back the original one, and adds the functionality you desire:
var originalFn = addToMe;
addToMe = function () {
originalFn(); // call the original function
// other stuff
};
You can do this because JavaScript functions are first-class objects.
Edit: If your function receives arguments, you should use apply to pass them to the original function:
addToMe = function () {
originalFn.apply(this, arguments); // preserve the arguments
// other stuff
};
You could also use an auto-executing function expression with an argument to store the reference of the original function, I think it is a little bit cleaner:
addToMe = (function (originalFn) {
return function () {
originalFn.apply(originalFn, arguments); // call the original function
// other stuff
};
})(addToMe); // pass the reference of the original function