Change/Wrap a function from prototype - javascript

I'm writing a framework that uses wrapping of functions in order to create a debug tool. Currently, I want to report and aggregate information upon function call. I'm using the following code:
function wrap(label, cb) {
return function () {
report(label);
cb.apply(this, arguments);
}
}
And then in order to bind the debug operation I will use:
function funcToWrap (){/* Some existing function*/}
funcToWrap = wrap("ContextLabel", funcToWrap);
Now, when funcToWrap is invoked, it is wired to go through report() method.
The requirement I have is to now change this syntax so that the wrapping is done via:
funcToWrap.wrap("ContextLabel");
Ideally, something like this would solve my issue, but this of course is illegal:
Function.prototype.time = function(label){
var func = this;
// The actual difference:
this = function () { // ILLEGAL
report(label);
func.apply(this, arguments);
}
};
Thank you from ahead for any insight regarding this.

The requirement I have is to now change this syntax so that the wrapping is done via:
funcToWrap.wrap("ContextLabel");
Unless there's a funcToWrap = at the beginning of that, you simply can't meet that requirement. There's no way to change the guts of the function, you can only do what you're doing, create a new function to take its place.
If you have a funcToWrap = at the beginning, of course, it's quite straightforward. But I take it that's not the requirement.
But if I'm mistaking the requirement, then:
Function.prototype.wrap = function wrap(label) {
var f = this;
return function () {
report(label);
return f.apply(this, arguments); // Note the added `return` here
};
};
Usage:
funcToWrap = funcToWrap.wrap("ContextLabel");
Reasonably certain from the question, though, that A) That's not what you're looking for, and B) You could have done it if it were.

The requirement I have is to now change this syntax so that the wrapping is done via:
funcToWrap.wrap("ContextLabel");
That's impossible. One cannot alter a function's behaviour from the outside, it's much like an immutable primitive value in that regard. The only thing you can do is to create a new function and overwrite the old one, but this overwriting has to be explicit. You could use some eval magic for that (like here), but I recommend to use an assignment like in your first example (regardless whether the wrap function is static or a Function method).

Related

Use more modules from return of Module Export [duplicate]

I'm trying to get the principles of doing jQuery-style function chaining straight in my head. By this I mean:
var e = f1('test').f2().f3();
I have gotten one example to work, while another doesn't. I'll post those below. I always want to learn the first principle fundamentals of how something works so that I can build on top of it. Up to now, I've only had a cursory and loose understanding of how chaining works and I'm running into bugs that I can't troubleshoot intelligently.
What I know:
Functions have to return themselves, aka "return this;"
Chainable functions must reside in a parent function, aka in jQuery, .css() is a sub method of jQuery(), hence jQuery().css();
The parent function should either return itself or a new instance of itself.
This example worked:
var one = function(num){
this.oldnum = num;
this.add = function(){
this.oldnum++;
return this;
}
if(this instanceof one){
return this.one;
}else{
return new one(num);
}
}
var test = one(1).add().add();
But this one doesn't:
var gmap = function(){
this.add = function(){
alert('add');
return this;
}
if(this instanceof gmap) {
return this.gmap;
} else{
return new gmap();
}
}
var test = gmap.add();
In JavaScript Functions are first class Objects. When you define a function, it is the constructor for that function object. In other words:
var gmap = function() {
this.add = function() {
alert('add');
return this;
}
this.del = function() {
alert('delete');
return this;
}
if (this instanceof gmap) {
return this.gmap;
} else {
return new gmap();
}
}
var test = new gmap();
test.add().del();
By assigning the new gmap();to the variable test you have now constructed a new object that "inherits" all the properties and methods from the gmap() constructor (class). If you run the snippet above you will see an alert for "add" and "delete".
In your examples above, the "this" refers to the window object, unless you wrap the functions in another function or object.
Chaining is difficult for me to understand at first, at least it was for me, but once I understood it, I realized how powerful of a tool it can be.
Sadly, the direct answer has to be 'no'. Even if you can override the existing methods (which you probably can in many UAs, but I suspect cannot in IE), you'd still be stuck with nasty renames:
HTMLElement.prototype.setAttribute = function(attr) {
HTMLElement.prototype.setAttribute(attr) //uh-oh;
}
The best you could probably get away with is using a different name:
HTMLElement.prototype.setAttr = function(attr) {
HTMLElement.prototype.setAttribute(attr);
return this;
}
To "rewrite" a function, but still be able to use the original version, you must first assign the original function to a different variable. Assume an example object:
function MyObject() { };
MyObject.prototype.func1 = function(a, b) { };
To rewrite func1 for chainability, do this:
MyObject.prototype.std_func1 = MyObject.prototype.func1;
MyObject.prototype.func1 = function(a, b) {
this.std_func1(a, b);
return this;
};
Here's a working example. You just need to employ this technique on all of the standard objects that you feel need chainability.
By the time you do all of this work, you might realize that there are better ways to accomplish what you're trying to do, like using a library that already has chainability built in. *cough* jQuery *cough*
First, let me state that i am explaining this in my own words.
Method chaining is pretty much calling a method of the object being returned by another function/method. for example (using jquery):
$('#demo');
this jquery function selects and returns a jquery object the DOM element with the id demo. if the element was a text node(element), we could chain on a method of the object that was returned. for example:
$('#demo').text('Some Text');
So, as long as a function/method returns an object, you can chain a method of the returned object to the original statement.
As for why the latter don't work, pay attention to where and when the keyword this is used. It is most likely a context issue. When you are calling this, make sure that this is referring to that function object itself, not the window object/global scope.
Hope that helps.
Just call the method as var test = gmap().add();
as gmap is a function not a variable

