Declare variable to be function and have properties in one statement - javascript

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

Related

Difference between variable and an arrow function [duplicate]

This question already has answers here:
How does the "this" keyword work, and when should it be used?
(22 answers)
Closed last year.
What's the difference between a variable:
const a = console.log;
a('HELLO');
and an arrow function:
const a = (str) => console.log(str);
a('HELLO');
And why in case of using a class member it doesn't work
class MyClass {
foo;
str;
constructor(str, foo) {
this.str = str;
this.foo = foo;
}
getFoo() {
return this.foo(this.str);
}
}
const instance = new MyClass(123, console.log);
// works
const f = (str) => {
instance.getFoo(str);
}
f('Hello');
// doesn't works -> this.str is undefined
const f = instance.getFoo;
f('Hello');
variable = classInstance.function actually just returns a reference to the function in the prototype, not linked to the actual instance, the this.* looks for global variables.
If you want to be able to have another variable store the function with the context of that variable, you need to use .bind(...) or similar
You can also give it a custom context
class MyClass {
foo;
str;
constructor(str, foo) {
this.str = str;
this.foo = foo;
}
getFoo() {
return this.foo(this.str);
}
}
const instance = new MyClass(123, console.log);
// give it the context object
const f = instance.getFoo.bind(instance);
f('Hello');
const f2 = instance.getFoo.bind({ str: "abcd", foo: console.log});
f2("...");
// Equal to the prototype
console.log(instance.getFoo == MyClass.prototype.getFoo);

Variable scope in a module

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

JavaScript function access to object property

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);
});
})();

Define a const in class constructor (ES6) [duplicate]

This question already has answers here:
Declaring static constants in ES6 classes?
(19 answers)
Closed 7 years ago.
Is there a way I can define a const in the constructor of a class?
I tried this:
class Foo {
constructor () {
const bar = 42;
}
getBar = () => {
return this.bar;
}
}
But
var a = new Foo();
console.log ( a.getBar() );
returns undefined.
You use static read-only properties to declare constant values that are scoped to a class.
class Foo {
static get BAR() {
return 42;
}
}
console.log(Foo.BAR); // print 42.
Foo.BAR = 43; // triggers an error
Simply defining a constant in the constructor won't attach it to the instance, you have to set it using this. I'm guessing you want immutability, so you can use getters:
class Foo {
constructor () {
this._bar = 42;
}
get bar() {
return this._bar;
}
}
Then you can use it like you normally would:
const foo = new Foo();
console.log(foo.bar) // 42
foo.bar = 15;
console.log(foo.bar) // still 42
This will not throw an error when trying to change bar. You could raise an error in a setter if you want:
class Foo {
constructor () {
this._bar = 42;
}
get bar() {
return this._bar;
}
set bar(value) {
throw new Error('bar is immutable.');
}
}
The problem is with "bar" scoping - it scoped to constructor:
'use strict';
class Foo {
constructor () {
const bar = 42;
this.bar = bar; // scoping to the class
}
getBar () {
return this.bar;
}
}
var a = new Foo();
console.log ( a.getBar() );

Setting a variable in the closure scope

I think I understand why variables exist outside of the function they were declared in, because you're returning another function:
myFunction = function() {
var closure = 'closure scope'
return function() {
return closure;
}
}
A = myFunction(); // myFunction returns a function, not a value
B = A(); // A is a function, which when run, returns:
console.log(B); // 'closure scope'
The way that it's written now, calling A() is like a getter.
Q: How can I write myFunction so that calling A(123) is a setter?
Try the following:
myFunction = function() {
var closure = 'closure scope'
// value is optional
return function(value) {
// if it will be omitted
if(arguments.length == 0) {
// the method is a getter
return closure;
} else {
// otherwise a setter
closure = value;
// with fluid interface ;)
return this;
}
}
}
A = myFunction(); // myFunction returns a function, not a value
A(123); // set value
B = A(); // A is a function, which when run, returns:
console.log(B); // '123'
You could do something like this if you want both getter and setter for example:
var func = function() {
var closure = 'foo';
return {
get: function() { return closure; },
set: function(value) { closure = value; }
}
};
var A = func();
A.set('foobar');
console.log(A.get()); //=> "foobar"
Should be as simple as:
myFunction = function() {
var closure = 'closure scope'
return function(setTo) {
if (typeof setTo !== "undefined") {
closure = setTo;
return this; //support call chaining, good idea hek2mgl
} else {
return closure;
}
}
}
Since the closure variable is within the closure of the function's scope, you should be able to assign to it the same way you can read from it.
See jsFiddle: http://jsfiddle.net/WF4VT/1/
Another alternative would be to use a class and define getters and setters:
function MyClass(p){
this._prop = p;
}
MyClass.prototype = {
constructor: MyClass,
get prop(){
return this._prop;
},
set prop(p){
this._prop = p;
}
}
var myObject = new MyClass("TEST");
console.log(myObject.prop);
myObject.prop = "test";
console.log(myObject.prop);
Demo: http://jsfiddle.net/louisbros/bMkbE/
jsFiddle Demo
Have your returned function accept an argument. Use it as a setter:
myFunction = function() {
var closure = 'closure scope';
return function(val) {
closure = val;
return closure;
}
}
A = myFunction(); // myFunction returns a function, not a value
B = A(123); // A is a function, which when run, returns:
console.log(B); // 'closure scope'
Revisiting this question, I see that I could do it this way:
function outside() {
var result = 'initialized'
return inside
function inside(argVariable) {
if(arguments.length) {
result = argVariable
return this
} else {
return result
}
}
}
myFunction = outside() // outside returns a function
X = myFunction() // returns: 'initialized'
$('body').append(X + '<br>')
myFunction(123) // setter
X = myFunction() // returns: 123
$('body').append(X)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

Categories