Javascript Nested functions with toString - javascript

Can anyone please explain this code? This example is taken from javascript.info.
I don't understand, especially the f.toString = function(){ return sum} part.
function sum(a) {
var sum = a
function f(b) {
sum += b
return f
}
f.toString = function() { return sum }
return f
}
alert( sum(1)(2) ) // 3
alert( sum(5)(-1)(2) ) // 6
alert( sum(6)(-1)(-2)(-3) ) // 0
alert( sum(0)(1)(2)(3)(4)(5) ) // 15

I think the author of that snippet wanted to achieve one goal, that is, something like "faking" operator overloading which is possible in other languages.
Since sum returns a function reference, we could not go like
sum(5) + 5;
That would result in something weird like "function sum() { ... }5". That is because ECMAscript calls the .toString() method on objects when invoked in a Math operation. But since he overwrites the .toString() method returning sum (which is a number), it does work again.

All objects in javascript 'inherit' a field called toString that exists on the prototype of boject. After assignment toString exists as any other field on f. It is assigned a as a function, and can be invoked as such:

Basically, sum is a function that can be chained into multiple calls. toString is a method of the object that returns what should be shown if the object is used in a context that expects a string.
Personally, I think it'd be easier like this:
function sum() {
var l = arguments.length, i, a = 0;
for( i=0; i<l; i++) a += arguments[i];
return a;
}
alert(sum(1,2));
alert(sum(5,-1,2));
alert(sum(6,-1,-2,-3));
alert(sum(0,1,2,3,4,5));

Here is a snippet from MDN article about Function.toString
The Function object overrides the toString method inherited from
Object; it does not inherit Object.prototype.toString. For Function
objects, the toString method returns a string representation of the
object in the form of a function declaration. That is, toString
decompiles the function, and the string returned includes the function
keyword, the argument list, curly braces, and the source of the
function body.
JavaScript calls the toString method automatically when a Function is to be represented as a text value, e.g. when a function is
concatenated with a string.
So basically, what this "annoying" piece of code is doing is providing an implementation for Function.toString that will be used when when a string representation is required, i.e. when alert is called (alert takes a string as an argument).
For the rest of the code, it's just calling itself recursively to compute the sum of the arguments.

Related

JavaScript Function Parameters vs Object Methods

