调用函数时如何解决“ this”未定义

时间:2019-05-24 09:20:45

标签: angular d3.js

我是d3.js(v5)和angular(v7)的新手,我的问题是每当我调用multiFormat函数格式化日期时,“ this”变得不确定。

我试图直接将此this.d3传递给multiFormat,并且可以使用,但是在这种情况下,我不知道如何传递日期参数... 解决该问题的方法是在addXandYAxis内部声明multiFormat函数并使用所有参数

private addXandYAxis() {
    const d3 = this.d3;
    let dmax = d3.extent(this.data, d => d3.timeParse('%d/%m/%Y')(d.date));
    dmax[0] = dmax[0].setMonth(dmax[0].getMonth() - 1);

    // definition des domains de X & Y 
    const xDomain = this.data.map(d => d.date);
    const yDomain = [0, this.d3.max(this.data, d => d.Donnees)];

    // localisation des dates
    const locale = this.d3.timeFormatLocale({
      dateTime: '%A, %e %B %Y г. %X',
      date: '%d.%m.%Y',
      time: '%H:%M:%S',
      periods: ['AM', 'PM'],
      days: ['Lundi', 'Mardi', 'Mercredi', 'Jeudi', 'Vendredi', 'Samedi', 'Dimanche'],
      shortDays: ['lu', 'ma', 'me' , 'je', 've', 'sa', 'di'],
      months: ['Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet', 'Août', 'Septembre', 'Octobre', 'Novembre', 'Decembre'],
      shortMonths: ['janv.', 'févr.', 'mars', 'avr', 'mai', 'juin', 'juill.' , 'août' , 'sept.' , 'oct.' , 'nov.' , 'déc.' ]
    });

    const formatMillisecond = locale.format('.%L');
    const formatSecond = locale.format(':%S');
    const formatMinute = locale.format('%I:%M');
    const formatHour = locale.format('%I %p');
    const formatDay = locale.format('%a %d');
    const formatWeek = locale.format('%b %d');
    const formatMonth = locale.format('%B');
    const formatYear = locale.format('%Y');

    function multiFormat(date) {
      console.log('date=' + date);
      return(d3.timeSecond(date) < date ? formatMillisecond
      : d3.timeMinute(date) < date ? formatSecond
      : d3.timeHour(date) < date ? formatMinute
      : d3.timeDay(date) < date ? formatHour
      : d3.timeMonth(date) < date ? (d3.timeWeek(date) < date ? formatDay : formatWeek)
      : d3.timeYear(date) < date ? formatMonth
      : formatYear)(date);
      }

我需要在其他地方使用multiFormat,并且我希望避免重复。 我在ngOnInit()中使用addXandYAxis,我的代码是

public addXandYAxis() {
    const d3 = this.d3;
    const dmax = d3.extent(this.data, d => d3.timeParse('%d/%m/%Y')(d.date));

    // define X & Y domains
    const xDomain = this.data.map(d => d.date);
    const yDomain = [0, this.d3.max(this.data, d => d.Donnees)];

    // Abscisse --> date
    this.x = d3.scaleTime()
    .domain(dmax)
    .range([ 0, this.width ]);

    this.xAxis = d3.axisBottom(this.x);

    this.svg.append('g')
    .attr('transform', 'translate(0,' + this.height + ')')
    .call(this.xAxis.tickFormat(this.multiFormat));
  }

 private multiFormat(date) {
    return(this.d3.timeSecond(date) < date ? this.formatMillisecond
      : this.d3.timeMinute(date) < date ? this.formatSecond
      : this.d3.timeHour(date) < date ? this.formatMinute
      : this.d3.timeDay(date) < date ? this.formatHour
      : this.d3.timeMonth(date) < date ? (this.d3.timeWeek(date) < date ? this.formatDay : this.formatWeek)
      : this.d3.timeYear(date) < date ? this.formatMonth
      : this.formatYear)(date);
      }

结果为错误TypeError:“ this.d3未定义”

感谢您的时间:)

2 个答案:

答案 0 :(得分:1)

您可以使用闭包来调用multiFormat 所以你可以这样做

import pygame
import pygame.freetype
import random

# a dict that defines the controls
# w moves up, s moves down etc
CONTROLS = {
    pygame.K_w: ( 0, -1),
    pygame.K_s: ( 0,  1),
    pygame.K_a: (-1,  0),
    pygame.K_d: ( 1,  0)
}

