2
let user = {
  firstName: "John",
  sayHi: () => alert(this.firstName)
    
};

let user2 = {
  firstName : "Mike",
  testFun : function(){let argFun = user.sayHi; argFun();} // Hello, undefined!
};

I understand that if I had invoked user.sayHi it would have received the value of this from the environment user was created in. But if I copy the value of user.sayHi to argFun, why doesn't this problem disappear, and isn't the code just equivalent to:

...
let user2 = {
  firstName : "Mike",
  testFun : function(){let argFun = () => alert(this.firstName); argFun();} // Hello, undefined!
};
DaddyMike
  • 161
  • 11
  • 1
    `argFun` is a function. It is not bound to `user` (or to `user2` in the second example). You have to either call it through `user` or `user2` or [bind it](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind) to `user` (or `user2`) then invoke the standalone function returned by `Function.bind()`. This is how JavaScript works. – axiac Sep 22 '20 at 18:11
  • Yes but wouldn't it just get the this from the outer function, the function testFun itself like a normal arrow function? – DaddyMike Sep 22 '20 at 18:13
  • 1
    The examples are not equal. In the former, the arrow function is a method of the object, and `this` refers to the object `user` is defined (most likely `window`). In the latter, when the arrow function is inside the method of the object, `this` refers to the object. Also, as axiac said, in the first example you're not calling the method in any context, but adding the context wouldn't fix the problem, because you can''t bind an arrow function. Simply don't use arrow functions as methods in object literals (in a constructor function it works fine). – Teemu Sep 22 '20 at 18:16
  • @Teemu so basically copying user.sayHi to argFun doesn't change anything and argFun still looks at the place user.sayHi was declared to determine the value of this? – DaddyMike Sep 22 '20 at 18:20
  • 1
    Yep, copying a function doesn't copy the context (a copy of a function is just a copy of the reference). In the first case it's the arrow function generating its own this, which is always the lexical environment. – Teemu Sep 22 '20 at 18:24
  • I don't know how to explain the results you're getting but is this what you're looking for? `const myVar = { firstname: 'John', sayHi: () => { return myFunc(myVar.firstname); } } function myFunc(name){ console.log("Hello, " + name); } myVar.sayHi();` – FernandoG Sep 22 '20 at 18:27
  • @Teemu if a copy of a function is just a copy of the reference then how come that a method copied from an object to another object gives different, correct values of this while copying an arrow function does not? Is it just because they are arrow functions? – DaddyMike Sep 22 '20 at 18:36
  • @FernandoG I want to get the name of the object the current method is situated in. – DaddyMike Sep 22 '20 at 18:38
  • 2
    Yes, exactly because they are arrow functions. The context is defined when you're calling a function, except an arrow function, which takes the `this` value from it's lexical environment, nevertheless how you're calling it. – Teemu Sep 22 '20 at 18:40
  • 1
    In `user2.textFun` you can simply call `user.sayHi`, but `user.sayHi` must be created as a function, not an arrow function. With an arrow function defined method even `user.sayHi()` gives you `undefined`. – Teemu Sep 22 '20 at 18:49
  • 2
    @DaddyMike The reason a method (defined with `function` and using `this`) gives a different result when copied to another object is because `this` is assigned when the method is invoked, not when defined, similar to the method arguments. When I call `foo.hi()` `foo` will be passed in as `this`, if we copy the method over to `bar` and call `bar.hi()` `bar` will be passed in as `this`. If you call the method by itself (without receiver) `hi()` then `window` will be passed in as `this` or `undefined` when using strict mode. – 3limin4t0r Sep 22 '20 at 18:53
  • @Teemu Thanks, I get it now – DaddyMike Sep 22 '20 at 18:56
  • @Teemu You can also define `user.sayHi` as an arrow function, by replacing `this` with the object in question. `const user = { firstname: "John", sayHi: () => alert(user.firstname) }`. – 3limin4t0r Sep 22 '20 at 19:00

1 Answers1

1

This great answer is quite helpful: Are 'Arrow Functions' and 'Functions' equivalent / interchangeable? To quote the pertinent part...

If the function you want to replace does not use this, arguments and is not called with new, then yes[, arrow functions and functions are equivalent].

Your function uses this, so, if you want to use an arrow function, define it in the constructor...

function User(firstName) {
  this.firstName = firstName;
  
  this.sayHi = () => {console.log("Hi, " + this.firstName + "!")}
}

let user = new User("John");
let user2 = new User("Mike");

user.sayHi();
user2.sayHi();
HoldOffHunger
  • 18,769
  • 10
  • 104
  • 133
  • 1
    This also works within a `constructor` function of a class. – Teemu Sep 22 '20 at 18:42
  • But why does the this in this.firstName (in this.sayHi) refer to the object itself now instead of the window? I mean shouldn't it look for this inside the this of the User constructor? – DaddyMike Sep 22 '20 at 19:18
  • The `this` in the constructor refers to the object. Constructors in most languages (including JS) return the object, so, naturally, the `this` is the object and not the window. – HoldOffHunger Sep 22 '20 at 19:18
  • I don't mean the this to the left of the equal signs, I mean the this inside the arrow function itself. It just seems counterintuitive to me that defining an arrow function with a constructor is not equivalent to defining it by simply assigning it inside the object. – DaddyMike Sep 22 '20 at 19:20
  • You are right, it is a bit counterintuitive, since arrow functions are often called "ECS6 functions", and why should function-behavior change? Etc., etc., but, it just is because that's the spec. – HoldOffHunger Sep 22 '20 at 19:26
  • 1
    I wouldn't say the difference being counterintuitive. Both of the functions has their own task, they are purposed to solve different problems, like Arrays and Objects ... – Teemu Sep 22 '20 at 19:31