Assigning arguments to local variables in closure - javascript

Here is a currying snippet from javascript patterns:
function add(x, y) {
var oldx = x, oldy = y;
if (typeof oldy === "undefined") { // partial
return function (newy) {
return oldx + newy;
}
}
// full application
return x + y;
}
ref: https://github.com/shichuan/javascript-patterns/blob/master/function-patterns/currying.html
What is the point of local vars oldx and oldy?

The variables oldx and oldy are completely unnecessary here; the code behaves identically without them:
function add(x, y) {
if (typeof y === "undefined") { // partial
return function (y) {
return x + y;
}
}
// full application
return x + y;
}
The function being returned here has access to outer-scope variables regardless of whether those variables are declared with var or declared as formal arguments to an outer function.
Generally speaking, if x is a primitive, it might sometimes make sense to assign it to a new variable if you needed a copy of that value to alter independently of the original:
function foo(x) {
var newX = x;
newX += 7;
// now newX and x are different
// ...
}
However, that need does not exist in this code, so it's totally unnecessary.

Related

Why does this JavaScript code return an error?

I know in JavaScript only function declarations are hoisted, which means it should print 30 after running the function sum.
However it says diff is not defined, shouldn't it be hoisted?
sum(10, 20);
diff(10, 20);
function sum(x, y) {
return x + y;
}
let diff = function(x, y) {
return x - y;
}
It's because as you said, only function declarations are hoisted, not function expressions (assigning a nameless function to a variable). Following code works:
sum(10, 20);
diff(10, 20);
function sum(x, y) {
return x + y;
}
function diff(x, y) {
return x - y;
}
To declare diff the way you did, you must lift it to the top of your code:
let diff = function(x, y) {
return x - y;
}
sum(10, 20);
diff(10, 20);
function sum(x, y) {
return x + y;
}
Yes, let and const are hoisted but you cannot access them before the actual declaration is evaluated at runtime.
You are accessing the function before you initialize it.
So this should work,
let diff = function(x, y) {
return x - y;
}
function sum(x, y) {
return x + y;
}
console.log(sum(10, 20));
console.log(diff(10, 20));
let diff will hoist but at the moment when function diff(10, 20); will be called variable diff will not jet be defined with the function.
Google this topic function declaration vs function expression
Because Function Expressions are not hoisted like Function Declarations
Function expressions in JavaScript are
not hoisted, unlike function declarations. You can't use function
expressions before you create them:
console.log(notHoisted) // undefined
// even though the variable name is hoisted, the definition isn't. so it's undefined.
notHoisted(); // TypeError: notHoisted is not a function
var notHoisted = function() {
console.log('bar');
};
https://developer.mozilla.org/en-US/docs/web/JavaScript/Reference/Operators/function#function_expression_hoisting
You will need to use a Function Declaration if you want it to be hoisted.

passing variables across functions on javascript

I'm trying to pass variables across functions,
something like
function one() {
var x = 1
}
function two() {
var y = x + 1;
}
alert(y);
Is there a way to do it?
edit:Thanks everyone for being so helpful, but maybe I should have been more specific with my question.
You current way has x and y in the scope of the function, which means the other function doesnt know it exists. Also, its good practice to name functions according to what they do. 3 straightforward ways to do this.
Global
Params
Inline
Set two variables outside of the functions scope that any function can reach.
var x, y;
function assignOne() {
x = 1;
}
function addOne() {
y = x + 1;
}
assignOne();
addOne();
console.log(y);
Pass in a parameter to to the function and return values.
function one() {
return 1;
}
function addOneTo(x) {
return x + 1;
}
const y = addOneTo(one());
console.log(y);
Perform functions inline
var x = null;
function one() {
x = 1;
}
function two() {
return x + 1;
}
one();
const y = two();
console.log(y);
You will need to hoist the scope, by extracting the variable declaration to outside of the functions. That is to say, define x and y outside of the functions. Note that you can still update their values from within the functions. However, don't forget that you'll actually need to invoke both functions as well!
This can be seen in the following:
var x, y;
function one() {
x = 1;
}
function two() {
y = x + 1;
}
one();
two();
console.log(y);
If you really want to get variable declared in one method, return it
function one(){
var x = 1;
return x;
}
function two() {
var x = one();
var y = x + 1;
return y;
}
alert(two());
Seems like you want to have shared state between both functions instead of passing arguments. So, an object oriented pattern seems to be appropriate.
class Thing {
constructor() {
this.x = 1;
}
one() {
return this.x;
}
two() {
return this.x + 1;
}
}
const t = new Thing();
console.log(t.one());
console.log(t.two());
If you want to share variables between functions but don't want to declare them in global scope, you can use a closure like this:
(function() {
var x, y;
function one() {
var x = 1
}
function two() {
var y = x + 1;
}
one();
two();
alert(y);
})();

