can a function reference itself in javascript? - javascript

Suppose we define a function that simply increments its input by some stored value dd:
var obj={}
obj.dd=1
obj.f=function(x){
return x+this.dd
}
Alternatively you could create a closure for dd as follows but this would create a static increment as opposed to one that could be altered later:
var dd=1
var f=function(x){
return x+dd
}
We could alternatively store dd in the function itself:
var obj={}
obj.f=function(x){
return x+this.f.dd
}
obj.f.dd=1
I am curious as to whether it is possible for a function to retrieve a variable attached to itself without going through a parent object, something like a self keyword that would refer to the function itself and would allow the following:
var f=function(x){
return x+self.dd
}
f.dd=1
I know it is unnecessary to do such a thing but I think it would be cool if you could.

You can give function literals a name:
var f = function me(x) {
return x + me.dd;
};
f.dd = 1;
This doesn’t work properly in older versions of IE/JScript, though, as me and f don’t reference the same object. The (deprecated and not usable in strict mode) alternative is arguments.callee:
var f = function(x) {
return x + arguments.callee.dd;
};
f.dd = 1;
Also, your note about the closure isn’t quite right; it can be altered later, even through another function:
var dd = 1;
var f = function(x) {
return x + dd;
};
var setdd = function(_dd) {
dd = _dd;
};

A function is an object. If you reference the var holding the function:
var f = function (x) {
return x + f.dd
};
f.dd = 1;
alert(f(1));
result: 2
If the function is named, you can do the same:
function foo(x) {
return x + foo.dd;
}
foo.dd = 1;
alert(foo(1));
result: 2

Related

Can a function read the binding of another function?

I'm currently learning javascript and I would appreciate some help.
I've been playing around trying to create a program that would multiply two numbers without using the * operator. I already found an easier way to do it than my approach but I'd like to know why the code I wrote doesn't work:
function addToItself(a) {
a = a + a;
return a;
}
function times(b) {
for (count = 0; count < b; count++) {
addToItself(a)
}
return a;
}
function multiply (x, y) {
a = x;
times(y);
}
let output = multiply(5, 2);
alert(output);
Is it not working because the binding "a" in the addToItself function has a local scope and the multiply function can't read it or is it something else?
Thanks a lot in advance!
The issue is with the scope of each variable. In JavaScript, a variable declated within a function is scoped to that function. This means that a variable declared within a function can only be accessed within the function. Scopes are nested, so a variable declared globally is accessible inside a function too, though that's often discouraged.
Additionally, function arguments (such as a in addToItself and b in times) are treated like variables scoped to the function.
I would advise looking at the MDN docs for "scope" and familiarizing yourself with how variables are scoped in JavaScript.
I have included a fixed version of your code is below, for reference:
function addToItself(a) {
// I used a new variable here since reassigning to an argument is discouraged
const twoA = a + a;
return twoA;
}
console.log('5 + 5 = ' + addToItself(5));
function times(value, times) {
let temp = 0;
for (let count = 0; count < times; count++) {
temp += value;
}
return temp;
};
console.log('5 * 5 = ' + times(5, 5));
No you can't read variable inside another function, there are easier way, like
function multiply(x, y) {
var result = 0;
for (var count = 0; count < y; count++) {
result += x
}
return result;
}
console.log("5 * 2 = " + multiply(5, 2));

Closures: Scope Chain Variables - Not sure how variables link up

Really new to Javascript. This code is taken from MDN.
// global scope
var e = 10;
function sum(a){
return function sum2(b){
return function sum3(c){
// outer functions scope
return function sum4(d){
// local scope
return a + b + c + d + e;
}
}
}
}
var s = sum(1);
var s1 = s(2);
var s2 = s1(3);
var s3 = s2(4);
console.log(s3) //log 20
When I try to input different variable names (EX below) they don't seem to work and I don't understand how everything links up together to spit out the answer 20.
// global scope
var e = 10;
function sum(a){
return function sum2(b){
return function sum3(c){
// outer functions scope
return function sum4(d){
// local scope
return a + b + c + d + e;
}
}
}
}
var w = sum(1);
var x = s(2);
var y = s1(3);
var z = s2(4);
console.log(s3) //log 20
When I change it to this it also does not work. The console tells me that sa is not defined
// global scope
var e = 10;
function sm(a){
return function sa(b){
return function sb(c){
// outer functions scope
return function sc(d){
// local scope
return a + b + c + d + e;
}
}
}
}
var s = sm(1);
var s1 = sa(2);
var s2 = sb(3);
var s3 = sc(4);
console.log(sc) //log 20
I can keep throwing out more examples that don't work. Someone, please help me understand how the first example works.
function sm(a){
return function sa(b){
return function sb(c){
// outer functions scope
return function sc(d){
// local scope
return a + b + c + d + e;
}
}
}
}
The function sm is taking one argument and is returning a function which takes one argument. The function sm returns is not named sb. Try to think of it as the return value of sm .
So, when you do
var s = sm(1);
The returned function is stored in the variable s
Now if you want to run the second function (sa inside sm) you need to invoke s.
var s1 = s(2);
The returned function (sb) is stored inside varibale s1.
Similarly,
var s2 = s1(3);
var s3 = s2(4);
console.log(s3); // 20

