I am trying to override a toString() method, but getting into difficulties.
Already looked here and here, but still no luck.
My code is as follows:
var Foo = function(arg) {
// some code here...
return function (a, b, c) {
// return function code...
};
};
Foo.prototype.toString = function () {
return "string representation of function";
};
exports.bar(arg) {
return Foo(arg);
};
In another module:
var mod = require('the-module-from-above');
console.log(mod.bar().toString()); // prints return function source code.
My question is, how come my toString() function isn't called, and how can I make it get called?
thank you.
You only set things on a function's prototype if you're using the function as a constructor with new. Since you don't appear to be doing that here, you need to set the toString function on the actual function you return.
function fooToString() {
return "string representation of function";
}
var Foo = function(arg) {
// some code here...
var ret = function (a, b, c) {
// return function code...
};
ret.toString = fooToString;
return ret;
};
You could also add the toString function when you actually create the object in the bar function, if you'd prefer to do that.
exports.bar(arg) {
var foo = Foo(arg);
foo.toString = fooToString;
return foo;
};
Related
I'm trying to create an object using constructor pattern and also define properties using Object.defineProperty.
function random (a,b,c) {
var sample = null;
this.a = a;
this.b = b;
if(b && c){
this.sample(b,c);
}
Object.defineProperty(random, 'sample', {
get: function(){
console.log(b);
}
});
};
var foo = new random(10,1,2);
This throws an error: Uncaught TypeError: object is not a function.
What am I doing wrong ? Please Help.
There are several issues:
You reference sample before it is defined
You define sample on the constructor (random), but it should be on this.
There was a closing parenthesis missing.
You call sample like a function, but you had not defined it as one. The function in defineProperty is the getter, not the method itself. If you want to code it like this, you need the getter to return your method.
Check this corrected code with comments:
function random (a,b,c) {
var sample = null;
this.a = a;
// First define, then call:
// Define on this, not on random:
Object.defineProperty(this, 'sample', {
get: function() {
// must return a function
return function (b) {
console.log(b);
};
}
}); // <-- missing bracket
// Moved after defineProperty:
if(b && c) {
this.sample(b,c); // note that you don't use the second argument
}
}
console.log(new random(1,2,3));
Learning how to write JS Fn that accepts an unknown number of arguments.
function foo(a,b,c,d){
//do something
//return something
}
var bar = function () {
var arg = Array.from(arguments);
var lastIndx = arg.length;
var parArray = arg.slice(1,lastIndx);
var argMnts = arguments[0];
return arguments[0].apply(this, parArray);
};
calling bar thus works:
bar(foo,1,4,3,7);
calling it like so:
var tester = bar(foo,1,4,3,7);
tester();
results in: tester is not a function
From my research I suspected it might have to do with the scope of "this" or arguments so I assigned their values to variables, subbed the vars, and the result was the same.
Some insight would be immensely appreciated.
In your example, calling bar() returns whatever the results of calling foo(...) is. So, if you want to be able to do this:
var tester = bar(foo,1,4,3,7);
tester();
Then, foo(...) has to return another function that can get assigned to tester and can then get called again.
If, instead of the way it is above, if you don't want bar(foo, ...) to actually call foo(), but want it to return a function that will then call foo() with the appropriate arguments, you can change bar() to this:
var bar = function () {
var args = Array.from(arguments);
var fn = args.shift();
var self = this;
return function() {
return fn.apply(self, args);
}
};
var tester = bar(foo,1,4,3,7);
tester();
Here, bar() returns a function, that (when called) will call foo().
Or, with the right ES6 support, you could use rest parameters;
var bar = function (fn, ...args) {
var self = this;
return function() {
return fn.apply(self, args);
}
};
or, you could use .bind() with rest parameters and the spread operator:
var bar = function (fn, ...args) {
return fn.bind(this, ...args);
};
I was watching a Pluralsight video from Douglas Crockford: http://pluralsight.com/training/Courses/TableOfContents/javascript-good-parts
In this video he goes through a number of interesting exercises to demonstrate some javascript principals.
When he gets to the 'demethodize' function you basically have the following code sample:
function add(x,y){
return x + y;
}
//add(1,2) => 3
function methodize(fn){
return function(x){
return fn(this, x);
};
};
Number.prototype.Add = methodize(add);
//(1).Add(2) => 3
function demethodize (fn){
return function(x,y){
return fn.call(x,y);
};
}
var newAdd = demethodize(Number.prototype.Add);
// newAdd(1,2) => 3
Note that this 'demethodize' function is for binary functions only.
My question is that, according to my understanding, the following should result in an equivalent 'demethodise' functions:
function demethodize (fn){
return fn.call;
}
or
var demethodize = Number.prototype.Add.call;
But these functions do not work (given the same binary function requirement)!
Why is this?
Please help me fill the gap in my understanding.
I had thought that if I had a binary function whose implementation contained another binary function call with the same arguments passed to the inner function, then using the inner function call directly would be equivalent.
The result of your demethodize function is the Function.prototype.call function - not bound to your fn, i.e. with no this value (which it had if it was called as fn.call(…)). You can however use the bind method to fix that:
function demethodize(fn) {
return Function.prototype.call.bind(fn);
}
// or long:
function demethodize(fn) {
return function(context/*, args... */) {
var args = Array.prototype.slice.call(arguments, 1);
return fn.apply(context, args);
// equivalent (for binary functions) to
return fn.call(context, args[0]);
// ^^^^^^ is a method invocation here
};
}
Because call doesn't know on which function it is supposed to be called. Have a look at the MDN documentation for how this works.
It's the same as
var foo = {bar: function() { console.log(this); }};
foo.bar(); // logs foo
var bar = foo.bar;
bar(); // logs window
You changed the way how .call is executed and with that you changed what this refers to.
I came across this syntax in "Hey Underscore, You're Doing it Wrong" JavaScript talk (4:15). I would like to know what it means.
var add = function(x,y){
return x + y;
}.autoCurry();//What is happening in this line.
First let's looks at what curry and autocurry actually do. I've annotated the source of these two functions (originally found in the wu.js library):
////
// Type:
//
// ((a,b, ... c) -> d) -> a -> b -> ... -> c -> d
//
// Example:
//
// function add(a, b) { return a + b; }
// add2 = curry(add, 2)
// add2(3)
// // 5
function curry(fn /* variadic number of args */) {
var args = Array.prototype.slice.call(arguments, 1);
function f() { return fn.apply(this, args.concat(toArray(arguments))); }
return f;
}
////
// Example:
//
// function add(a, b) { return a + b; }
// autoCurry(add);
//
// add(2)(3)
// // 5
//
// add(2, 3)
// // 5
function autoCurry(fn, numArgs) {
numArgs = numArgs || fn.length;
function f() {
if (arguments.length < numArgs)
{
return numArgs - arguments.length > 0 ?
autoCurry(curry.apply(this, [fn].concat(toArray(arguments))),
numArgs - arguments.length) :
curry.apply(this, [fn].concat(toArray(arguments)));
}
else
{
return fn.apply(this, arguments);
}
}
f.toString = function() { return fn.toString(); };
f.curried = true;
return f;
}
In other words,
autoCurry(add)
Takes a function that takes two arguments and returns a number, and returns a function A that takes a single argument and returns a function B. Where B is a function that takes a single argument and returns a number:
add(1) -> returns a function add1(), which itself takes a single argument.
Next, the speaker in that talk does the following:
Function.prototype.autoCurry = function(n) { return autoCurry(this, n); }
This simply applies the autoCurry method to any given function (self) so that
var add = function(x,y){
return x + y;
}.autoCurry();
Has the same effect as:
var add = function(x,y) { return x + y; };
add = autoCurry(add)
Well, I can't tell you what, exactly autoCurry is doing... ...but what I can tell you is this:
They've modified the Function constructor's prototype Function.prototype.autoCurry = function () { };
Every new function you make on that page will now have access to this method as one of its properties.
var myFunc = function () { return true; }; myFunc.autoCurry();
You can chain statements together, happily in JS.
var myObj = { run : function () { } }, result = myObj.run(); is the same as
var result = { run : function () { } }.run();, as long as you don't care about myObj after.
So:
You are creating a function, and as soon as it's created, you're running a method on it, and the return statement of that method (the last thing in the chain) is being saved to the variable.
Now, currying is a form of taking a function and wrapping it in other functions, which allows you to call it with only a portion of the arguments needed.
function add_two_numbers = function (x, y) { return x + y; }
Currying would allow you to do this:
var save_x_for_later = curry(add_two_numbers),
save_y_and_add = save_x_for_later(3),
result = save_y_and_add(5);
result; // 8
As for your new title, the answer is the following:
You will get an error thrown in your face:
.autoCurry() is not a part of the language.
It was written, by hand, and put on the Function.prototype as Function.prototype.autoCurry = function () { }
I could go into an implementation of currying, but there's a lot of stuff to wrap your head around, if you haven't done much functional programming, or if "lambda" is a head-scratching term.
In JavaScript, a function instantiation expression:
function name( arg1, arg2, ... ) { /* code */ }
creates a function and results in a reference to the function object. Thus, the .autoCurry() is a reference to a property on that object, which is apparently assumed to be a function.
I suspect that the example you're looking at has some other code that adds "autoCurry" to the Function prototype object. That way, every function object has access to that function as the "autoCurry" property.
I've got a JS object that looks like so:
return {
foo: function() {
return this.bar();
},
bar: function() {
return 1;
}
}
Why do I keep getting a TypeError: this.bar is not a function logged in FireBug? What's the proper way to reference the bar() method from foo() in the same object?
Update
So I've posted a fiddle with the whole code here. The return call is actually part of a RequireJS define. Let me know if any further clarification is required.
It depends on how it is called; If for instance theObject.foo is passed as callback to another function (e.g. jQuery(x).on("click", theObject.foo)), the this context will probably be lost.
A way to enforce that bar calls foo is to make a closure. Change the function that returns the object as:
function thatReturnsTheOject() {
var ret = {
foo: function() {
return ret.bar(); // <---- Using `ret` not `this`
},
bar: function() {
return 1;
}
};
return ret;
}
Another way, more complex but may result in a more familiar language usage is this:
function thatReturnsTheOject() {
var ret = {};
ret.foo = (function() {
return this.bar(); // <---- Using `this` again
}).bind(ret); // <---- but note the `bind()`
ret.bar = function() {
return 1;
};
return ret;
}