Is this a functional declaration, expression, and object? - javascript

I'm learning JavaScript and am trying to learn the proper terms for what I am doing. There are so many ways to create a function.
I have created 3 examples that do the same thing, but the functions are created in completely different ways.
My questions are:
Are any one of these methods better than the other?
Why would I choose to do one way or another?
What is the last "object" method called?
What advice would you have to make this example better?
//EXAMPLE 1
// is this called function declaration?
function add( a, b ) {
return a + b;
}
function subtract( a, b ) {
return a - b;
}
function compute( a, b ) {
var sum = add( a, b );
var difference = subtract( a, b );
var total = sum + difference;
return total;
}
compute( 2, 3 ); //returns 4
//EXAMPLE 2
// is this called function expressions?
var add = function ( a, b ) {
return a + b;
};
var subtract = function ( a, b ) {
return a - b;
};
var compute = function ( a, b ) {
var sum = add( a, b );
var difference = subtract( a, b );
var total = sum + difference;
return total;
};
compute( 2, 3 ); //returns 4
//EXAMPLE 3
// what is this method called?
var calculator = {
add: function ( a, b ) {
return a + b;
},
subtract: function ( a, b ) {
return a - b;
},
compute: function ( a, b ) {
var sum = this.add( a, b );
var difference = this.subtract( a, b );
var total = sum + difference;
return total;
}
}
calculator.compute( 2, 3 ); //returns 4

is this called function declaration?
function add( a, b ) {
return a + b;
}
Yes.
is this called function expressions?
var add = function ( a, b ) {
return a + b;
};
Yes. Notice that only the function(…){…} part is the function expression, the rest is a normal assignment (variable declaration with initialiser, to be pedantic).
what is this method called?
… {
add: function ( a, b ) {
return a + b;
},
…
}
Again, it's a function expression. Used as a property value in an object literal here, to define a method.
Are any one of these methods better than the other?
Function declarations are preferred over assigning function expressions to variables (there are slight differences). You should use expressions only where you need them as an expression (e.g. in IIFEs, conditional assignments, property assignments, property definitions, return statements etc).

Function declaration:
function add(a,b) { return a+b; }
A function declaration is defined at parse time for a certain script block. It can be called anywhere in the block without producing an error:
(function() {
add(3,3) //The function block has already been parsed, add() is available
function add(a,b) { return a+b; }
})();
Function expressions:
var add = function(a,b) { return a+b; }
Function expressions assign a variable to an anonymous function. These are evaluated at run time and cannot be called before being declared.
(function() {
add(3,3) //Error: add() has not yet been defined.
var add = function(a,b) { return a+b; }
})();
Object Methods:
Methods, are functions that are a property of an object.
var obj = {
propert1: 'property1 value',
add: function(a,b) {
return a+b;
}
};
These may be called via obj.add(3,3), however not prior to declaring the object via an object literal or assignment of a method to a property.
Is there a preffered way?
Declaring functions via a function declaration offers flexibility. It may however lead to unexpected results, For example(raised functions):
(function returnVal() {
function getSomething() {
return 'foo';
}
return getSomething();
function getSomething() {
return 'bar';
}
})(); //returns 'bar'
The return of the function may appear unexpected, however functions are raised during parse-time, and getSomething() is overridden.
Rewriting the code using a function expression produces the desired result
(function returnVal() {
var getSomething = function() {
return 'foo';
}
return getSomething();
getSomething = function() {
return 'bar';
}
})(); //returns 'foo'
Object methods on the other hand act much like function expressions however they are accessible under the object's name.
var obj = {};
obj.foo = function() { /*code*/ }
obj.bar = function() { /*code*/ }
They act similarly to function expressions, however this groups code under the ownership of obj. For clarity you may wish to choose this.

Related

Need details on scope example