# a function that handles the behaviour a sprite that
# should be controled with the keys defined in CONTROLS
def keyboard_controlled_b(player, events, dt):

    # let's see which keys are pressed, and create a 
    # movement vector from all pressed keys.
    move = pygame.Vector2()
    pressed = pygame.key.get_pressed()

    for vec in (CONTROLS[k] for k in CONTROLS if pressed[k]):
        move += vec

    if move.length():
        move.normalize_ip()

    move *= (player.speed * dt/10)

    # apply the movement vector to the position of the player sprite
    player.pos += move
    player.rect.center = player.pos

# a function that let's a sprite follow another one
# and kill it if they touch each other
def zombie_runs_to_target_b(target):
    def zombie_b(zombie, events, dt):

        if target.rect.colliderect(zombie.rect):
            zombie.kill()
            return

        move = target.pos - zombie.pos

        if move.length():
            move.normalize_ip()

        move *= (zombie.speed * dt/10)
        zombie.pos += move
        zombie.rect.center = zombie.pos

    return zombie_b

# a simple generic sprite class that displays a simple, colored rect
# and invokes the given behaviour
class Actor(pygame.sprite.Sprite):

    def __init__(self, color, pos, size, behavior, speed, *grps):
        super().__init__(*grps)
        self.image = pygame.Surface(size)
        self.image.fill(color)
        self.rect = self.image.get_rect(center=pos)
        self.pos = pygame.Vector2(pos)
        self.behavior = behavior
        self.speed = speed

    def update(self, events, dt):
        self.behavior(self, events, dt)

# a sprite class that displays a timer
# when the timer runs out, a function is invoked
# and this sprite is killed
class WaveCounter(pygame.sprite.Sprite):

    font = None

    def __init__(self, time_until, action, *grps):
        super().__init__(grps)
        self.image = pygame.Surface((300, 50))
        self.image.fill((3,2,1))
        self.image.set_colorkey((3, 2, 1))
        self.rect = self.image.get_rect(topleft=(10, 10))

        if not WaveCounter.font:
            WaveCounter.font = pygame.freetype.SysFont(None, 32)

        WaveCounter.font.render_to(self.image, (0, 0), f'new wave in {time_until}', (255, 255, 255))
        self.timer = time_until * 1000
        self.action = action

    def update(self, events, dt):
        self.timer -= dt

        self.image.fill((3,2,1))
        WaveCounter.font.render_to(self.image, (0, 0), f'new wave in {int(self.timer / 1000) + 1}', (255, 255, 255))

        if self.timer <= 0:
            self.action()
            self.kill()

def main():
    pygame.init()
    screen = pygame.display.set_mode((600, 480))
    screen_rect = screen.get_rect()
    clock = pygame.time.Clock()
    dt = 0
    sprites_grp = pygame.sprite.Group()
    zombies_grp = pygame.sprite.Group()
    wave_tm_grp = pygame.sprite.GroupSingle()

    # the player is controlled with the keyboard
    player = Actor(pygame.Color('dodgerblue'), 
                   screen_rect.center, 
                   (32, 32), 
                   keyboard_controlled_b, 
                   5, 
                   sprites_grp)

    # this function should be invoked once the timer runs out
    def create_new_wave_func():
        # let's create a bunch of zombies that follow the player
        for _ in range(15):
            x = random.randint(0, screen_rect.width)
            y = random.randint(-100, 0)
            Actor((random.randint(180, 255), 0, 0), 
                  (x, y), 
                  (26, 26), 
                  zombie_runs_to_target_b(player), 
                  random.randint(2, 4), 
                  sprites_grp, zombies_grp)

    while True:
        events = pygame.event.get()
        for e in events:
            if e.type == pygame.QUIT:
                return

        # no timer, no zombies => create new timer
        if len(wave_tm_grp) == 0 and len(zombies_grp) == 0:
            WaveCounter(5, create_new_wave_func, sprites_grp, wave_tm_grp)

        sprites_grp.update(events, dt)

        screen.fill((80, 80, 80))
        sprites_grp.draw(screen)
        pygame.display.flip()
        dt = clock.tick(60)

if __name__ == '__main__':
    main()

因为'this'引用了调用函数的范围

答案 1 :(得分:0)

通常,this的问题可以通过将有问题的功能转换为箭头功能来解决:

public addXandYAxis = () => {
// ...

private multiFormat = (date) => { 
// ...