Javascript 使用类方法作为回调时的Promise.then执行上下文

Javascript 使用类方法作为回调时的Promise.then执行上下文,javascript,ecmascript-6,promise,es6-promise,Javascript,Ecmascript 6,Promise,Es6 Promise,为什么承诺。那么在使用类方法作为回调时传递未定义的执行上下文,在使用“普通函数”时传递窗口的执行上下文 类方法是否与其拥有的对象/类分离?为什么未定义而不是窗口 function normal() { console.log('normal function', this); } const arrow = () => { console.log('arrow function', this); } function strictFunction() { 'use

为什么
承诺。那么
在使用类方法作为回调时传递
未定义的执行上下文
,在使用“普通函数”时传递
窗口的执行上下文

类方法是否与其拥有的对象/类分离?为什么
未定义
而不是
窗口

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();
功能正常(){
console.log('正常功能',此项);
}
常数箭头=()=>{
log('arrow function',这是);
}
函数strictFunction(){
"严格使用",;
log('strict function',this);
}
福班{
测试(){
this.method();//Foo
Promise.resolve().then(()=>console.log('inline arrow function',this));//Foo
Promise.resolve().then(正常);//窗口
Promise.resolve().then(箭头);//窗口
Promise.resolve().then(strictFunction);//未定义

Promise.resolve().then(this.method);//undefined之所以
this.method
未定义,是因为当您这样使用它时,实际上只是将没有上下文的函数作为回调函数。因此,当它运行时,它不知道这一点

如果要维护上下文,请使用
bind
函数

Promise.resolve().then(this.method.bind(this))
Bind将上下文绑定到方法。它本质上等同于:

Promise.resolve().then(((self) => () => self.method())(this))
它是一个包装器,用于将上下文映射到范围中的变量

对于类方法,当您将其作为变量获取时,它与包含函数引用的变量基本上没有区别

Promise.resolve().then(this.method.bind(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(窗口)
(或
global
节点中的操作相同)

这里有一些代码说明了它们之间的区别。您还可以看到,如果您
绑定它,它将如何维护上下文

class-Foo{
构造函数(){
this.b=this.b.bind(this);
}
a(){
归还这个;
}
b(){
归还这个;
}
}
const foo=新foo();
常数a=foo.a;
常数b=foo.b;
常量绑定=foo.a.bind(foo);
log('A',foo.A().constructor.name);
log('A',A());
console.log('A',A.apply(foo.constructor.name));
log('A',bind().constructor.name);
log('B',foo.B().constructor.name);

console.log('B',B().constructor.name);
这里的引用告诉您原因:

在严格模式下,
将在内部未定义;在松散模式下,它将是全局对象

报告说:

类声明或类表达式的所有部分都是严格的模式代码

因此,由于严格模式,未绑定类方法中的
将是
未定义的

A类{
方法(){
console.log(this);
}
}
常数a=新的a();
a、 方法();//a
const unboundMethod=a.method;

unboundMethod();//undefined
这与承诺无关,而是调用此
的上下文

案例1:

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
是在
Foo
类中定义的函数,因此
this
被评估为触发函数的对象,即
this.method
中的
this
。因此显示了-
Foo

案例2:

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?
箭头函数是ES6的一个特性,它的唯一属性是
this
上下文位于定义它的封闭上下文中。函数是在
this===Foo
的上下文中调用的,所以显示的就是这个

案例3:

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?
arrow函数保留其上下文作为窗口,因为它是一个arrow函数,而正常函数在没有上下文的情况下进行求值,在这种情况下,
在不处于
严格模式
时被求值为窗口

案例4:

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?
由于
严格模式
是在窗口上声明的函数体中请求的,
被评估为未定义

案例5:

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?

Promise.resolve().then(this.method);//undefined在我的例子中,它帮助了定义“self”的简单解决方案

应用程序组件.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
          }),
        );
      }
    });
  }
}
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);
        }
      );
    });
  }
}
fb.service.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
          }),
        );
      }
    });
  }
}
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);
        }
      );
    });
  }
}
从'rxjs/Rx'导入{BehaviorSubject};
从“@angular/core”导入{Injectable,NgZone};
从'@angular/Http'导入{Http};
声明变量窗口:任意;
声明var FB:任何;
@可注射()
导出类FacebookService{
事件:任何[];
public ready=新行为主体(false);
建造商(专用区:NgZone){
}
公共加载SDK(){
this.loadAsync(()=>{});
}
公共loadAsync(回调:()=>void){
window.fbasyninit=()=>this.zone.run(回调);
//异步加载Facebook SDK
常量s='script';
const id='facebook jssdk';
const fjs=document.getElementsByTagName[0];
//tslint:禁用下一行:卷曲
if(document.getElementById(id))返回;
const js=document.createElement;
js.id=id;
js.src=http://connect.facebook.net/en_US/all.js';
fjs.parentNode.insertBefore(js,fjs);
}
public getEvents():承诺{
返回新承诺((解决、拒绝)=>{
FB.init({
appId:“app_id”,
xfbml:是的,
状态:正确,
曲奇:是的,
版本:“v2.10”
});
FB.api(
“/salsaparty.bg/events”,
“得到”,
{
访问令牌:“访问令牌”
},
功能(响应){
决心(回应);
}
);
});
}
}

作为
obj传递的类方法引用。方法始终与
obj
分离-这不是特定的。@Alnitak但是为什么
未定义