ES6 How to get _this inside class, inside another context [duplicate] - javascript

This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 7 years ago.
I was searching and can't find a proper way to figure out this in ES6 way.
class MyClass {
// i can't event decalre _this/_self here
constructor() {
setTimeout(function(){
// other work..
hiUser(); // this.hiUser() or //_this.hiUser() not working
},1000);
}
hiUser(){
alert('Hi');
}
}

The previous answers only gave you code samples on how to fix it; Let me explain your issue and why it's happening
In your code example, the function inside of your setTimeout is being bound to the this value of the setTimeout (which is generally window or undefined in strict mode).
setTimeout(function () {
// this === window
}, 1000);
In ES6, they introduced lambda expressions (arrow functions) which are "lexically bound" -- meaning that they borrow the this value from their outside scope. In your case, that's the class/object.
In order to leverage the lambda expressions, it would look like:
class Foo {
constructor () {
setTimeout(() => this.myMethod(), 1000);
}
myMethod () {
console.log('foo');
}
}
If you're using Babel to transpile your code, and are using experimental features, you can use ES7's binding syntax to solve your problem as well.
If you bind a function/method, it creates a copy of that function, and binds the this value to whatever you choose. This will allow you to use the function statement that will be bound to your class/object.
<context to be bound> :: <function to receive context>
class Foo {
constructor () {
setTimeout(this::function() {
this.myMethod();
}, 1000);
}
myMethod () {
console.log('foo');
}
}
An even shorter version would look something like the following
constructor () {
setTimeout(this::this.myMethod, 1000);
}
If you're still having issues understanding this, I suggest you read more about ES6 classes and javascript binding.

You can use fat arrow functions:
class MyClass {
constructor() {
setTimeout(() => {
this.hiUser();
}, 1000);
}
hiUser(){
alert('Hi');
}
}
Or you can use the simple ES5's Function.prototype.bind method:
class MyClass {
constructor() {
setTimeout(function() {
this.hiUser();
}.bind(this), 1000);
}
hiUser(){
alert('Hi');
}
}
There is an ES7 proposal to shorthand the Function.prototype.bind method, so, depending on the transpiler (e.g Babel or Typescript) you're (possibly) using, you can set the ES7 flags and use it today:
class MyClass {
constructor() {
setTimeout(::function() {
this.hiUser();
}, 1000);
}
hiUser(){
alert('Hi');
}
}

setTimeout might have its own this context. You could set _self in the constructor though, or use arrow functions:
class MyClass {
constructor () {
var self = this;
// etc.
}
}

Related

JavaScript field access from anonymous function [duplicate]

This question already has answers here:
How does the "this" keyword work, and when should it be used?
(22 answers)
Closed 3 years ago.
how can I access a fiel from within an anonymous function inside a method?
like in this example:
class Something {
constructor (){
this.gax = “gax”;
}
doSomething(){
(function () {
console.log(this.gax);
}());
}
}
new Something().doSomething();
this will result in an error that "this" is undefined.
thank you very much in advance, I could not find an answer in the web after searching for hours.
best,
lev
In your anonymous function, this is bound to the function; it no longer refers to the class.
Use an arrow function instead, which doesn't have it's own this binding.
class Something {
constructor (){
this.gax = "gax";
}
doSomething(){
(() => {
console.log(this.gax);
})();
}
}
new Something().doSomething();
Alternatively, you could use something like .call(), .apply(), or .bind():
class Something {
constructor (){
this.gax = "gax";
}
doSomething(){
(function() {
console.log(this.gax);
}).call(this);
}
}
new Something().doSomething();
class Something {
constructor (){
this.gax = "gax";
}
doSomething(){
(function () {
console.log(this.gax);
}).apply(this);
}
}
new Something().doSomething();
You can use apply method. The apply() method calls a function with a given this value

Does VueJS make a distinction between function declaration formats under its methods property?

Our team is working on a VueJS project and I noticed that some of the method functions are declared this way:
methods: {
doSomething: function () {
//do it here...
}
}
while others are in this format:
methods: {
doSomething() {
//do it here...
}
}
Both of the formats work just fine and if I remember my javascript correctly, the second method is just a javascript shorthand for function declaration.
But does VueJS makes a distinction between the two formats? What is the best/preferred way to declare VueJS methods? How about VueJS computed functions, does it have to be formatted in the same way as method functions?
It has nothing to do with Vue.
Starting with ECMAScript 2015, a shorter syntax for method definitions on objects initializers is introduced. It is a shorthand for a function assigned to the method's name.
Given the following code:
var obj = {
foo: function() {
/* code */
},
bar: function() {
/* code */
}
};
You are now able to shorten this to:
var obj = {
foo() {
/* code */
},
bar() {
/* code */
}
};
Ref: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Method_definitions
There is one more way to declare a method
methods: {
doSomething: () => {
//do it here...
}
}
Actually your ways of declaration is same and you are right - you can use both in same way.
But remember, if you need to access component's instance inside of method (this) - arrow function would not let you do that.
methods: {
doSomething: () => {
console.log(this) // undefined
}
}
In that case you almost always have to use this way:
methods: {
doSomething() {
console.log(this) // insance
}
}
well both are objects they can be written any way its not about vue its about js engine over here which does not distinguish between both in any way. with respect to the best practices you should follow https://v2.vuejs.org/v2/style-guide its an official guid for the same. certain times if your function is small You can skip
methods:{
xyz(){
}
}
and write it as
methods:{
xyz:()=> return something;
}

Using es6 arrow functions inside class [duplicate]

