避免在 ES6 的函数内定位 this 的对象作用域

2024-05-19

例如,我正在使用 D3.js 运行一个项目,导入特定模块并调用它们的函数。

Setup:

  • TypeScript/ES6
  • 导入特定的 D3 组件
  • 角6

我有一个对象(在本例中是一个角度指令),并在 SVG 画布上绘制一些圆圈,并希望它们在拖动事件上触发函数。

减少的代码片段: 请看一下drawPoints()在这个片段的底部

import { ElementRef, HostListener, Output, EventEmitter, OnInit, Input, OnChanges, SimpleChanges, Directive } from '@angular/core';
import * as Selection from 'd3-selection';
import * as Shape from 'd3-shape';
import * as Random from 'd3-random';
import * as Drag from 'd3-drag';

import { Config } from './../models/config.model';
import { Point } from './../models/point.model';
import { Param } from './../models/param.model';

@Directive({
  selector: '[appCanvas]'
})
export class CanvasDirective implements OnInit, OnChanges {
  private canvas: any;
  private defs: any;
  private gradient: any;
  private svg: any;
  private expandedPoints: Point[];
  private drag: Point;
  public config: Config;

  @Input()
  private param: Param;

  @Output()
  private emitConfig: EventEmitter<Config>;

  @HostListener('window:resize', ['$event'])
  private onResize(event) {
    this.init();
  }

  constructor(
    private el: ElementRef
  ) {
    this.canvas = el.nativeElement;
    this.emitConfig = new EventEmitter();
  }

  ngOnInit() {
    intSvg();
    // ..
  }

  private initSvg() {
    if (!this.svg) {
      this.svg = Selection.select(this.canvas).append('svg');
    }
    this.svg
      .attr('width', this.config.width)
      .attr('height', this.config.height);
  }

  private drawPoints(points: Point[]) {
    points.forEach(point => {
      this.svg.append('circle')
        .attr('r', point.color ? 20 : 10)
        .attr('cx', point.x)
        .attr('cy', point.y)
        .attr('fill', point.color ? point.color : 'lightgray')
        .attr('stroke-width', !point.color ? 2 : 0)
        .attr('stroke', !point.color ? 'gray' : '')
        .call(Drag.drag()
          .on('drag', () => {
            // What to call here?
            // Selection.select(this) will not work
            // So how to target the correct „this“?
          }));
    });
  }
  // ...
}

出现的问题是无法到达正确的位置this在附加圆圈的拖动功能内。

那里有多个示例,但它们在课堂上不起作用,因为this参数受到保护。

归功于 Mike Bostock 的例子https://bl.ocks.org/mbostock/22994cc97fefaeede0d861e6815a847e https://bl.ocks.org/mbostock/22994cc97fefaeede0d861e6815a847e


像 D3 这样的旧库依赖于动态thiscontext 而不是将所有必要的数据作为参数传递并需要使用const self = this达到词汇的技巧this在回调中。这个技巧在 ES6 中被认为是过时的,但在这种情况下是必要的。为了获得动态上下文,需要使用常规函数而不是箭头:

private drawPoints(points: Point[]) {
  const self = this;
  ...
    .call(Drag.drag()
      .on('drag', function (this: ProperContextTypeIfNecessary) {
        Selection.select(this);
        // class instance can be referred as `self`
      }));
});

类实例应该被称为似乎不一致this在一个地方和self在另一个中(这在 ES5 中不是问题,因为self为了一致性,应该在这种情况下彻底使用)。

正如中所解释的这个相关答案 https://stackoverflow.com/a/47661894/3731501,另一种方法是包装函数,它将提供回调函数 D3 上下文作为参数,而this仍然可以引用类实例。在这种情况下可以使用箭头函数:

function contextWrapper(fn) {
    const self = this;

    return function (...args) {
        return fn.call(self, this, ...args);
    }
}

...

private drawPoints(points: Point[]) {
  const self = this;
  ...
    .call(Drag.drag()
      .on('drag', contextWrapper((d3Context: ProperContextTypeIfNecessary) => {
        Selection.select(d3Context);
        // class instance can be referred as `this`
      }));
});
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