Object function scope

factory(n) returns objects with functions.
func1 function definition creates its own scope, and x inside this function references x = n + ''.
But func2 is a reference and the scope is wrong.
Is there a way to return an object from create so its functions were references (not separate definitions)?
Actually, I'm fine with func1 approach while function definition footprint is small. If it is a complex function it would be better not to clone this function into every object comming from factory(n). inner_func may not use this, it is simple function. Also I want to avoid new and this.
var factory = (function(){
var x = '!';
return function create(n){
var x = n + '';
return {
func1: function(y){return inner_func(x, y); },
/* vs */
func2: inner_func_api
}
}
function inner_func_api(y){ return inner_func(x, y); }
function inner_func(a, b){ return a + b; }
}());
var f1 = factory(2);
var f2 = factory(3);
var f1_func1 = f1.func1(4);
var f2_func1 = f2.func1(5);
var f1_func2 = f1.func2(4);
var f2_func2 = f2.func2(5);
console.log(f1_func1, f2_func1); //24 35
console.log(f1_func2, f2_func2); //!4 !5
You could define that function separately from the object initializer on the return statement:
var factory = (function(){
var x = '!';
return function create(n){
var x = n + '';
function func1(y) {
return inner_func(x, y);
}
return {
func1: func1,
/* vs */
func2: inner_func_api
}
}
function inner_func_api(y){ return inner_func(x, y); }
function inner_func(a, b){ return a + b; }
}());
However, it makes no practical difference, and it doesn't matter how big or complicated that function is. Function instances do take up space, but the code for the function is constant (immutable) and doesn't need to be part of every Function object created from the same piece of source code.

Can I pass parameter like reference

I need function change to change variables and return back to Tst1. I expect to get in console:
5
aaa
but have unchanged ones:
6
bbb
My functions:
function change ( aa,bb )
{
aa=5;
bb="aaa";
}
function Tst1()
{
aa=6;
bb="bbb";
change(aa,bb);
console.log (aa);
console.log (bb);
}
One way is to move change() into the function test(). Then it shares the same variables as the calling scope.
'use strict';
function test() {
function change() {
aa = 6;
bb = 76;
}
var aa = 5,
bb = 6;
change();
document.write(aa + " " + bb);
}
test();
JavaScript is like java in that primitives are never passed by reference but objects are always passed by reference. You need to wrap your data in an object and pass that instead:
function change (aa, bb)
{
aa.value = 5;
bb.value = "aaa";
}
function Tst1()
{
aa = { value: 6 };
bb = { value: "bbb" };
change(aa, bb);
console.log (aa.value); // outputs 5
console.log (bb.value); // outputs aaa
}
or you can play with global variable, but it is not a good practice.
var aa,bb;
function change(){
aa=6;
bb=76;
}
function test(){
aa = 5;
bb = 6;
change();
console.log(aa + " " + bb);
}
test();
Short answer: NO, you can't pass primitive parameters by reference in JS.
One alternative solution to the presented here is to return the result values as array of items:
function change ( aa,bb )
{
aa=5;
bb="aaa";
return [aa, bb];
}
function Tst1()
{
aa=6;
bb="bbb";
result = change(aa,bb);
aa = result[0];
bb = result[1];
document.writeln(aa);
document.writeln(bb);
}
Tst1();

Is there a better way to bring all scoped variables of one function into another?