This question already has answers here:
How to use arrow functions (public class fields) as class methods?
(4 answers)
Closed 8 months ago.
When i change a function draw(){ //} to draw = () => { // }
I am getting an error like "Uncaught SyntaxError: Unexpected token =".
What may be the reason?
First of all, you probably shouldn't do that. Why? Well, because arrow functions are not semantically the same as regular functions.
If you register the functions as this.draw = () => {//}, then every instance of your class* will have a duplicate definition of that function which is a waste of space and a misuse of some core language features such as prototype inheritance.
draw() on the other hand registers that function on the prototype so that definition of the draw function can be shared between all instances and even changed dynamically for ALL instances at the same time.
In your constructor you can have this.draw = () => {//} but there isn't really much point in doing this. draw(){//} should be fine for anything you want.
Below, in my example, I've shown both use cases as you can see nothing is saved by using an arrow function.
class StandardFunction {
draw() {
console.log('StandardFunction: you called draw')
}
}
class ArrowFunction {
constructor() {
this.draw = () => {
console.log('ArrowFunction: you called draw')
}
}
}
const test1 = new StandardFunction();
const test2 = new ArrowFunction();
test1.draw();
test2.draw();
I hope you find this helpful
You will need to use babel's Class properties transform, which will transpile:
class Picture {
draw = () => {
console.log('drawing')
}
}
into:
class Picture {
constructor() {
this.draw = () => {
console.log('drawing');
};
}
}
You can try it in this repl (make sure to enable the class properties transform plugin)

Difference between normal function and the shorter function syntax added in ES6?

So, ES6 has added this way of defining a function,
func() { }
And then we have the old way of doing the same,
function func() {}
As far as, I understand
We can use the new short syntax in object and classes only.
And ES6 classes can only have these short syntax functions, adding long function syntax gives error
I am trying to understand what is the actual implementation difference between the two. Is it related to the use of this or super key word.
Good question!
Here are some of the ways you can declare a function (that can possibly be named doSomething):
Normal function declaration (for the lack of a better world)
This can defined in any block in your code
function doSomething() {
}
Class method and Object shorthand syntax (ES6 only)
These can only be declared inside Class blocks and objects where the function keyword isn't required
class MyClass {
doSomething() { // class method
}
}
// ES6
const myObject = {
foo: 1,
bar: 'baz',
doSomething() { // shorthand: key 'doSomething' whose value is a function
},
}
// ES5 (also ES6)
var myObject = {
foo: 1,
doSomething: function doSomething() {
},
}
Anonymous Functions (functions without a name)
// doesn't have a name but can be invoked using the variable name
const myFunction = function () {}
Callback functions (also can be anonymous)
fetch('/path/to/page').then(function () {
// do something
})
// same as above but with name
fetch('/path/to/page').then(function doSomething() {
// do something
})
Immediately-Invoked Functions (IIFE)
(function doSomething() {
// do something immediately
}())
I'm going to pause here to note that all of the above types of function declaration above have their own scope. Meaning, the this keyword references the actual function, not its surrounding scope.
Arrow functions (lexically scoped)
Meaning that these functions keeps surrounding context when using the this keyword.
const doSomething = () => {
// do something
}
const myObject = {
doSomething: () => {
// do something
}
}
fetch('/path/to/page').then(() => {
// do something
})
(() => {
// do something immediately
})()

This keyword doesn't seem to work like it should [duplicate]

This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 1 year ago.
Normally I'd assign an alternative "self" reference when referring to "this" within setInterval. Is it possible to accomplish something similar within the context of a prototype method? The following code errors.
function Foo() {}
Foo.prototype = {
bar: function () {
this.baz();
},
baz: function () {
this.draw();
requestAnimFrame(this.baz);
}
};
Unlike in a language like Python, a Javascript method forgets it is a method after you extract it and pass it somewhere else. You can either
Wrap the method call inside an anonymous function
This way, accessing the baz property and calling it happen at the same time, which is necessary for the this to be set correctly inside the method call.
You will need to save the this from the outer function in a helper variable, since the inner function will refer to a different this object.
var that = this;
setInterval(function(){
return that.baz();
}, 1000);
Wrap the method call inside a fat arrow function
In Javascript implementations that implement the arrow functions feature, it is possible to write the above solution in a more concise manner by using the fat arrow syntax:
setInterval( () => this.baz(), 1000 );
Fat arrow anonymous functions preserve the this from the surrounding function so there is no need to use the var that = this trick. To see if you can use this feature, consult a compatibility table like this one.
Use a binding function
A final alternative is to use a function such as Function.prototype.bind or an equivalent from your favorite Javascript library.
setInterval( this.baz.bind(this), 1000 );
//dojo toolkit example:
setInterval( dojo.hitch(this, 'baz'), 100);
i made a proxy class :)
function callback_proxy(obj, obj_method_name)
{
instance_id = callback_proxy.instance_id++;
callback_proxy.instances[instance_id] = obj;
return eval('fn = function() { callback_proxy.instances['+instance_id+'].'+obj_method_name+'(); }');
}
callback_proxy.instance_id = 0;
callback_proxy.instances = new Array();
function Timer(left_time)
{
this.left_time = left_time; //second
this.timer_id;
this.update = function()
{
this.left_time -= 1;
if( this.left_time<=0 )
{
alert('fin!');
clearInterval(this.timer_id);
return;
}
}
this.timer_id = setInterval(callback_proxy(this, 'update'), 1000);
}
new Timer(10);

Categories

Resources