I'm learning about scope in JS and I'm stuck on an example:
function one() {
var a = 1;
console.log(a);
function two() {
var a = a + 2;
console.log(a);
}
two();
}
one();
Running this will output NAN.
Can you explain why it doesn't take variable a from function one() and instead chooses to define it again ? I know that var defines it again, but conidering it's a nested function why it doesn't use the variable from parent?
Thanks!
UPDATE:
As far as I've understood, and correct me if I'm wrong, same variable name can appear in different scope
function one() {
var a = 1;
console.log( a );
}
function two() {
var a = 2;
console.log( a );
}
one();
two();
Also I know that code in one scope can access variables of either that scope or any scope outside of it
function one() {
var a = 1;
function two() {
var b = 2;
console.log( a + b );
}
two();
console.log( a );
}
one();
That's why I get confused
I know that var defines it again, but conidering it's a nested function why it doesn't use the variable from parent?
Because...var defines it again, in a nested scope. That means the a within two is not the same a as within one; it's a different variable that shadows (hides) one's a, so two can't use it.
So now we know it's a different variable, let's look at why you get NaN from two's console.log: The line
var a = a + 2;
is treated like this:
var a;
a = a + 2;
and a newly-declared variable with no initializer has the value undefined by default. undefined + 2 is NaN.
If we change two to not shadow a, two can indeed use a:
function one() {
var a = 1;
console.log(a);
function two() {
var b = a + 2; // Note declaring b, and using a
console.log(b);
}
two();
}
one();

Why does returning this ECMAScript Harmony arrow function expression produce unexpected behavior?

I've been playing with the new ECMAScript 6 features and this question has to do with arrow functions. The following code is a simple functional composition method assigned to the Function object's prototype. It works perfectly well using a simple anonymous function but does not when using an arrow function instead.
Function.prototype.compose = function (bar) {
var foo = this;
return function () {
return foo(bar.apply(null, arguments));
};
};
var addFive = function (baz) {
return baz + 5;
};
var addTen = function (hello) {
return hello + 10;
};
var addFifteen = addFive.compose(addTen);
console.log(addFifteen(10));
http://jsfiddle.net/oegonbmn/
Function.prototype.compose = function (bar) {
var foo = this;
return () => foo(bar.apply(null, arguments));
};
var addFive = function (baz) {
return baz + 5;
};
var addTen = function (hello) {
return hello + 10;
};
var addFifteen = addFive.compose(addTen);
console.log(addFifteen(10));
http://www.es6fiddle.com/hyo32b2p/
The first one logs 25 correctly to the console whereas the second one logs function (hello) { return hello + 10; }105 which doesn't exactly tell me what I'm doing wrong.
I am not returning the value within the arrow function since it is supposed to implicitly return the very last statement (the first and last in this instance) and I suppose the issue at hand has something to do with the lexical scoping and the values of this, maybe. Can anyone explain?
Both this and arguments are not (re)bound in arrow functions, but instead lexically scoped. That is, you get whatever they are bound to in the surrounding scope.
In ES6, using arguments is deprecated anyway. The preferred solution is to use rest parameters:
Function.prototype.compose = function (bar) {
return (...args) => this(bar.apply(null, args));
};
or, in fact:
Function.prototype.compose = function (bar) {
return (...args) => this(bar(...args));
};

Cross module function scope? Where is it looking

Given the following:
include.js
module.exports = function() {
...
return {
func: function(val) {
return Function('return ' + val + ';');
}
}
}()
running.js
var outer = function() {
var include = require('./include.js');
var x = include.func('eq');
console.log(x(5, 5));
}
outer()
...where would I put function eq(x, y){ return x === y; } such that this would work? I'm currently getting an eval at <anonymous> on the line that calls the function; x(5,5) in this case.
It doesn't like when eq is in include.js or when it's in running.js ~ I know this is example code is taken from my project and made pretty ambiguous...but, if it's possible, where would that function go?
OR
...would it be better to define an object of functions where the keys are the name of the function?
defaultFuncs = {
'eq': function(x, y){ return x === y; }
}
The parent scope of functions created via new Function is the global scope, not any local or module scope. So
global.eq = function(a,b) { return a==b };
function func(name) { return Function("return "+name+";"); }
var x = func("eq");
var equals = x();
equals(5, 5) // true
should work.
...would it be better to define an object of functions where the keys are the name of the function?
Definitely yes.

How to bind function arguments without binding this?

