Promise.then execution context when using class methods as a callback

Why Promise.thendoes it convey the execution context undefinedwhen using the class method as a callback and windowwhen using the "normal function"?

Does a class method refer to its own object / class? and why undefined, and not window?

function normal() {
    console.log('normal function', this);
}
const arrow = () => {
    console.log('arrow function', this);
}

function strictFunction() {
    'use strict';
    console.log('strict function', this);
}

class Foo {
    test() {
        this.method(); // Foo
        Promise.resolve().then(() => console.log('inline arrow function', this)); // Foo
        Promise.resolve().then(normal); // window
        Promise.resolve().then(arrow); // window
        Promise.resolve().then(strictFunction); // undefined
        Promise.resolve().then(this.method); // undefined <-- why?
    }

    method() {
        console.log('method', this);
    }
}

const F = new Foo();
F.test();

( jsFiddle )

I would expect the context to this.methodbe lost, but I can’t understand why the different behavior between this.methodboth the “normal” and the arrow functions.

? , , Promises A +, , " this undefined , global object.".

+6
4

, , , :

this undefined ; .

ES6 , :

ClassDeclaration ClassExpression

, - , this undefined.

class A {
  method() {
    console.log(this);
  }
}

const a = new A();
a.method(); // A
const unboundMethod = a.method;
unboundMethod(); // undefined
Hide result

, , , this undefined , .

normal arrow this window, , , .


promises then, undefined this, this.

PromiseReactionJob spec:

PromiseReactionJob , .

...
let handlerResult be Call(handler, undefined, «argument»).

- this, undefined.

+7

Promises, , this.

1:

this.method(); // Foo

method - , Foo, this , , this this.method. , Foo.

2:

Promise.resolve().then(() => console.log('inline arrow function', this)); // Foo

- ES6, this , . , this === Foo, .

3:

Promise.resolve().then(normal); // window
Promise.resolve().then(arrow); // window

, , , this , strict mode.

4:

Promise.resolve().then(strictFunction); // undefined

strict mode , , this undefined.

5:

Promise.resolve().then(this.method); // undefined <-- why?

spec , :

ClassDeclaration ClassExpression .

+2

this.method undefined, , , , , . , , .

, bind.

Promise.resolve().then(this.method.bind(this))

. :

Promise.resolve().then(((self) => () => self.method())(this))

.

, , , .

:

const a = () => {};

class Foo {
    a() {}
}
const foo = new Foo();

console.log(a); // just a function
console.log(foo.a) // just a function
console.log(foo.a()) // a function called with a context of foo

, foo.a(), , foo.a.call(foo), a foo. foo.a foo, , foo.a.call(window) ( global Node).

, . , , bind, .

class Foo {
  constructor() {
    this.b = this.b.bind(this);
  }
  
  a () {
    return this;
  }
  
  b () {
    return this;
  }
}

const foo = new Foo();
const a = foo.a;
const b = foo.b;
const bound = foo.a.bind(foo);

console.log('A', foo.a().constructor.name);
console.log('A', a());
console.log('A', a.apply(foo).constructor.name);
console.log('A', bound().constructor.name);

console.log('B', foo.b().constructor.name);
console.log('B', b().constructor.name);
Hide result
0

"".

app.component.ts

export class AppComponent implements OnInit {
  public cards: Card[] = [];
  public events: any[] = [];

  constructor(private fbService: FacebookService) {
    this.fbService.loadSdk();
  }

  ngOnInit() {
    const self = this;

    this.fbService.getEvents().then((json: any) => {
      for (const event of json.data)
      {
        self.cards.push(
          new Card({
            imageUrl: 'assets/ny.jpg',
            id: event.id,
            name: event.name
          }),
        );
      }
    });
  }
}

fb.service.ts

import { BehaviorSubject } from 'rxjs/Rx';
import { Injectable, NgZone } from '@angular/core';
import { Http } from '@angular/http';


declare var window: any;
declare var FB: any;

@Injectable()
export class FacebookService {
  events: any[];

  public ready = new BehaviorSubject<boolean>(false);

  constructor(private zone: NgZone) {
  }

  public loadSdk() {
    this.loadAsync(() => { });
  }


  public loadAsync(callback: () => void) {
    window.fbAsyncInit = () => this.zone.run(callback);
    // Load the Facebook SDK asynchronously
    const s = 'script';
    const id = 'facebook-jssdk';
    const fjs = document.getElementsByTagName(s)[0];
    // tslint:disable-next-line:curly
    if (document.getElementById(id)) return;

    const js = document.createElement(s);
    js.id = id;
    js.src = 'http://connect.facebook.net/en_US/all.js';
    fjs.parentNode.insertBefore(js, fjs);
  }

  public getEvents(): Promise<any> {
    return new Promise((resolve, reject) => {
      FB.init({
        appId: 'app_id',
        xfbml: true,
        status: true, 
        cookie: true,
        version: 'v2.10'
      });

      FB.api(
        '/salsaparty.bg/events',
        'GET',
        {
          access_token: 'acess_token'
        },
        function (response) {
          resolve(response);
        }
      );
    });
  }
}
0

Source: https://habr.com/ru/post/1014189/


All Articles