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);
Related
This seems to correctly return the correct value of 1:
let test = function() {
let test = 1;
function getTest() {
return test;
}
return {getTest};
}();
console.log(test.getTest());
But this does not:
let test = function() {
this.test = 1;
function getTest() {
return this.test;
}
return {getTest};
}();
console.log(test.getTest());
Why?
I am unsure what exactly you were trying to achieve with your code. An IIFE should not be mixed up with an object instantiation which I have demonstrated below. In this context the this works as expected:
const test=new function() { // object instantiation
this.test = 1; // this defines the property test
this.getTest=function(){
return this.test; // this references the same property
}
};
// test.test=123; // you can manipulate the property test here
console.log(test.getTest());
Or, in form of a simple object assignment:
const test={ // object assignment
test: 1, // defines the property `test`
getTest(){ return this.test; } // the `this` references the `test` property
};
console.log(test.getTest());
Because of the scope of this.
let test = function() {
this.test = 1; // this refers to the scope of the 1st level function
function getTest() {
return this.test; // this refers to the getTest function, and is undefined
}
return {getTest};
}();
console.log(test.getTest());
Just to make the point of the behavior of this you could use an arrow function, which captures the encompassing scope, including this
let test = function() {
this.test = 1;
const getTest = ()=> this.test; // still points to upper function
return {getTest};
}();
console.log(test.getTest());
But note that this a bad practice in this case because you keep in memory a reference to a function after it has reach end of scope. You shouldn't return any reference to this from a this kind of immediately invoked function, it creates a memory leak.
So a better thing to do would be to define the function and the test value on the returned object, with this being a reference to this object an not of a closure's scope object that doesn't exist any more
let test = function() {
return {
test: 1,
getTest() {
return this.test;
},
}
}();
console.log(test.getTest());
This question already has answers here:
declare function properties inside
(2 answers)
Adding custom properties to a function
(10 answers)
Closed 1 year ago.
It's possible to create a method like this in a literal object :
https://jsfiddle.net/7q1530sp/2
let o = {
f: function f () {
alert("f")
}
}
o.f();
Since function is also an object, I'd like to be able to do the same within a function I tried this but it doesn't work, is there a way ?
https://jsfiddle.net/7q1530sp/1
function o(){
f: function f () {
alert("f")
}
}
o.f();
You can define as many functions-within-functions as you like!
let f1 = function() {
let f2 = function() {
let f3 = function() {
return 'functions';
};
return 'love ' + f3();
};
return 'I ' + f2();
};
console.log(f1());
If you want to define functions as properties, you could also do the following:
let f1 = function() {
return 'I ';
};
f1.f2 = function() {
return 'love ';
};
f1.f3 = function() {
return 'functions';
};
console.log(f1() + f1.f2() + f1.f3());
Note that this property assignment works exactly the same way that objects work; e.g.
let f1 = function(){}; f1.someProperty = 'someValue';
vs
let o = {}; o.someProperty = 'someValue';
The assignment of properties to a function doesn't need to occur within the function body, but functions certainly could assign properties to themselves:
let f = function() {
f.a = 'b';
f.c = 'd';
};
Note that in this case the f.a and f.c properties wouldn't exist until you actually call the function by performing: f().
You have to define it outside of the function:
function o(){
console.log("o");
}
o.f = function(){
console.log("f");
}
o.f()
You can create objects within a function in Javascript.
Here is your code:
function o() {
const d = {
f: function f() {
alert("f")
},
}
d.f();
}
o();
Output:
https://jsfiddle.net/pLjc0vbf/1/
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
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() );