Please see my exaple:
var AbcVar = "abc";
function Abc(AbcVar){
console.log(AbcVar);
}
It this wrong way to allowing function to access external var?
Why is the output of console.log undefined?
It's time to meet Mr. Scoping.
Plainly speaking, scoping is an encapsulation of variables (note that in javascript, functions are also variables.) Now, in the imaginary language I just made up, the { character starts a scope and } ends it, variables are defined with simple equality (x = 42 for example):
{ |
x = 42; |
{ | |
y = "I'm in an inner scope!"; | |
x == 42; //true | |
{ | | |
x == 42; | | |
y == "I'm in an inner scope!"; | | |
| x, y, z are defined |
z = "pyramid time!"; | | |
y = y + "...not"; | | x, y are defined | x is defined
} | | |
y == "I'm in an inner scope!...not"; | |
//z is not defined | |
x = 4; | |
} | |
x == 4; |
//y is undefined |
//z is undefined |
} |
javascript has lexical scoping. Put simply, functions create a new scope:
var x = 42;
(funciton () {
x === 42;
var y = 5;
})();
//y is undefined
Now, there's an additional place where variables can be created, and that is in the function arguments. The two following functions behave the same (arguments is a pseudo-array containing the parameters passed into the function):
function parameterfull(a, b, c) {
//do stuff with a, b, c
}
function parameterless() {
var a = arguments[0], b = arguments[1], c = arguments[2];
//do stuff with a, b, c
}
If you happen to not pass an argument, its value will be undefined.
Now, using your function and the above translation:
var AbcVar = "abc";
function Abc() {
var AbcVar = arguments[0];
console.log(AbcVar);
}
So now you see why AbcVar is (sometimes) undefined inside the function.
tl;dr The function parameter AbcVar is overriding the global variable AbcVar, and since you didn't pass a value to the function, it's undefined (but only inside of the function, the global AbcVar remains the same.)
Inside the function, AbcVar will refer to the parameter AbcVar of the function. If you don't pass any parameter, the value will be undefined.
The parameter shadows the variable in higher scope with the same name. If you want to access it, you have to remove or rename the parameter. That said, you should always prefer passing arguments to functions (where possible).
hi you can change this to
var AbcVar = "abc";
function Abc(bbb){
console.log(AbcVar);
}
you can access external global var,if you write inside function,it assume that like;
var AbcVar = "abc";
function Abc(var AbcVar){
console.log(AbcVar);
}
so inside funciton AbcVar is new vaiable and null ,it shadow global AbcVar
if you run the function you've just created and pass it your AbcVar,
console.log(AbcVar);
it loggs "abc" as expected
Consider the following code
var AbcVar = "abc";
function logVariable(passedIn){
console.log(passedIn);
}
logVariable(AbcVar);
which creates a variable, a function to log the value of the variable, and then passes the variable to the logger which loggs it in the console
If you notice two lines on your interactive console after you run your logger function: abc followed by undefined
the first is the line printed when you call console.log() and the second is the value that logVariable returns after executing, which is undefined on success.
Related
I have a function that uses a mutable variable that takes strings and returns strings. (its a read eval print loop interpreter)
I tried exporting it as such:
let () =
Js.export_all
(object%js
method js_run_repl = Js.wrap_callback js_run_repl
end)
Heres a snippet of the function im exporting
let js_run_repl str =
match String.(compare str "quit") with
| 0 -> "bye"
| _ -> ...
regardless of my input it always returns bye, calling the function directly in ocaml produced the expected behaviour. Heres the output from node:
> var mod = require('./main.bc');
undefined
> mod.js_run("constant P : Prop");
MlBytes { t: 0, c: 'bye', l: 3 }
>
Its also peculiar why the function is called js_run instead of js_run_repl. the latter is undefined according to node.
let () =
Js.export_all
(object%js
method js_run_repl str =
str
|> Js.to_string
|> js_run_repl
|> Js.string
end)
I had to convert the strings explicitly to ocaml strings and back to js
I'm trying to dynamically create node.js variables that point to objects.
I know I can create a variable dynamically in scope using eval:
var vars = ['a','b']
for(var n=0; n<vars.length; n++) {
eval('var '+vars[n]+' = '+n)
}
console.log(b) // prints 1
The above dynamically creates variables and gives them a value of whatever their index is inside the vars list.
But what if I want to set these dynamic variables to an object reference? Something like the following:
var vars = {a: {}, b:{}}
for(var k in vars) {
eval('var '+k) // create the variable dynamically
new Function('value', k+' = value')(vars[k]) // attempt to set the value
}
a.b = 5
console.log(vars.a.b) // undefined : (
I know why the above doesn't work - the function created by new Function can't see the current scope, and so can't set the value. Is there a way to do what I'm trying to do, such that console.log(vars.a.b) would print "5" rather than "undefined"?
UPDATE:
Hmm, I was wrong that new Function can't see or modify variables in the local scope, since this works:
var obj = {}
eval('var x')
new Function('value', 'x = value')(obj)
obj.a = 5
console.log(x.a) // prints 5
So now I'm pretty confused why my loop above doesn't seem to work..
UPDATE 2:
I just realized that my code actually does work in chrome's console. But its not working in node.js...
UPDATE JUST FOR PHIL:
Here's my situation. I'm using Parsimmon to build a parser combinator. This is how that's done:
var L = Parsimmon.createLanguage({
combinator1: function() {
return Parsimmon.string('hi')
},
combinator2: function() {
return L.combinator1.many()
}
})
I'd like to eliminate the need to write L. before every parser combinator I write. I could do this:
var combinator2 = L.combinator2
But that would require me to add an additional line like that for every combinator I write. As you can see, I can't use with since L is created after I'd be able to write with(L) and if I define my functions below then use them in the object, I'm back to duplicating those function names every time i write a new combinator.
So to summarize, I'd like to loop through L and put all the generated parser combinators into a nice clean variable in scope so I can write combinator1 instead of L.combinator1 (etc).
IIUC, whether or not there are better ways to achieve your goal, if you just remove 'var ' on the dynamic Function, it will operate on the outer (global) scope.
Change:
new Function('value', k+' = value')(vars[k])
to:
new Function('value', k+' = value')(vars[k])
So:
var vars = {a: {}, b:{}}
for(var k in vars) {
eval('var '+k) // create the variable dynamically
new Function('value', k+' = value')(vars[k]) // attempt to set the value
}
a.b = 5
console.log(vars.a.b)
You don't want to declare a new variable with local scope inside the function, you want to operate on the outer scope.
Update to address new question
Your first loop does work. Try introspecting on a or b; they are as should be expected, 0 and 1, respectively.
Update 2 based on info this is for Node.js
Per https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function , Function always works on the global scope. In Node, this is on global and var variables are not the global scope but are the module's scope. To fix this for Node, you can do the following and omit your eval var declaration (which was overriding for the module the global scope which you have access to inside Function):
var vars = {a: {}, b:{}}
for(var k in vars) {
new Function('value', k +' = value')(vars[k]) // attempt to set the value
}
a.b = 5
console.log(vars.a.b) // 5
In other words, the inner function sets variables which automatically become accessible via global, so your module code, in the absence of any module-scoped var declarations of a overwriting the global, you can set the global a properties as with the line a.b = 5.
Update 3
Since I had just been addressing your issue in understanding Function, I gave the above information. As per your follow-up comment (and again, without speaking to its suitability for your specific use case), you can operate on the object via eval as follows:
var vars = {a: {}, b:{}}
for(var k in vars) {
eval('var '+k+' = vars["'+k+'"]')
}
a.b = 5
console.log(vars.a.b) // 5
But to reiterate the warnings made by others--using eval is generally not a good idea and can be dangerous when the variables referenced include arbitrary user data...
change this line :
from :
a.b = 5
to
vars.a.b = 5
because a is undefined in your case that's why it is now allowing to create a new property
vars.a will return you a object not only a as a is vars property.
I have a code that works with print inside do block as,
do { print ([(n, 2^n) | n <- [0..19]]) }
Then i tried a much simpler version to print a variable value,
do { let a = 1; print (a) }
It throws error as parse error on input }
What else, i tried with no success ---
ghci> let a = 1; print (a)
And
ghci> :{
| let a = 1;
| print (a)
| :}
Once you start a let statement, the rest of the line is considered to be additional let assignments. Consider this error message:
ghci> do print 1; let c = 2; d = 3
<interactive>:3:13:
The last statement in a 'do' block must be an expression
let c = 2
d = 3
Note that the let keyword is not needed for d = 3.
To add a monadic statement after a let you'll need to put it on a separate line (with the correct indentation):
ghci> :{
| do print 1; let a = 2; b = 3
| print b
| :}
1
3
AFAIK, there is no way to put a monadic statement after a let on the same line.
In Haskell you can say
main = do
let x = 5
print x
and this will not compile:
main = do
let x = 5
in print x
But if I am using explicit layout, this does not compile:
main = do {
let x = 5;
print x;
}
but this works:
main = do {
let x = 5
in print x;
}
Am I right? Is there anyplace I can read more about explicit layout and do and let notation? Section 3.14 of the Haskell 98 report seems to me to suggest that my third example should work, as it says I can write
do { let DECLS; stmts }
and it translates to
let DECLS in do { stmts }
The normative answer to your question can be found in the Haskell report's description of the layout rule.
Briefly, you need to place a semicolon between your let block and the next statement of the do block. That semicolon needs to lie outside of the let block. If you don't use layout for the let block, that's easy, just say:
let {x = 5};
However, if you do use layout for the let block, then the only way to close the let block is to start a line in a column before the column of x. So that means you'd have to write something like this:
main = do {
let x = 5
; print x;
}
Oh, and for your other example, again with layout a semicolon is getting inserted before the in, so your code desugars to:
main = do {
let {x = 5
};
in print x
}
I am just learning F# and have been converting a library of C# extension methods to F#. I am currently working on implementing a function called ConvertFirstLetterToUppercase based on the C# implementation below:
public static string ConvertFirstLetterToUppercase(this string value) {
if (string.IsNullOrEmpty(value)) return value;
if (value.Length == 1) return value.ToUpper();
return value.Substring(0, 1).ToUpper() + value.Substring(1);
}
The F# implementation
[<System.Runtime.CompilerServices.ExtensionAttribute>]
module public StringHelper
open System
open System.Collections.Generic
open System.Linq
let ConvertHelper (x : char[]) =
match x with
| [| |] | null -> ""
| [| head; |] -> Char.ToUpper(head).ToString()
| [| head; _ |] -> Char.ToUpper(head).ToString() + string(x.Skip(1).ToArray())
[<System.Runtime.CompilerServices.ExtensionAttribute>]
let ConvertFirstLetterToUppercase (_this : string) =
match _this with
| "" | null -> _this
| _ -> ConvertHelper (_this.ToCharArray())
Can someone show me a more concise implementation utilizing more natural F# syntax?
open System
type System.String with
member this.ConvertFirstLetterToUpperCase() =
match this with
| null -> null
| "" -> ""
| s -> s.[0..0].ToUpper() + s.[1..]
Usage:
> "juliet".ConvertFirstLetterToUpperCase();;
val it : string = "Juliet"
Something like this?
[<System.Runtime.CompilerServices.ExtensionAttribute>]
module public StringHelper =
[<System.Runtime.CompilerServices.ExtensionAttribute>]
let ConvertFirstLetterToUppercase (t : string) =
match t.ToCharArray() with
| null -> t
| [||] -> t
| x -> x.[0] <- Char.ToUpper(x.[0]); System.String(x)
Try the following
[<System.Runtime.CompilerServices.ExtensionAttribute>]
module StringExtensions =
let ConvertFirstLetterToUpperCase (data:string) =
match Seq.tryFind (fun _ -> true) data with
| None -> data
| Some(c) -> System.Char.ToUpper(c).ToString() + data.Substring(1)
The tryFind function will return the first element for which the lambda returns true. Since it always returns true it will simply return the first element or None. Once you've established there is at least one element you know data is not null and hence can call Substring
There's nothing wrong with using .NET library functions from a .NET language. Maybe a direct translation of your C# extension method is most appropriate, particularly for such a simple function. Although I'd be tempted to use the slicing syntax like Juliet does, just because it's cool.
open System
open System.Runtime.CompilerServices
[<Extension>]
module public StringHelper =
[<Extension>]
let ConvertFirstLetterToUpperCase(this:string) =
if String.IsNullOrEmpty this then this
elif this.Length = 1 then this.ToUpper()
else this.[0..0].ToUpper() + this.[1..]