Why does the following code return just an empty string:
var a = {
name:"321",
foo: function(){
console.log(name);
}
}
a.foo();
because you haven't scoped name to anything so it's looking for a global variable.
try replacing
console.log(name);
with
console.log(this.name);
you can use this keyword like this - console.log(this.name); .In result of your code, you see an empty string and not a undefined error because window.name variable already exists and has nothing to do with the name variable in your object
Following comments on Rich Linnell answer:
foo is for the object's function scope exemple, and bar for callbacks's scopes.
Code:
var foo = "global",
bar = "global",
a = {
foo: (callback) => {
// var foo = 'local';
console.log('foo: ' + foo);
callback();
}
};
(() => {
// var bar = "parent";
a.foo(() => {
// var bar = "local";
console.log('bar: ' + bar);
});
})();
Related
Is it possible to combine the following into one statement:
// Combine from here
const foo = function() {
return 'hello';
}
foo.world = 'world';
// to here
console.log(foo() + foo.world) // helloworld
(foo = () => 'hello').world = 'world'
You can move the property declaration into the function.
let foo = function () {
foo.world = 'world';
return 'hello';
};
console.log(foo() + foo.world)
You have to assign statics outside of the function/class declaration. Here is an alternative ES5 version using classes.
class foo {
constructor() {
// constructor...
}
toString() {
return 'hello'
}
}
foo.world = 'world' // static member variables need to be assigned outside, no other way
console.log(new foo() + foo.world) // helloworld
I'm writing my first javascript module, and there is something that I don't understand with the scope variables. Here is my module :
var Module = (function () {
var myString ='a';
var changeString = function () {
myString ='b';
console.log(myString);
};
return {
changeString: changeString,
myString:myString
};
})();
Now if I do :
Module.myString; // returns 'a'
Module.changeString(); // returns 'b'
Module.myString; // returns 'a'
For me , the last command should return 'b' because I've changed myString with the changeString method. I don't understand why, since myString is declared outside the changeString method, so the scope seems ok. I would like to understand why it behaves like this, and how to make a method which overwrites the value of my variable.
Thanks in advance.
This makes a copy of myString at the time the object is created:
return {
changeString: changeString,
myString:myString
}
You can use a getter to return the local variable dynamically and that will give you the behaviour you expected:
return {
changeString: changeString,
get myString() {
return myString;
}
}
Full example:
var Module = (function () {
var myString ='a';
var changeString = function () {
myString ='b';
console.log(myString);
};
return {
changeString: changeString,
get myString() {
return myString;
}
}
})();
console.log( Module.myString );
Module.changeString();
console.log( Module.myString );
The anonymous function is only executed once, and the object returned by it is thus also only evaluated once: it is an object with a string property myString which is a primitive value -- it will not change if the variable myString is changed later.
If you wanted the behaviour like you expected it, then you should keep a reference in the Module to the object you return, and then mutate that object when the string property needs to change:
var Module = (function () {
var changeString = function () {
obj.myString = 'b'; // mutation of obj!
console.log(obj.myString);
};
var obj = {
changeString: changeString,
myString: 'a';
};
return obj; // we have a reference to this object
})();
As is said in other answers, because myString is a primitive, its value is copied from the scope to the member value of the anonymous object returned. In order to access the externally available copy of myString from the changeString() method, you can reference the anonymous object assigned to Module using the this keyword:
var Module = (function() {
var myString = 'a';
var changeString = function() {
// `Module.changeString()` causes `this === Module` inside here
this.myString = 'b';
};
return {
changeString: changeString,
myString: myString
};
})();
console.log(Module.myString); // returns 'a'
Module.changeString();
console.log(Module.myString); // returns 'b'
Using ES6 syntax, there are a few shortcuts you can take to simplify this approach:
var Module = (() => {
let myString = 'a';
return {
// ES6 for `myString: myString,`
myString,
// ES6 for `changeString: function () {`
changeString () {
this.myString = 'b';
}
};
})();
console.log(Module.myString); // returns 'a'
Module.changeString();
console.log(Module.myString); // returns 'b'
You see this behaviour because you return a fresh object.
The string myString gets copied because it is a primitive value.
You can achieve your goal with a few adjustments:
var Module = function() {
var myString = 'a';
this.changeString = function() {
myString = 'b';
};
this.getString = function() {
return myString;
};
};
var mod = new Module;
console.log(mod.getString()); // a
mod.changeString();
console.log(mod.getString()); // b
I need the current function name as a string to log to our log facility. But arguments.callee.name only works in loose mode. How to get the function name under "use strict"?
For logging/debugging purposes, you can create a new Error object in the logger and inspect its .stack property, e.g.
function logIt(message) {
var stack = new Error().stack,
caller = stack.split('\n')[2].trim();
console.log(caller + ":" + message);
}
function a(b) {
b()
}
a(function xyz() {
logIt('hello');
});
You can bind function as its context then you can access its name via this.nameproperty:
function x(){
console.log(this.name);
}
x.bind(x)();
After little research here is a good solution :
function getFnName(fn) {
var f = typeof fn == 'function';
var s = f && ((fn.name && ['', fn.name]) || fn.toString().match(/function ([^\(]+)/));
return (!f && 'not a function') || (s && s[1] || 'anonymous');
}
function test(){
console.log(getFnName(this));
}
test = test.bind(test);
test(); // 'test'
Source : https://gist.github.com/dfkaye/6384439
Building on #georg solution, this one returns just the function name. Note though that it may fail if called from an anonymous function
function getFncName() {
const stackLine = (new Error())!.stack!.split('\n')[2].trim()
const fncName = stackLine.match(/at Object.([^ ]+)/)?.[1]
return fncName
}
function Foo() {
console.log(getFncName()) // prints 'Foo'
}
A simple solution to dynamically retrieve function names [like magic variables] is the use of scoped variables, and the Function.name property.
{
function foo() {
alert (a.name);
}; let a = foo
}
{
function foo2() {
alert(a.name)
}; let a = foo2
};
foo();//logs foo
foo2();//logs foo2
Note: Nested functions cease to be source elements, and are hence not hoisted. Also, this technique cannot work with anonymous functions.
If (like me) you want to define this elsewhere and call it generically, you can store the code as a string somewhere global or import it, then eval() it wherever to access the current function name. (Using eval keeps the context at the point of invocation.)
There's gotta be a way to do this without using a string, but whatever.
SomeObject.whatFunc =
'const s = new Error().stack;' +
"const stackLine = new Error().stack.split('\\n')[2].trim();" +
'const fncName = stackLine.match(/(?<=at )(.*)(?= \\()/gm)[0];' +
'console.log(fncName);'
// Whereever you want the func name
function countBananas('weeee') {
eval(SomeObject.whatFunc)
// blah blah blah
}
countBananas() // logs 'countBananas'
just an update to get the full name :
function logIt(message) {
var stack = new Error().stack,
// update is on this line
caller = stack.split('\n')[2].trim().split(/\s+/)[1];
console.log(caller.trim().split(/\s+/)[1];);
}
function a(b) {
b()
}
a(function xyz() {
logIt('hello');
});
I am studying the execution context from Javascript. But i dont understand why the "function foo" not will be over written by the "var foo".
I hope someone can explain this,
thank you for your respons.
function ace() {
console.log(typeof foo); // function pointer
console.log(typeof bar); // undefined
var foo = 'hello',
bar = function() {
return 'world';
};
function foo() {
return 'hello';
}
var foo = 'hello';
}
ace();
why the "function foo" not will be over written by the "var foo".
foo is overwritten at the line where foo is re-defined
function ace() {
console.log(typeof foo); // function pointer
console.log(typeof bar); // undefined
var foo = 'hello',
bar = function() {
return 'world';
};
function foo() {
return 'hello';
}
var foo = 'hello';
console.log(foo);
try {
foo()
} catch(e) {
console.log("catch:", e.message)
}
}
ace();
But i dont understand why the "function foo" not will be over written by the "var foo".
The var declaration does not overwrite the function declaration. They both declare the same variable, and because of the function declaration it is initialised with a function. It is only the assignment that will overwrite the value.
If you take hoisting into account, your script will behave like
function ace() {
var foo, bar;
var foo = function() {
return 'hello';
}
var foo;
console.log(typeof foo); // function
console.log(typeof bar); // undefined
foo = 'hello';
bar = function() {
return 'world';
};
console.log(typeof foo); // string
foo = 'hello';
}
ace();
I have JS object with custom methods as prototype (e. g. Foo.prototype.myAwesomeMethod). If I load my object in a localStorage and get it later I'll loose these methods.
var foo = new Foo()
console.log(foo.myAwesomeMethod()) // WIN
localStorage.setItem('foo', foo)
foo = localStorage.getItem('foo')
console.log(foo.myAwesomeMethod()) // FAIL...
Is it possible to save the prototype of the object in the localStorage ? If not, how to properly re-instantiate the class?
you can try this
function Foo() {
this.bar = 1;
}
Foo.prototype.myAwesomeMethod = function () {
return "And the winner is " + this.bar;
}
var foo;
window.onload = function () {
foo = new Foo();
foo.bar = 3;
console.log(foo.myAwesomeMethod()); // "And the winner is 3"
var test = JSON.stringify(foo); //localStorage.setItem('foo', foo);
foo = JSON.parse(test); // = localStorage.getItem('foo');
foo.__proto__ = new Foo(); // <--------------
console.log(foo.myAwesomeMethod()); // "And the winner is 3"
});
EDIT:
my previous code was untested and didn't work, this is the working code