In Javascript, how can I bind arguments to a function without binding the this parameter?
For example:
//Example function.
var c = function(a, b, c, callback) {};
//Bind values 1, 2, and 3 to a, b, and c, leave callback unbound.
var b = c.bind(null, 1, 2, 3); //How can I do this without binding scope?
How can I avoid the side-effect of having to bind the function's scope (e.g. setting this = null) as well?
Edit:
Sorry for the confusion. I want to bind arguments, then be able to call the bound function later and have it behave exactly as if I called the original function and passed it the bound arguments:
var x = 'outside object';
var obj = {
x: 'inside object',
c: function(a, b, c, callback) {
console.log(this.x);
}
};
var b = obj.c.bind(null, 1, 2, 3);
//These should both have exact same output.
obj.c(1, 2, 3, function(){});
b(function(){});
//The following works, but I was hoping there was a better way:
var b = obj.c.bind(obj, 1, 2, 3); //Anyway to make it work without typing obj twice?
I'm still new at this, sorry for the confusion.
Thanks!
You can do this, but best to avoid thinking of it as "binding" since that is the term used for setting the "this" value. Perhaps think of it as "wrapping" the arguments into a function?
What you do is create a function that has the desired arguments built into it via closures:
var withWrappedArguments = function(arg1, arg2)
{
return function() { ... do your stuff with arg1 and arg2 ... };
}(actualArg1Value, actualArg2Value);
Hope I got the syntax right there. What it does is create a function called withWrappedArguments() (to be pedantic it is an anonymous function assigned to the variable) that you can call any time any where and will always act with actualArg1Value and actualArg2Value, and anything else you want to put in there. You can also have it accept further arguments at the time of the call if you want. The secret is the parentheses after the final closing brace. These cause the outer function to be immediately executed, with the passed values, and to generate the inner function that can be called later. The passed values are then frozen at the time the function is generated.
This is effectively what bind does, but this way it is explicit that the wrapped arguments are simply closures on local variables, and there is no need to change the behaviour of this.
In ES6, this is easily done using rest parameters in conjunction with the spread operator.
So we can define a function bindArgs that works like bind, except that only arguments are bound, but not the context (this).
Function.prototype.bindArgs =
function (...boundArgs)
{
const targetFunction = this;
return function (...args) { return targetFunction.call(this, ...boundArgs, ...args); };
};
Then, for a specified function foo and an object obj, the statement
return foo.call(obj, 1, 2, 3, 4);
is equivalent to
let bar = foo.bindArgs(1, 2);
return bar.call(obj, 3, 4);
where only the first and second arguments are bound to bar, while the context obj specified in the invocation is used and extra arguments are appended after the bound arguments. The return value is simply forwarded.
In the native bind method the this value in the result function is lost. However, you can easily recode the common shim not to use an argument for the context:
Function.prototype.arg = function() {
if (typeof this !== "function")
throw new TypeError("Function.prototype.arg needs to be called on a function");
var slice = Array.prototype.slice,
args = slice.call(arguments),
fn = this,
partial = function() {
return fn.apply(this, args.concat(slice.call(arguments)));
// ^^^^
};
partial.prototype = Object.create(this.prototype);
return partial;
};
var b = function() {
return c(1,2,3);
};
One more tiny implementation just for fun:
function bindWithoutThis(cb) {
var bindArgs = Array.prototype.slice.call(arguments, 1);
return function () {
var internalArgs = Array.prototype.slice.call(arguments, 0);
var args = Array.prototype.concat(bindArgs, internalArgs);
return cb.apply(this, args);
};
}
How to use:
function onWriteEnd(evt) {}
var myPersonalWriteEnd = bindWithoutThis(onWriteEnd, "some", "data");
It's a bit hard to tell exactly what you ultimately want to do because the example is sort of arbitrary, but you may want to look into partials (or currying): http://jsbin.com/ifoqoj/1/edit
Function.prototype.partial = function(){
var fn = this, args = Array.prototype.slice.call(arguments);
return function(){
var arg = 0;
for ( var i = 0; i < args.length && arg < arguments.length; i++ )
if ( args[i] === undefined )
args[i] = arguments[arg++];
return fn.apply(this, args);
};
};
var c = function(a, b, c, callback) {
console.log( a, b, c, callback )
};
var b = c.partial(1, 2, 3, undefined);
b(function(){})
Link to John Resig's article: http://ejohn.org/blog/partial-functions-in-javascript/
Using LoDash you can use the _.partial function.
const f = function (a, b, c, callback) {}
const pf = _.partial(f, 1, 2, 3) // f has first 3 arguments bound.
pf(function () {}) // callback.
May be you want to bind reference of this in last but your code:-
var c = function(a, b, c, callback) {};
var b = c.bind(null, 1, 2, 3);
Already applied binding for instance this and later you can not change it.
What I will suggest that use reference also as a parameter like this:-
var c = function(a, b, c, callback, ref) {
var self = this ? this : ref;
// Now you can use self just like this in your code
};
var b = c.bind(null, 1, 2, 3),
newRef = this, // or ref whatever you want to apply inside function c()
d = c.bind(callback, newRef);
Use a protagonist!
var geoOpts = {...};
function geoSuccess(user){ // protagonizes for 'user'
return function Success(pos){
if(!pos || !pos.coords || !pos.coords.latitude || !pos.coords.longitude){ throw new Error('Geolocation Error: insufficient data.'); }
var data = {pos.coords: pos.coords, ...};
// now we have a callback we can turn into an object. implementation can use 'this' inside callback
if(user){
user.prototype = data;
user.prototype.watch = watchUser;
thus.User = (new user(data));
console.log('thus.User', thus, thus.User);
}
}
}
function geoError(errorCallback){ // protagonizes for 'errorCallback'
return function(err){
console.log('#DECLINED', err);
errorCallback && errorCallback(err);
}
}
function getUserPos(user, error, opts){
nav.geo.getPos(geoSuccess(user), geoError(error), opts || geoOpts);
}
Basically, the function you want to pass params to becomes a proxy which you can call to pass a variable, and it returns the function you actually want to do stuff.
Hope this helps!
An anonymous user posted this additional info:
Building on what has already been provided in this post -- the most elegant solution I've seen is to Curry your arguments and context:
function Class(a, b, c, d){
console.log('#Class #this', this, a, b, c, d);
}
function Context(name){
console.log('#Context', this, name);
this.name = name;
}
var context1 = new Context('One');
var context2 = new Context('Two');
function curryArguments(fn) {
var args = Array.prototype.slice.call(arguments, 1);
return function bindContext() {
var additional = Array.prototype.slice.call(arguments, 0);
return fn.apply(this, args.concat(additional));
};
}
var bindContext = curryArguments(Class, 'A', 'B');
bindContext.apply(context1, ['C', 'D']);
bindContext.apply(context2, ['Y', 'Z']);
Well for the exemple you gave, this will do
var b= function(callback){
return obj.c(1,2,3, callback);
};
If you want to guarenty enclosure of the parameters :
var b= (function(p1,p2,p3, obj){
var c=obj.c;
return function(callback){
return c.call(obj,p1,p2,p3, callback);
}
})(1,2,3,obj)
But if so you should just stick to your solution:
var b = obj.c.bind(obj, 1, 2, 3);
It's the better way.
Simple like that?
var b = (cb) => obj.c(1,2,3, cb)
b(function(){}) // insidde object
More general solution:
function original(a, b, c) { console.log(a, b, c) }
let tied = (...args) => original(1, 2, ...args)
original(1,2,3) // 1 2 3
tied(5,6,7) // 1 2 5
I'm using this function:
function bindArgs(func, ...boundArgs) {
return function (...args) {
return func(...boundArgs, ...args);
};
}
// use
const deleteGroup = bindArgs(this.props.deleteGroup, "gorupName1");
Why not use a wrapper around the function to save this as mythis ?
function mythis() {
this.name = "mythis";
mythis = this;
function c(a, b) {
this.name = "original";
alert('a=' + a + ' b =' + b + 'this = ' + this.name + ' mythis = ' + mythis.name);
return "ok";
}
return {
c: c
}
};
var retval = mythis().c(0, 1);
jQuery 1.9 brought exactly that feature with the proxy function.
As of jQuery 1.9, when the context is null or undefined the proxied function will be called with the same this object as the proxy was called with. This allows $.proxy() to be used to partially apply the arguments of a function without changing the context.
Example:
$.proxy(this.myFunction,
undefined /* leaving the context empty */,
[precededArg1, precededArg2]);
Jquery use case:
instead:
for(var i = 0;i<3;i++){
$('<input>').appendTo('body').click(function(i){
$(this).val(i); // wont work, because 'this' becomes 'i'
}.bind(i));
}
use this:
for(var i = 0;i<3;i++){
$('<input>').appendTo('body').click(function(e){
var i = this;
$(e.originalEvent.target).val(i);
}.bind(i));
}