Can someone explain to me the difference of when to use a function by feeding your variables into the parenthesis, and when to tack the function on after the variable with a period, like using the toString() function?
example code
function addMe(a){
a = a+1;
return a;
}
var num = 1;
addMe(num);
num.toString();
I'm not actually sure if my syntax is correct, but I want to know when to feed a variable as a parameter, like how I feed the variable num, to the addMe function. And when to use the function .toString() by putting a period after the variable and typing out the function.
could I have done something like this- provided I built my function correctly?
var num = 1;
num.addMe();
Thanks for the help!
The first is used for simple 'stand alone' functions, while the latter is used for object methods. E.g a number object by default has a toString() method. Some object methods may also require parameters to be passed between the parentheses.
Variables (a function declaration is just a function stored in a variable) are looked up in the scope chain (going up to the next outer scope until a variable with the name is found):
let a = 1; // outer scope
{ // inner scope
console.log(a); // looked up in "inner scope", than "outer scope"
}
Properties of an object are looked up in the objects prototype chain, so if you do
a.b
then a gets looked up in the scopes as explained above, then b is accessed on the resulting object (everything is an object in JavaScript, except for "nothing" (undefined, null)) by looking up the prototype chain. For a simple object, the chain is quite short:
const a = { b: 1 }; // object -> Object.prototype
Here b will be found in the object itself. However all objects inherit from the Object.prototype object, so if you add a property to that (please don't):
Object.prototype.test = 1;
you can then look it up on every object, as the lookup traverses up the prototype chain, and reaches Object.prototype:
console.log({}.test); // 1
Now for numbers (like in your case), they inherit the Number.prototype so you could do:
Number.prototype.addMe = function() {
console.log(this);
};
// two dots are needed to distinguish it from numbers with a fraction (e.g. 1.2)
1..addMe();
That said, now addMe can be called on every number, everywhere in your code. While that might seems useful, it is actually a pain as you don't know where a certain method was added
1..whereDoIComeFrom()
that makes code unreadable and unstructured. Instead if you need a certain functionality multiple times, abstract it into a function, don't touch the native prototypes.
I assume that addMe is just a simplified example, if it isn't, read on:
If you pass an argument to a function in JavaScript, the value will be copied (it is a bit more complicated with non primitives (everything except numbers, booleans etc.)) into the parameter variable of the function called so here:
function addMe(a){
a = a+1;
console.log(a); // 2
return a;
}
var num = 1;
addMe(num);
console.log(num); // 1 ... ?
you actually got two variables (a and num), changing a does not change num. But as you return a you can do:
num = addMe(num);
which copies the value of num into a, then increases a by one and then copues the value of a back to num.
When you did var num = 1 you created a JavaScript object. It looks just like a number but you can think of everything in JavaScript as an object (simplification) and all these objects have different features. So a number has some features, a string has some other features, etc.
You mentioned one feature: toString. Another feature would be toLowerCase.
toString and toLowerCase are functions that come with JavaScript. These functions are then "put on" all of these objects for us to use.
I can have a string variable like
var text = 'MY TEXT'
var lowercaseText = text.toLowerCase()
console.log(lowercaseText) // my text
This code will work because it was decided that the toLowerCase function should work on strings
I can also have an array (list of items)
const list = ['A', 'B', 'C']
const answer = list.toLowerCase()
console.log(answer)
But this code won't work because toLowerCase doesn't work on arrays. So you get the following error message: list.toLowerCase is not a function.
Basically its saying: I don't know what toLowerCase means when used on this list variable (array).
In JavaScript this is called prototypes. Prototype is a way for JavaScript to get some feature from another. Basically: I have all kinds of functions, what object can use what functions. This is called the prototype chain.
In both cases you are using a function. addMe is a function you created and toString is a function in JavaScript that has been placed on objects through this prototype-chain.
Im not actually sure if my syntax is correct
Yes your syntax is correct. Your addMe function is the standard way to create a function in JavaScript.
But i want to know when to feed a variable as a parameter, like how i
feed the variable num, to the addMe function.
Just like you did, you define a function and parameters like you did.
..and when to use the function .toString() by putting a period after
the variable and typing out the function.
When you want to place your function on a object so that all instances of that object can you that object.
In most cases, espcially when you are starting out. You don't have to worry about these prototypes. The way you did.
function addMe(number) {
return number+1
}
const answer = addMe(1) //2
Is a standard way of defining a function and calling it.

Number vs new Number internal implementation

I understand that writing
var x = Number("7"); // makes a number, a primitive
var y = new Number("7"); // makes a Number object
and I'm aware of the usual cautions against option 2, but what is going on behind the scenes? I was under the impression if a function is a constructor, it should not return a value via a return statement: it just sets up its implicit object, this, and returns it.
So how come Number, String, and Boolean constructors are able to return either a primitive or an object? Does the JavaScript engine parse those expressions differently as a special feature in the language? Or can a programmer also "overload" a constructor function to either return a primitive or an object, depending on whether the constructor is called with/without "new"?
Using the constructor the Number object will be an object, using the function Number instead will return the conversion of an object to its representation as a numeric value.
So, basically within the Number object, the function is validating how was called. This is possible by checking the object this.
Something interesting is coercing the Number object to a numeric value as follow:
var x = Number("7"); // makes a number, a primitive
var y = new Number("7");
console.log(x === +y)
Go and read about the specification
https://www.ecma-international.org/ecma-262/5.1/#sec-15.7
It has nothing to do with syntax and there's nothing special about those constructors. The Number() and other constructors simply test to see whether this is bound before proceeding.
You can do it too:
function MyConstructor() {
if (!this) return new MyConstructor();
// stuff ...
}
Now calling MyConstructor() will behave exactly like new MyConstructor().
Also, a constructor can return something. If it returns an object, then that's used instead of the implicitly-constructed object that new creates. Thus you could also implement a "new-is-optional" constructor another way:
function MyConstructor() {
let object = this || Object.create(MyConstructor.prototype);
// stuff ...
return object;
}
So the Number() constructor takes a different tack. In most runtimes it may or may not actually be implemented as JavaScript, but if it were it might look something like this:
function Number(n) {
if (this) {
// invoked with "new"
this.fantasyValueSetter(n); // cannot really do this
return this;
}
return +n; // plain number primitive if not invoked with "new"
}

Why Is A Period Used To Call "toString()" On a number JavaScript

Why is it that when toString is called on a number it isn't called like a typical function. I would expect var num = 5; toString(num); but instead it is done like var num = 5; num.toString();. Why is a period used to call the function on the number rather than supplying the number as an argument? I know that periods are used to reference properties of an object but I can't see how that applies to this situation. Sorry if this is an easy question, but I am new to programming and I really want to understand the language before I continue.
In JavaScript, the . is used to access a property on an object. In this case, a Number has a property on it toString that is a function you can invoke.
var num = 5;
num.toString //function toString() { [native code] }
num.toString() //"5"
the function toString without anything preceding it is really a property on the window object, and is the equivalent of the following:
window.toString //function toString() { [native code] }
toString() on it's own is actually window.toString() which is Object.prototype.toString.
It does not take any arguments.
console.info(toString === window.toString)
console.info(window.toString())
What you may perceive as global, built-in functions are actually methods of the window instance.
The prototype of the number is defined https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toString.
If you use directly the toString, this means that you ask from the global scope to use the global toString ( window.toString()). The window is very generic to know how to convert a specific number to String.

JavaScript chained concatenation function?

No jQuery please!
The Web says that the native String.concat() and join() functions of JS are to be avoided because of their poor performance, and a simple for() loop of += assignments should work a lot faster.
So I'm trying to create a function in pure JavaScript that will concatenate strings. This is somewhat how I envision it:
I want a main function concatenate() that will concatenate all passed arguments and additionally insert a variable string after each concatenated argument, except for the last one.
If the main function is called by itself and without the chained .using() function, then that variable string should be an empty one, which means no separators in the result.
I want a chained sub-function .using() that will tell the main concatenate() function what certain string other than the default '' empty string to add after each concatenated segment.
In theory, it should work like this:
concatenate('a','b','c'); /* result: 'abc' */
concatenate('a','b','c').using('-'); /* result: 'a-b-c' */
I want to avoid having two separate functions, like concatenate() and concatenateUsing(), because the concatenateUsing() variant would then have to utilize a special constant argument (like arguments[0] or arguments[arguments.length-1]) as the injected separator and that would be terribly untidy. Plus, I would always forget which one it was.
I also want to avoid having a superceding Concatenate object with two separate sub-methods, like Concatenate.strings() and Concatenate.using() or similar.
Here are some of my failed attempts so far...
Attempt #1:
function concatenate()
{
var result="";
if(this.separator===undefined){var separator=false;}
for(var i=0; i<arguments.length; i++)
{result += arguments[i] + ((separator && (i<arguments.length-1))?separator:'');}
this.using=function(x)
{
this.separator=x;
return this;
}
return result;
}
So what I'm trying to do is:
check if the separator variable is undefined, this means it wasn't set from a sub-method yet.
If it's undefined, declare it with the value false for later evaluation.
Run the concatenation, and if separator has another value than false then use it in each concatenation step - as long as it's not the last iteration.
Then return the result.
The sub-method .using(x) should somewhere along the way set the
value of the separator variable.
Naturally, this doesn't work.
Attempt #2:
var concatenate = function()
{
var result="";
var separator="";
for(var i=0; i<arguments.length; i++)
{result += arguments[i] + ((separator && (i<arguments.length-1))?separator:'');}
return result;
}
concatenate.prototype.using=function(x)
{
this.separator=x;
return this;
}
It also doesn't work, I assume that when this is returned from the using() sub-method, the var separator="" of the main concatenate() function just overwrites the value with "" again.
I tried doing this 4 or 5 different ways now, but I don't want to bore you with all the others as well.
Does anyone know a solution for this puzzle?
Thanks a lot in advance!
What you are trying to do is impossible.
You cannot chain something to a method call that returns a primitive, because primitives do not have (custom) methods1.
And you cannot make the first function return different things depending on whether something is chained or not, because it doesn't know about its call context and has to return the result before the method call is evaluated.
Your best bet is to return an object that can be stringified using a custom toString method, and also offers that using thing. It would be something along the lines of
function concatenate() {
return {
args: Array.from(arguments), // ES6 for simplicity
using: function(separator) {
return this.args.join(separator);
},
toString: function() {
return this.args.join("");
}
};
}
console.log(String(concatenate('a','b','c')); // result: 'abc'
// alternatively, use ""+… or explicitly call the ….toString() method
console.log(concatenate('a','b','c').using('-')); // result: 'a-b-c'
1: No, you don't want to know workarounds.

JavaScript variable number of arguments to function

Is there a way to allow "unlimited" vars for a function in JavaScript?
Example:
load(var1, var2, var3, var4, var5, etc...)
load(var1)
Sure, just use the arguments object.
function foo() {
for (var i = 0; i < arguments.length; i++) {
console.log(arguments[i]);
}
}
In (most) recent browsers, you can accept variable number of arguments with this syntax:
function my_log(...args) {
// args is an Array
console.log(args);
// You can pass this array as parameters to another function
console.log(...args);
}
Here's a small example:
function foo(x, ...args) {
console.log(x, args, ...args, arguments);
}
foo('a', 'b', 'c', z='d')
=>
a
Array(3) [ "b", "c", "d" ]
b c d
Arguments
​ 0: "a"
​1: "b"
​2: "c"
​3: "d"
​length: 4
Documentation and more examples here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters
Another option is to pass in your arguments in a context object.
function load(context)
{
// do whatever with context.name, context.address, etc
}
and use it like this
load({name:'Ken',address:'secret',unused:true})
This has the advantage that you can add as many named arguments as you want, and the function can use them (or not) as it sees fit.
I agree with Ken's answer as being the most dynamic and I like to take it a step further. If it's a function that you call multiple times with different arguments - I use Ken's design but then add default values:
function load(context) {
var defaults = {
parameter1: defaultValue1,
parameter2: defaultValue2,
...
};
var context = extend(defaults, context);
// do stuff
}
This way, if you have many parameters but don't necessarily need to set them with each call to the function, you can simply specify the non-defaults. For the extend method, you can use jQuery's extend method ($.extend()), craft your own or use the following:
function extend() {
for (var i = 1; i < arguments.length; i++)
for (var key in arguments[i])
if (arguments[i].hasOwnProperty(key))
arguments[0][key] = arguments[i][key];
return arguments[0];
}
This will merge the context object with the defaults and fill in any undefined values in your object with the defaults.
It is preferable to use rest parameter syntax as Ramast pointed out.
function (a, b, ...args) {}
I just want to add some nice property of the ...args argument
It is an array, and not an object like arguments. This allows you to apply functions like map or sort directly.
It does not include all parameters but only the one passed from it on. E.g. function (a, b, ...args) in this case args contains
argument 3 to arguments.length
Yes, just like this :
function load()
{
var var0 = arguments[0];
var var1 = arguments[1];
}
load(1,2);
As mentioned already, you can use the arguments object to retrieve a variable number of function parameters.
If you want to call another function with the same arguments, use apply. You can even add or remove arguments by converting arguments to an array. For example, this function inserts some text before logging to console:
log() {
let args = Array.prototype.slice.call(arguments);
args = ['MyObjectName', this.id_].concat(args);
console.log.apply(console, args);
}
Although I generally agree that the named arguments approach is useful and flexible (unless you care about the order, in which case arguments is easiest), I do have concerns about the cost of the mbeasley approach (using defaults and extends). This is an extreme amount of cost to take for pulling default values. First, the defaults are defined inside the function, so they are repopulated on every call. Second, you can easily read out the named values and set the defaults at the same time using ||. There is no need to create and merge yet another new object to get this information.
function load(context) {
var parameter1 = context.parameter1 || defaultValue1,
parameter2 = context.parameter2 || defaultValue2;
// do stuff
}
This is roughly the same amount of code (maybe slightly more), but should be a fraction of the runtime cost.
While #roufamatic did show use of the arguments keyword and #Ken showed a great example of an object for usage I feel neither truly addressed what is going on in this instance and may confuse future readers or instill a bad practice as not explicitly stating a function/method is intended to take a variable amount of arguments/parameters.
function varyArg () {
return arguments[0] + arguments[1];
}
When another developer is looking through your code is it very easy to assume this function does not take parameters. Especially if that developer is not privy to the arguments keyword. Because of this it is a good idea to follow a style guideline and be consistent. I will be using Google's for all examples.
Let's explicitly state the same function has variable parameters:
function varyArg (var_args) {
return arguments[0] + arguments[1];
}
Object parameter VS var_args
There may be times when an object is needed as it is the only approved and considered best practice method of an data map. Associative arrays are frowned upon and discouraged.
SIDENOTE: The arguments keyword actually returns back an object using numbers as the key. The prototypal inheritance is also the object family. See end of answer for proper array usage in JS
In this case we can explicitly state this also. Note: this naming convention is not provided by Google but is an example of explicit declaration of a param's type. This is important if you are looking to create a more strict typed pattern in your code.
function varyArg (args_obj) {
return args_obj.name+" "+args_obj.weight;
}
varyArg({name: "Brian", weight: 150});
Which one to choose?
This depends on your function's and program's needs. If for instance you are simply looking to return a value base on an iterative process across all arguments passed then most certainly stick with the arguments keyword. If you need definition to your arguments and mapping of the data then the object method is the way to go. Let's look at two examples and then we're done!
Arguments usage
function sumOfAll (var_args) {
return arguments.reduce(function(a, b) {
return a + b;
}, 0);
}
sumOfAll(1,2,3); // returns 6
Object usage
function myObjArgs(args_obj) {
// MAKE SURE ARGUMENT IS AN OBJECT OR ELSE RETURN
if (typeof args_obj !== "object") {
return "Arguments passed must be in object form!";
}
return "Hello "+args_obj.name+" I see you're "+args_obj.age+" years old.";
}
myObjArgs({name: "Brian", age: 31}); // returns 'Hello Brian I see you're 31 years old
Accessing an array instead of an object ("...args" The rest parameter)
As mentioned up top of the answer the arguments keyword actually returns an object. Because of this any method you want to use for an array will have to be called. An example of this:
Array.prototype.map.call(arguments, function (val, idx, arr) {});
To avoid this use the rest parameter:
function varyArgArr (...var_args) {
return var_args.sort();
}
varyArgArr(5,1,3); // returns 1, 3, 5
Use the arguments object when inside the function to have access to all arguments passed in.
Be aware that passing an Object with named properties as Ken suggested adds the cost of allocating and releasing the temporary object to every call. Passing normal arguments by value or reference will generally be the most efficient. For many applications though the performance is not critical but for some it can be.
Use array and then you can use how many parameters you need. For example, calculate the average of the number elements of an array:
function fncAverage(sample) {
var lenghtSample = sample.length;
var elementsSum = 0;
for (var i = 0; i < lenghtSample; i++) {
elementsSum = Number(elementsSum) + Number(sample[i]);
}
average = elementsSum / lenghtSample
return (average);
}
console.log(fncAverage([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])); // results 5.5
let mySample = [10, 20, 30, 40];
console.log(fncAverage(mySample)); // results 25
//try your own arrays of numbers

Categories

Resources