【问题标题】:ES6: Access two different scopes (class-global and object-local) in the same functionES6:在同一个函数中访问两个不同的作用域(类全局和对象局部)
【发布时间】:2018-07-01 19:03:07
【问题描述】:

这有点难以解释。请原谅这个牵强的例子。

我想在同一个函数中访问两个不同的作用域(类全局和对象局部)。所述函数是一个对象方法。

我使用的是babel-preset-react-native,应该是 ES6 (https://facebook.github.io/react-native/docs/javascript-environment.html)。

给定以下示例类:

class Logic {

  constructor() {
    this.keys = ['Red Key', 'Blue Key'];
  }

  hasKey = (searchKey) => {
    return this.keys.includes(searchKey);
  }

  allowedToEnter = {
    redHouse: () => {
      // some logic
      return true;
    },
    // ...
  };

  houses = [
    {
      name: 'Red House',
      isAccessible: () => {
        return this.hasKey('Red Key');
      },
      shouldAccess__Global: () => {
        return /* wrong scope */this.isAccessible() && this.allowedToEnter.redHouse();
      },
      shouldAccess__Local: function () {
        return this.isAccessible() && /* wrong scope */this.allowedToEnter.redHouse();
      },
    },
    // ...
  ];
}

let logic = new Logic();
console.log(logic.houses[0].shouldAccess__Global());
// returns: isAccessible is not a function
console.log(logic.houses[0].shouldAccess__Local());
// returns: Cannot read property 'redHouse' of undefined

定义箭头函数将类范围绑定到this。使用经典的函数语法,它将this 绑定到它的“所有者”的范围内,即数组内的房屋对象。我明白,在这两种情况下,这都是正确的行为。

是否有一种优雅的方式来编写 shouldAccess 方法,同时提供对两个范围的访问权限?

我想出的一个可能的解决方案如下:

shouldAccess__withHelper: function () {
  return this.isAccessible() && this.helper().allowedToEnter.redHouse();
},
helper: () => {
  return this;
},

这不是优雅的想法。我的阵列中有大量的房屋物品。给每个对象一个辅助函数很糟糕。

我知道整个数据结构有点复杂,并不理想。我不是在寻求关于如何更好地构建我的代码的建议。 我正在处理给定结构中的大量逻辑,重构所有内容将是一个巨大的痛苦。

【问题讨论】:

  • 你不能在函数外声明一个变量,比如...var outerThis = this
  • 根据显示的代码,这应该可以工作:var globalThis = this; class Logic { ... shouldAccess: function () { this.isAccessible() && globalThis.allowedToEnter.redHouse() } ?
  • ty,但是这两个建议都不起作用。 shouldAccess__Local 根本无法访问类范围,因此在类构造函数中定义 outerThis = this 没有帮助。类外的var globalThis = this; 不允许我访问类函数。
  • 根据经验,在 JS OOP 中,this 应该引用类实例。这个问题表明类设计出了问题。您可以使用 class 关键字包装所有内容并不意味着应该这样做。为什么会有Logic 的东西?这听起来不像是一个类的合适实体。它不使用状态,因此不能从实例化中受益,这表明它不应该是一个类。
  • 你说得对,我几乎将遗留代码封装在一个类中。但它确实订阅了一个状态,为了简化,我只是在示例中删除了它。不过你说得很好,也许上课不是正确的方法。

标签: javascript ecmascript-6 scope


【解决方案1】:

Logic 似乎不是一个适合类的实体。虽然房屋似乎是适当的实体,但它们不是类。

根据经验,在 JS OOP 中,this 通常指的是类实例。 Рouses 类可以更轻松地处理房屋逻辑关系,并且通过依赖注入提供“逻辑”实例:

class AbstractHouse {
  constructor(logic, name) {
    this.name = name;
    this.logic = logic;
  }
}

class RedHouse extends AbstractHouse {
  constructor(logic, name = 'Red House') {
    super(logic, name);
  }

  shouldAccess() {
    return this.isAccessible() && this.logic.allowedToEnter.redHouse()
  }
}

class Logic {
  ...
  houses = [new RedHouse(this)];
}

应该为每种房屋类型扩展基类以根据房屋类型显式列出redHouse 方法名称这一事实表明这不是完美的关系,可以改进为更灵活。也不知道有多少种房屋类型,以及为每种类型设置一个类是否是个好主意。

即使没有实际的类,房屋也可以按照某些接口将“逻辑”实例暴露给他们的方法:

  houses = [
    {
      logic: this, // same as dependency injection in house constructor
      name: 'Red House',
      shouldAccess() {
        return this.isAccessible() && this.logic.allowedToEnter.redHouse()
      }
      ...
    }
  ];

【讨论】:

    【解决方案2】:

    整理我的想法并提出问题帮助我想出了另一个可能的解决方案。

    像下面这样定义shouldAccess ...

    shouldAccess__passLogic: function (logic) {
      return this.isAccessible() && logic.allowedToEnter.redHouse();
    },
    

    ... 并在函数调用 (console.log(logic.houses[0].shouldAccess__Local(logic));) 上将类实例传递给该函数确实可以解决问题。不是很漂亮,但至少应该很容易重构。

    不过,我仍然愿意接受其他建议!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-08-21
      • 1970-01-01
      • 2012-12-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-01
      相关资源
      最近更新 更多