How can I access local scope dynamically in javascript?

If you want to use global functions and variable dynamically you can use:
window[functionName](window[varName]);
Is it possible to do the same thing for variables in the local scope?
This code works correctly but currently uses eval and I'm trying to think of how else to do it.
var test = function(){
//this = window
var a, b, c; //private variables
var prop = function(name, def){
//this = window
eval(name+ ' = ' + (def.toSource() || undefined) + ';');
return function(value){
//this = test object
if ( !value) {
return eval('(' + name + ')');
}
eval(name + ' = value;')
return this;
};
};
return {
a:prop('a', 1),
b:prop('b', 2),
c:prop('c', 3),
d:function(){
//to show that they are accessible via to methods
return [a,b,c];
}
};
}();
>>>test
Object
>>>test.prop
undefined
>>>test.a
function()
>>>test.a()
1 //returns the default
>>>test.a(123)
Object //returns the object
>>>test.a()
123 //returns the changed private variable
>>>test.d()
[123,2,3]
To answer your question, no, there is no way to do dynamic variable lookup in a local scope without using eval().
The best alternative is to make your "scope" just a regular object [literal] (ie, "{}"), and stick your data in there.
No, like crescentfresh said. Below you find an example of how to implement without eval, but with an internal private object.
var test = function () {
var prv={ };
function prop(name, def) {
prv[name] = def;
return function(value) {
// if (!value) is true for 'undefined', 'null', '0', NaN, '' (empty string) and false.
// I assume you wanted undefined. If you also want null add: || value===null
// Another way is to check arguments.length to get how many parameters was
// given to this function when it was called.
if (typeof value === "undefined"){
//check if hasOwnProperty so you don't unexpected results from
//the objects prototype.
return Object.prototype.hasOwnProperty.call(prv,name) ? prv[name] : undefined;
}
prv[name]=value;
return this;
}
};
return pub = {
a:prop('a', 1),
b:prop('b', 2),
c:prop('c', 3),
d:function(){
//to show that they are accessible via two methods
//This is a case where 'with' could be used since it only reads from the object.
return [prv.a,prv.b,prv.c];
}
};
}();
I think you actually sort of can, even without using eval!
I might be wrong so please correct me if I am, but I found that if the private variables are declared inside the local scope as arguments, instead of using var, i.e:
function (a, b, c) { ...
instead of
function () { var a, b, c; ...
it means that those variables/arguments, will be bound together with the function's arguments object if any values are given to them in the function's invocation, i.e:
function foo (bar) {
arguments[0] = 'changed...';
console.log(bar); // prints 'changed...'
bar = '...yet again!';
console.log(arguments[0]); // prints '..yet again!'
}
foo('unchanged'); // it works (the bound is created)
// logs 'changed...'
// logs '...yet again!'
foo(undefined); // it works (the bound is created)
// logs 'changed...'
// logs '...yet again!'
foo(); // it doesn't work if you invoke the function without the 'bar' argument
// logs undefined
// logs 'changed...'
In those situations (where it works), if you somehow store/save the invoked function's arguments object, you can then change any argument related slot from arguments object and the changes will automatically be reflected in the variables themselves, i.e:
// using your code as an example, but changing it so it applies this principle
var test = function (a, b, c) {
//this = window
var args = arguments, // preserving arguments as args, so we can access it inside prop
prop = function (i, def) {
//this = window
// I've removed .toSource because I couldn't apply it on my tests
//eval(name+ ' = ' + (def.toSource() || undefined) + ';');
args[i] = def || undefined;
return function (value) {
//this = test object
if (!value) {
//return eval('(' + name + ')');
return args[i];
}
//eval(name + ' = value;');
args[i] = value;
return this;
};
};
return {
a: prop(0, 1),
b: prop(1, 2),
c: prop(2, 3),
d: function () {
// to show that they are accessible via to methods
return [a, b, c];
}
};
}(0, 0, 0);
If the fact that you can pass the values as arguments into the function annoys you, you can always wrap it with another anonymous function, that way you really don't have any access to the first defined values passed as arguments, i.e:
var test = (function () {
// wrapping the function with another anomymous one
return (function (a, b, c) {
var args = arguments,
prop = function (i, def) {
args[i] = def || undefined;
return function (value) {
if (!value) {
return args[i];
}
args[i] = value;
return this;
};
};
return {
a: prop(0, 1),
b: prop(1, 2),
c: prop(2, 3),
d: function () {
return [a, b, c];
}
};
})(0, 0, 0);
})();
Full Dynamic Access Example
We can map all argument variable names into an array by getting the function itself (arguments.callee) as a string, and filtering its parameters using a regex:
var argsIdx = (arguments.callee + '').replace(/function(\s|\t)*?\((.*?)\)(.|\n)*/, '$2').replace(/(\s|\t)+/g, '').split(',')
Now with all the variables in an array, we can now know the corresponding variable name for each function's arguments slot index, and with that, declare a function (in our case it's prop) to read/write into the variable:
function prop (name, value) {
var i = argsIdx.indexOf(name);
if (i === -1) throw name + ' is not a local.';
if (arguments.hasOwnProperty(1)) args[i] = value;
return args[i];
}
We can also dynamically add each variable as a property, like in the question's example:
argsIdx.forEach(function (name, i) {
result[name] = prop.bind(null, name);
});
Finally we can add a method to retrieve variables by name (all by default), and if true is passed as the first argument, it returns the hard-coded array with all the variables by their identifiers, to prove that they are being changed:
function props (flgIdent) {
var names = [].slice.call(arguments.length > 0 ? arguments : argsIdx);
return flgIdent === true ? [a, b, c, d, e, f] : names.map(function (name) {
return args[argsIdx.indexOf(name)];
});
}
The prop and props functions can be made available as methods inside the returned object, in the end it could look something like this:
var test = (function () {
return (function (a, b, c, d, e, f) {
var argsIdx = (arguments.callee + '').replace(/function(\s|\t)*?\((.*?)\)(.|\n)*/, '$2').replace(/(\s|\t)+/g, '').split(','),
args = arguments,
result = {
prop: function (name, value) {
var i = argsIdx.indexOf(name);
if (i === -1) throw name + ' is not a local.';
if (arguments.hasOwnProperty(1)) args[i] = value;
return args[i];
},
props: function (flgIdent) {
var names = [].slice.call(arguments.length > 0 ? arguments : argsIdx);
return flgIdent === true ? [a, b, c, d, e, f] : names.map(function (name) {
return args[argsIdx.indexOf(name)];
});
}
};
args.length = argsIdx.length;
argsIdx.forEach(function (name, i) {
result[name] = result.prop.bind(null, name);
});
return result;
})(0, 0, 0, 0, 0, 0);
})();
Conclusions
It's impossible to read/write a function's local scope variable without eval, but if those variables are function's arguments and if they're given values, you can bound those variable identifiers to the function's arguments object and indirectly read/write into them from the arguments object itself.
Hopefully I'm not over-simplifying, but what about something as simple as using an object?
var test = {
getValue : function(localName){
return this[localName];
},
setValue : function(localName, value){
return this[localName] = value;
}
};
>>> test.a = 123
>>> test.getValue('a')
123
>>> test.a
123
>>> test.setValue('b', 999)
999
>>> test.b
999

Categories