Executing a method inside a method

I'm currently working on a JavaScript exercise in FreeCodeCamp, and one of the test-cases my code should work with is a function call that looks like this:
addTogether(2)(3);
here is the bare-bones function I'm given:
function addTogether() {
return;
}
When I run the code below:
function addTogether() {
return arguments;
}
In the console, that the editor provides, I get:
TypeError: addTogether(...) is not a function
The instructions hint at using the arguments object, and it works well with test-case function calls that only have one argument object (i.e. addTogether(2, 3);), but not with the one I've shown above.
Is there a way to access/utilize the separate argument objects when they're in the format I showed above?
Note: I don't want any sort of answer to solve the problem, just info on any techniques on accessing the arguments of these type of function calls.
Help, is greatly appreciated.
Don't think of it as two separate sets of arguments. Think of it as you're calling another function (which you are). Functions are first-class values in JavaScript so you can use them just like any other value. This includes returning them from functions.
var f = function(y) {
console.log('f:', y);
};
var getF = function(x) {
console.log('getF:', x);
return f;
};
getF(1)(2);
Functions can also use values that exist in any parent scope. Loosely speaking, functions which do this are called closures.
function createGetX(x) {
return function() {
// Since x is in the parent scope, we can use it here
return x;
}
}
var one = createGetX(1);
console.log(one()); // Always
console.log(one()); // returns
console.log(one()); // one
Sometimes it helps me to think in a certain order. You can read the code "addTogether(2)" and stop before reading the "(3)".
From there you can see the exercise wants you to have that first part "addTogether(2)" return a function...since anytime there are "()" that means a function is getting called.
So "addTogether(2)" needs to return a function that takes one argument. Later that 3 will be one example of an input.
I think the name "addTogether" is a bit confusing..since that function's job is to make up and return the actual function that adds.
Sort of hard to explain this one without helping too much, but the bulk of your job here is to return a custom function, which includes the first variable (from it's scope) and expects another variable when it's called.
You could do this with closures.
function addTogether(x) {
return function(y) {
return x+y;
}
}

What does . mean in a JS function when it's used as in .data = [...] [duplicate]

I'm trying to get the principles of doing jQuery-style function chaining straight in my head. By this I mean:
var e = f1('test').f2().f3();
I have gotten one example to work, while another doesn't. I'll post those below. I always want to learn the first principle fundamentals of how something works so that I can build on top of it. Up to now, I've only had a cursory and loose understanding of how chaining works and I'm running into bugs that I can't troubleshoot intelligently.
What I know:
Functions have to return themselves, aka "return this;"
Chainable functions must reside in a parent function, aka in jQuery, .css() is a sub method of jQuery(), hence jQuery().css();
The parent function should either return itself or a new instance of itself.
This example worked:
var one = function(num){
this.oldnum = num;
this.add = function(){
this.oldnum++;
return this;
}
if(this instanceof one){
return this.one;
}else{
return new one(num);
}
}
var test = one(1).add().add();
But this one doesn't:
var gmap = function(){
this.add = function(){
alert('add');
return this;
}
if(this instanceof gmap) {
return this.gmap;
} else{
return new gmap();
}
}
var test = gmap.add();
In JavaScript Functions are first class Objects. When you define a function, it is the constructor for that function object. In other words:
var gmap = function() {
this.add = function() {
alert('add');
return this;
}
this.del = function() {
alert('delete');
return this;
}
if (this instanceof gmap) {
return this.gmap;
} else {
return new gmap();
}
}
var test = new gmap();
test.add().del();
By assigning the new gmap();to the variable test you have now constructed a new object that "inherits" all the properties and methods from the gmap() constructor (class). If you run the snippet above you will see an alert for "add" and "delete".
In your examples above, the "this" refers to the window object, unless you wrap the functions in another function or object.
Chaining is difficult for me to understand at first, at least it was for me, but once I understood it, I realized how powerful of a tool it can be.
Sadly, the direct answer has to be 'no'. Even if you can override the existing methods (which you probably can in many UAs, but I suspect cannot in IE), you'd still be stuck with nasty renames:
HTMLElement.prototype.setAttribute = function(attr) {
HTMLElement.prototype.setAttribute(attr) //uh-oh;
}
The best you could probably get away with is using a different name:
HTMLElement.prototype.setAttr = function(attr) {
HTMLElement.prototype.setAttribute(attr);
return this;
}
To "rewrite" a function, but still be able to use the original version, you must first assign the original function to a different variable. Assume an example object:
function MyObject() { };
MyObject.prototype.func1 = function(a, b) { };
To rewrite func1 for chainability, do this:
MyObject.prototype.std_func1 = MyObject.prototype.func1;
MyObject.prototype.func1 = function(a, b) {
this.std_func1(a, b);
return this;
};
Here's a working example. You just need to employ this technique on all of the standard objects that you feel need chainability.
By the time you do all of this work, you might realize that there are better ways to accomplish what you're trying to do, like using a library that already has chainability built in. *cough* jQuery *cough*
First, let me state that i am explaining this in my own words.
Method chaining is pretty much calling a method of the object being returned by another function/method. for example (using jquery):
$('#demo');
this jquery function selects and returns a jquery object the DOM element with the id demo. if the element was a text node(element), we could chain on a method of the object that was returned. for example:
$('#demo').text('Some Text');
So, as long as a function/method returns an object, you can chain a method of the returned object to the original statement.
As for why the latter don't work, pay attention to where and when the keyword this is used. It is most likely a context issue. When you are calling this, make sure that this is referring to that function object itself, not the window object/global scope.
Hope that helps.
Just call the method as var test = gmap().add();
as gmap is a function not a variable

How to create a shorthand for 'this.getAttribute'

Correct me if I'm wrong. I'm not sure if shorthand is the correct word. But, it's the closest I can come up with:
For example:
this.getAttribute
I am using this a lot throughout one of my scripts, over 20 items.
Is it possible to just reference it like:
getA
or something? Instead of typing this.getAttribute over and over again? I know it seems likes a first world problem, but I am very OCD about my code and like to be minimal but still sustain readability. getA to reference this.getAttribute still makes a alot of sense (to me anyway), and in essence, shorter code. Any way to accomplish this?
if you call assign a method of an object to a var and call it by that, it the value of this inside the method will be the global context, as the function context is bound to where it got called from, so you can't do that.
However, you can use the built in Function method bind to preserve the context, but it's a rather expensive operation just to alias your method.
var getA = this.getAttribute.bind(this);
getA("yourAttribute");
or use call to enforce the context when you call it
var getA = this.getAttribute;
getA.call(this,"yourAttribute");
but both are not really great and in most cases all you need to do is to keep the actual return value in a var and reuse that, without invoking the getter at all. The getter is verbose because that's a good way to make an expensive method look expensive, and discourage people from calling it 20 times in a row in the first place. They usually should only be called when you expect a different result.
var a = this.getAttribute("yourAttribute");
When you say you call it 20 times in 20 different places I'm relatively sure those are not 20 places that expect the value to be different, especially when they are inside the same function scope.
If you are dealing with custom data-* attributes you can also just directly retrieve it from the .data property on your element, it's a map of all your data-attributes which is the ideal scenario.
<element data-your-attribute="yourData"></element>
var a = this.data.yourAttribute; //automatically updated and name converted from dash to camelCase
(all examples assume this refers to you element, and your function is a method of your element)
Yes, you can create a function like this:
function getA(element, attr) {
return element.getAttribute(attr);
}
And then, instead of this.getAttribute(attr), use getA(this, attr).
However, if you want to use it to get several attributes of the same element, and you want to avoid avoid passing this each time, you can use
var getA = this.getAttribute.bind(this);
And then, instead of this.getAttribute(attr), use getA(attr).
To sum it up:
#Adeneo says:
function getA(element, attr)
{
return element.getAttribute(attr);
}
I said:
Element.prototype.getA = Element.prototype.getAttribute
Which can be used as:
var attr = getA(document.getElementById("test"), "attr"); //Adeneo
var attr = document.getElementById("test").getA("attr"); //Mouser
I strongly advise against extending the Element object.
jQuery does the following:
They have their master function object $. That function has a method called attr. So the master function object finds an element on the page to which you can call the method attr.
$("element").attr("attr");
To reproduce:
var masterFunction = function(selector)
{
this.result = document.querySelectorAll(selector);
}
var selectElement = function(selector)
{
return new masterFunction(selector);
}
masterFunction.prototype.attr = function(attr)
{
var returnArray = [];
Array.prototype.forEach.call(this.result, function(element){
if (element.hasAttribute(attr))
{
returnArray.push(element.getAttribute(attr))
}
});
return returnArray;
}
Please remember that this, like jQuery returns an array containing the results.

Is there a way to make native function chainable? [duplicate]

I'm trying to get the principles of doing jQuery-style function chaining straight in my head. By this I mean:
var e = f1('test').f2().f3();
I have gotten one example to work, while another doesn't. I'll post those below. I always want to learn the first principle fundamentals of how something works so that I can build on top of it. Up to now, I've only had a cursory and loose understanding of how chaining works and I'm running into bugs that I can't troubleshoot intelligently.
What I know:
Functions have to return themselves, aka "return this;"
Chainable functions must reside in a parent function, aka in jQuery, .css() is a sub method of jQuery(), hence jQuery().css();
The parent function should either return itself or a new instance of itself.
This example worked:
var one = function(num){
this.oldnum = num;
this.add = function(){
this.oldnum++;
return this;
}
if(this instanceof one){
return this.one;
}else{
return new one(num);
}
}
var test = one(1).add().add();
But this one doesn't:
var gmap = function(){
this.add = function(){
alert('add');
return this;
}
if(this instanceof gmap) {
return this.gmap;
} else{
return new gmap();
}
}
var test = gmap.add();
In JavaScript Functions are first class Objects. When you define a function, it is the constructor for that function object. In other words:
var gmap = function() {
this.add = function() {
alert('add');
return this;
}
this.del = function() {
alert('delete');
return this;
}
if (this instanceof gmap) {
return this.gmap;
} else {
return new gmap();
}
}
var test = new gmap();
test.add().del();
By assigning the new gmap();to the variable test you have now constructed a new object that "inherits" all the properties and methods from the gmap() constructor (class). If you run the snippet above you will see an alert for "add" and "delete".
In your examples above, the "this" refers to the window object, unless you wrap the functions in another function or object.
Chaining is difficult for me to understand at first, at least it was for me, but once I understood it, I realized how powerful of a tool it can be.
Sadly, the direct answer has to be 'no'. Even if you can override the existing methods (which you probably can in many UAs, but I suspect cannot in IE), you'd still be stuck with nasty renames:
HTMLElement.prototype.setAttribute = function(attr) {
HTMLElement.prototype.setAttribute(attr) //uh-oh;
}
The best you could probably get away with is using a different name:
HTMLElement.prototype.setAttr = function(attr) {
HTMLElement.prototype.setAttribute(attr);
return this;
}
To "rewrite" a function, but still be able to use the original version, you must first assign the original function to a different variable. Assume an example object:
function MyObject() { };
MyObject.prototype.func1 = function(a, b) { };
To rewrite func1 for chainability, do this:
MyObject.prototype.std_func1 = MyObject.prototype.func1;
MyObject.prototype.func1 = function(a, b) {
this.std_func1(a, b);
return this;
};
Here's a working example. You just need to employ this technique on all of the standard objects that you feel need chainability.
By the time you do all of this work, you might realize that there are better ways to accomplish what you're trying to do, like using a library that already has chainability built in. *cough* jQuery *cough*
First, let me state that i am explaining this in my own words.
Method chaining is pretty much calling a method of the object being returned by another function/method. for example (using jquery):
$('#demo');
this jquery function selects and returns a jquery object the DOM element with the id demo. if the element was a text node(element), we could chain on a method of the object that was returned. for example:
$('#demo').text('Some Text');
So, as long as a function/method returns an object, you can chain a method of the returned object to the original statement.
As for why the latter don't work, pay attention to where and when the keyword this is used. It is most likely a context issue. When you are calling this, make sure that this is referring to that function object itself, not the window object/global scope.
Hope that helps.
Just call the method as var test = gmap().add();
as gmap is a function not a variable

Categories

Resources