understanding Let scope

My assumption with code is that for the second let x the code above it is in the temporal dead zone. Hence should not throw error.
Code
function f(condition, x) {
if (condition) {
let x = 100;
return x;
}
let x = 30; // <---- throw error
return x;
}
f(true, 1);
Well the problem here is that you are redeclaring the same variable x twice in the same function, so the variable x will be hoisted.
if (condition) {
//This x declaration is fine as it wasn't preceded with any others declaration inside the same block scope
let x = 100;
return x;
}
//Now this second x declaration will cause the hoisting problem
let x = 30; // <---- throw error
Here the second let x = 30; declaration is hoisting the x variable in your function scope. So conclusion is that you can't declare the same variable more than once in the same scope.
For further reading about varaible hoisting in Javascript you can check:
MDN Hoisting
reference.
A guide to JavaScript variable hoisting 🚩 with let and const article
Issues seem to be with x already being a function parameter having the same scope as the outer x. If i change function parameter x with y, the code works fine.
Code
function f(condition, y) {
if (condition) {
let x = 100;
return x;
}
let x = 30; // <---- doesnt throw error
return x;
}
f(true, 1);

Scope of variables in functions using javascript

Why the y is leaked outside the function as scope in JavaScript are bound to functions.
A detailed explanation would be fruitful.
var x = 0;
function f(){
var x = y = 1; // x is declared locally. y is not!
};
f();
console.log(x, y); // 0, 1
It's just syntax error.
The line var x = y = 1; Means:
Declare local variable x,
y = 1,
Declare global variable y (since it's not declared)
x = y;
Replace
var x = y = 1;
with
var x = 1, y = 1;
or
var x = 1;
var y = 1;
and you will get local variable y
http://www.w3schools.com/js/js_variables.asp
The reason the y variable is global is that in Javascript if you omit the var keyword from an assignment statement, the variable the value is assigned to is declared on the global object.
That means that if you wrote the f() function this way, declaring both x and y with the var keyword:
function f(){
var x, y;
x = y = 1;
};
Then both x and y would be local variables (local x shadowing the global one).
It's bad practice to assign a variable without declaring it (with the var keyword).
New versions of JS will throw an error on this. You can use EC5's strict mode to take advantage of this behavior:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions_and_function_scope/Strict_mode
so you'd write your function this way:
function f(){
'use strict'
var x, y;
x = y = 1;
};
now if you forget to declare y you get an error yelling at you to do so.

multiple constructor in javascript

I have a question: I was wondering if it is possible to simulate the
multiple constructors, like in Java (yes, I know that the languages are
completely different)?
Let's say that I have a class called "Point" which would have two
values "x" and "y".
Now, let's say if it were the Java version, I would want two
constructors: one that accept two numbers, the other accepts a string:
public class Point {
private int x;
private int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
public Point(String coord) {
this.x = coord.charAt(0);
this.y = coord.charAt(1);
}
//...
}
//In JavaScript, so far I have
Point = function() {
var x;
var y;
//...
}
Is it possible to have two declarations for the Point.prototype.init?
Is it even possible to have multiple constructors in JavaScript?
You can do this in javascript by testing the number of arguments, or the type of the arguments.
In this case, you can do it by testing the number of arguments:
function Point(/* x,y | coord */) {
if (arguments.length == 2) {
var x = arguments[0];
var y = arguments[1];
// do something with x and y
} else {
var coord = arguments[0];
// do something with coord
}
}
Yes, you can, although not as your expecting. As Javascript is weakly typed, no-one cares or checks what type the arguments that you provide are.
Java requires two different constructors because it is strongly typed and the argument types have to match the method signature, however this isn't the case with JavaScript.
function Point(arg1, arg2) {
if (typeof arg1 === "number" && typeof arg2 === "number") {
// blah
} else if (typeof arg1 === "string" && arguments.length == 1) {
// blah
} else {
throw new Error("Invalid arguments");
}
};
This is inspired from iOS.
class Point {
constructor() {
this.x = 0; // default value
this.y = 0; // default value
}
static initWithCoor(coor) {
let point = new Point();
point.x = coor.x;
point.y = coor.y;
return point;
}
static initWithXY(x,y) {
let point = new Point();
point.x = x;
point.y = y;
return point;
}
}
Just like that, you could have as many initializers as you want without writing lots of if-else.
let p1 = Point.initWithCoor({ x:10, y:20 });
let p2 = Point.initWithXY(10, 20);
Just make one constructor wrap another:
function Point(x,y) {
//make the point and do what the constructor is designed to do
}
function PointStr(str) {
var xp = arguments[0];
var yp = arguments[1];
return new Point(xp, yp);
}

Categories

Resources