Please consider the following code:
<html>
<head>
<script type="text/javascript">
function a(){
var v = 9;
var w = 2;
var x = 7;
var template = '{w} + {x} = {v}';
var func = eval('(' + c.toString() + ')');
func(template);
}
function b(){
var v = 1;
var y = 'hello';
var z = 'world';
var template = '{v}. {y} {z}';
var func = eval('(' + c.toString() + ')');
func(template);
}
function c(template){
var re = /{(.+?)}/;
var match = template.match(re);
while (match != null){
template = template.replace(re, eval(match[1]));
match = template.match(re);
}
alert(template);
}
</script>
</head>
<body>
<input type="button" value="a" onclick="a()"/><br/>
<input type="button" value="b" onclick="b()"/><br/>
</body>
</html>
This code has two functions (a and b) and a parsing function c that receives a string template as parameter and parses it, using variables that are scoped in the calling function (a or b).
This means that function c has to 'know' all the variables that are known to whichever function was calling it.
What I want is for c to 'know' all the variables in the scope of its caller.
My solution was this line of code in a and b:
var func = eval('(' + c.toString() + ')');
What this does is redefine c as func inside the calling function, so in effect making it a sub function of the caller and thus bringing it into the same scope.
This solution works great, but the problem with it is that it's ugly. I have to turn c into a string and re-eval it to a function every time I want to use it. I'm hoping someone can suggest a better solution, if such exists.
I don't want to pass all the variables as parameters to c because:
The template to parse can be very big and include anywhere from1 to dozens of variables.
If I pass all the variables as parameters to c and access them using the arguments array in c it means I have to use array notation inside the template which is bad practice for obvious reasons.
Putting all the variables into a hash map object and passing that object as parameter to c is possible, but makes for a huge coding overhead to create this hash map from the caller's variables before any call to c.
Note:
Please don't bother pointing out to me that the parsing function is not perfect, it's just a simplified example of my actual code.
You're overcomplicating things. You can eliminate the need to cross scopes by packing your replacement values as an object rather than as individual variables, and using the g flag and a replacement function allow you to greatly simplify c(). Give this a try:
function a(){
var values = {
v: 9,
w: 2,
x: 7
};
func(c('{w} + {x} = {v}', values));
}
function b(){
var values = {
v: 1,
y: 'hello',
z: 'world'
};
func(c('{v}. {y} {z}', values));
}
function c(template, values) {
return template.replace(/{(.*?)}/g, function(match) {
return values[match[1]];
});
}
After playing with it for a while, this is the closest I've been able to come to passing the local scope into another function. It's seriously hacky, involves a fair bit of code duplication, and still needs eval() (though not as much), but it may be what you're looking for.
Basically, this involves declaring all of your local variables as function parameters (instead of using var statements) so that their names can be extracted by converting the function back to source via .toString(). These parameters are not supplied when calling a() and b()!
(Note that the c() function here is identical to the one in my other answer.)
rxArgs = /^[^(]+\(([^)]+)\)/;
function a(v, w, x){
v = 9;
w = 2;
x = 7;
var args = rxArgs.exec(arguments.callee.toString())[1].split(", ");
var i = args.length, values = {};
while (i--) values[args[i]] = eval(args[i]);
func(c('{w} + {x} = {v}', values));
}
function b(v, y, z){
v = 1;
y = 'hello';
z = 'world';
var args = rxArgs.exec(arguments.callee.toString())[1].split(", ");
var i = args.length, values = {};
while (i--) values[args[i]] = eval(args[i]);
func(c('{v}. {y} {z}', values));
}
function c(template, values) {
return template.replace(/{(.*?)}/g, function(match) {
return values[match[1]];
});
}
At this point, however, you're introducing so much boilerplate into each function that you're probably better off simply inlining c() instead.
function a(){
var v = 9;
var w = 2;
var x = 7;
func('{w} + {x} = {v}'.replace(/{(.*?)}/g, function(match) {
return eval(match[1]);
}));
}
function b(){
var v = 1;
var y = 'hello';
var z = 'world';
func('{v}. {y} {z}'.replace(/{(.*?)}/g, function(match) {
return eval(match[1]);
}));
}
I would strongly suggest having your code really parse the templates and interpret the "{foo}" references explicitly in your own code, instead of using eval() for everything.
It's not really clear why code like your "a()" and "b()" examples even need a template mechanism. In a language with first-class function objects like Javascript, what your code seems suspiciously desirous of achieving can be done much better by just programming functionally.
EDIT:
Your question seems to imply that the values will be coming from the caller. If they're all coming that way, you could just pass along the arguments object to c.
Then in the c function, grab the next item in the arguments object you passed for each match in the template.
Example: http://jsfiddle.net/u99Bj/1/
function a(){
var template = '{w} + {x} = {v}';
c(template,arguments);
}
function b(){
var template = '{v}. {y} {z}';
c(template,arguments);
}
function c( template, args ){
var re = /{(.+?)}/;
var i = 0;
var match = template.match(re);
while (match != null){
template = template.replace(re, args[i++]);
match = template.match(re);
}
alert(template);
}
If some of the functions will have some static values, then you would need to convert the arguments into an Array, and supplement the Array as needed.
Can't you do that :
function c(template,caller)
{ ...
}
and call
c(template,this)
then you could just get the variables as members of this (passing the function as an object instead of passing its scope)
EDIT
What about this approach?
function a(){
this.v = 9;
this.w = 2;
this.x = 7;
this.template = '{w} + {x} = {v}';
}
function c(obj){
var template = obj.template;
var re = /{(.+?)}/;
var match = template.match(re);
while (match != null){
template = template.replace(re, obj[match[1]]);
match = template.match(re);
}
alert(template);
}
<input type="button" value="a" onclick="c(new a())"/><br/>
What about this, using simply this keyword
<script type="text/javascript">
function a(){
this.v = 9;
this.w = 2;
this.x = 7;
var template = '{w} + {x} = {v}';
c(template);
}
function b(){
this.v = 1;
this.y = 'hello';
this.z = 'world';
var template = '{v}. {y} {z}';
c(template);
}
function c(template){
var re = /{(.+?)}/;
var match = template.match(re);
while (match != null){
template = template.replace(re, eval(match[1]));
match = template.match(re);
}
alert(template);
}
</script>
All variables will be initialized in document by default. You can encapsulate in other objects. Be careful about optional variables, as they may not be cleared on method call, and may interfere with parsing.

Categories