避免在 ES6 的函数内定位 this 的对象作用域 的相关文章

  • 在 React 组件中等待异步函数并显示 Spinner

    初学者在这里 尝试从服务器获取一些数据并在获取后将其显示在我的反应组件中 但是 我在将异步函数集成到我的反应组件中时遇到了麻烦 import React useState from react import request from gra
  • 使用javascript滚动滚动条或鼠标滚轮后触发事件

    我想知道是否可以触发事件after使用滚动条或鼠标滚轮 或在触摸设备上滑动 时滚动页面 基本上 我想检测用户何时停止滚动 以便我可以进行 AJAX 加载 而不是在滚动时加载 看起来jQuery s scroll 每次用户滚动时都会触发 并且
  • 是否可以在 TypeScript 中生成带有模板文字的字符串文字组合?

    是否可以在 TypeScript 中生成字符串文字与模板文字组合的排列 type MetaKey meta type CtrlKey ctrl type ShiftKey shift type AltKey alt type Modifer
  • 用更好的模式替换开关(Javascript)

    我必须升级我的应用程序以根据用户类型和角色属性显示页面 目前 我使用一个简单的 switch 语句来根据用户类型来执行此操作 例如 switch type case a return CONSTANT ONE case b return C
  • 使用 babel env 预设时,展开运算符出现语法错误

    我正在努力 现代化 meern io 入门样板 https github com Hashnode mern starter通过替换巴别塔es2015 and stage 0预设为env 然而 似乎env预设无法识别以下片段client m
  • 无需重定向的 HTML 页面提交

    有没有什么方法可以在不使用ajax的情况下提交html表单而无需从当前页面重定向 你可以设置一个target 为您form 这样您就可以将表单提交到新选项卡 target blank 或一个小的 隐藏的iframe target nameo
  • 插件 gulp-babel 错误:插件/预设文件不允许导出对象,只能导出函数

    我现在尝试在我的 Ionic v1 应用程序中使用 JavaScript 2015 ES6 包 json name test version 1 0 0 dependencies ionic native deeplinks 4 18 0
  • 在给定索引上将字符串分成两部分并返回两部分

    我有一个字符串 需要在给定索引上拆分 然后返回两个部分 并用逗号分隔 例如 string 8211 8 211 98700 98 700 因此 我需要能够在任何给定索引上拆分字符串 然后返回字符串的两半 内置方法似乎执行分割 但只返回分割的
  • 如何在数据表角度中基于 JSON 动态填充表值?

    我在用着Angular 数据表 https l lin github io angular datatables 我需要能够根据返回的数据动态创建表 换句话说 我不想指定列标题 Example json数据 id 2 city Baltim
  • JS:修改 JS 对象中的值/对

    我正在尝试找出修改对象的最佳方法 而无需三次写出类似的对象 所以我有这三个对象 var object1 start start end end type 1 var object2 start start end end type 2 va
  • 如何让php页面从html页面接收ajax post

    我有一个非常简单的表单 其中有一个名字输入字段 我捕获了表单数据 并使用标准 jQuery 发布方法通过 ajax 将其传输到 PHP 页面 但是 我根本无法从 PHP 页面获得任何在服务器端捕获数据的响应 我不确定我做错了什么或缺少什么
  • 为什么 TypeScript 混合了模块和原型模式?

    我正在查看此页面上 TypeScript 生成的 JS 代码 http www typescriptlang org Playground http www typescriptlang org Playground 基本上 要创建一个Gr
  • chrome 选项卡/窗口中的 window.open 行为

    我有一小段 javascript 旨在打开两个或更多选项卡 这在 FF 和 IE 中工作正常 但 chrome 会在新窗口而不是选项卡中打开第二个窗口 它不依赖于 url 因为我已经尝试过使用两个相同的 url 第一个在选项卡中打开 第二个
  • 如何禁用网页中的萤火虫?

    如何使用 Javascript 禁用 firebug 我想这样做是为了向访问者隐藏我的网页的运作方式 有什么选择可以做到这一点吗 你不能 你能做的最好的事情就是混淆你的 JavaScript 实际上刮掉了 您能做的最好的事情就是将所有安全关
  • jQuery:向左滑动和向右滑动

    我见过slideUp and slideDown在 jQuery 中 左右滑动的功能 方式怎么样 您可以使用 jQuery UI 中的附加效果来做到这一点 详情请参阅此处 http docs jquery com UI Effects Sl
  • jQuery UI 对话框 - 关闭后无法打开

    我有一个问题jquery ui dialog box https jqueryui com dialog 问题是 当我关闭对话框然后单击触发它的链接时 除非刷新页面 否则它不会再次弹出 如何在不刷新实际页面的情况下回调对话框 下面是我的代码
  • 如何得知客户端从服务器的下载速度?

    根据客户的下载速度 我想以低质量或高质量显示视频 任何 Javascript 或 C 解决方案都是可以接受的 Thanks 没有任何办法可以确定 您只能测量向客户端发送数据的速度 如果没有来自客户端的任何类型的输入来表明其获取信息的速度 您
  • 尽管设置了元数据,Reflect.getMetadata() 返回未定义

    我正在尝试在我的 TypeScript 应用程序中使用注释 但是我一定做错了什么 因为Reflect getMetadata 总是返回undefined 尽管我可以在调试器中看到元数据似乎设置正确 my class ts 带有带注释的属性
  • 拉斐尔路径交叉点不起作用

    我对拉斐尔和 pathIntersection method JSFiddle 示例 http jsfiddle net t6gWt 2 您可以看到有两条线都与曲线相交 但当我使用 pathIntersection method 有一个未解
  • 在引导程序中以编程方式更改选项卡窗格选项卡

    我使用的选项卡窗格定义为 ul class nav nav tabs li a href personal Personal Information a li li class active a href contact Contact a

随机推荐