【问题标题】:this is referring to the class which it is part of and not the one from which the instance is calledthis 指的是它所属的类,而不是调用实例的类
【发布时间】:2020-07-06 14:09:40
【问题描述】:
class ElPush {
  pushElement(type) {
    document
      .querySelector(`#${type}-projects`)
      .querySelectorAll("li")
      .forEach((el) => {
        this.itemLog.push(el);
      });
  }
}

我想使用 ElPush 类将元素推送到 itemLog 数组中,该数组存在于下面给出的 ActiveItem 类中

class ActiveItem {
  constructor() {
    this.itemLog = [];
    const elPush = new ElPush();
    elPush.pushElement("active");

    console.log(this.itemLog);
  }
}
class FinishedItem {
  constructor() {
    this.itemLog = [];
    const elPush = new ElPush();
    elPush.pushElement("finished");

    console.log(this.itemLog);
  }
}
class App {
  static init() {
    const activeList = new ActiveItem();
  }
}
App.init();

ElPush 中的 this.itemLog.push(el); 行抛出错误 Cannot read property 'push' of undefined

我知道这不是一个实用的解决方案,但我只是在练习 opp 概念,并且非常希望提供任何解决方案

【问题讨论】:

  • 当您在ElPush.pushElement 中使用ActiveItem 方法时,您要么必须在那里传递ActiveItem 实例,要么将相应的容器属性添加到ElPush
  • 我不明白; itemLog 不是 ElPush 的属性;你为什么希望这能奏效?
  • 如果 OP 想要保留基于类的方法,那么 itemLog 应该是任何 ElPush 实例的属性,而不是 ActiveItem 实例的属性。如示例代码所示,后者中的日志记录应为console.log(elPush.itemLog)。将itemLog 保留为任何ActiveItem 实例的属性的任何方法都必须通过其他非基于类的(组合)技术来提供push 功能。
  • 实际上有多个类需要ElPush所以每个类的itemLog应该是不同的,我想要的是使用相同的ElPush类根据Type参数在不同的item Log中推送不同的元素推元素。
  • @abhinaykhalatkar ... "... 我只想使用相同的 ElPush 类根据 pushElement 的 Type 参数在不同的项目日志中推送不同的元素。" ...但是对于这项任务,根本不需要类抽象。一个简单的辅助/实用功能已经足够完成这项工作了。

标签: javascript oop this


【解决方案1】:

// - still class based for being recognizable to the OP.
// - the query part should be refactored
//   as simple helper/utility function.
//
class ProjectItemQuery {
  query(type) {
    return Array.from(document
      .querySelector(`#${ type }-projects`)
      .querySelectorAll("li")
    );
  }
}

// refactored query helper.
function queryProjectItems(type) {
  return Array.from(document
    .querySelector(`#${ type }-projects`)
    .querySelectorAll("li")
  );
}

class ActiveItems {
  constructor() {
    const itemQuery = new ProjectItemQuery;

    this.list = itemQuery.query("active");
  //this.list = queryProjectItems("active");

    console.log('ActiveItems :: list : ', this.list);
  }
}

class FinishedItems {
  constructor() {
    this.list = queryProjectItems("finished");

    console.log('FinishedItems :: list : ', this.list);
  }
}

class App {
  static init() {
    const activeItemList = (new ActiveItems).list;
    const finishedItemList = (new FinishedItems).list;

    console.log('App :: init :: activeItemList : ', activeItemList);
    console.log('App :: init :: finishedItemList : ', finishedItemList);
  }
}
App.init();
.as-console-wrapper { min-height: 100%!important; top: 0; }
<ul id='active-projects'>
  <li>foo</li>
  <li>bar</li>
</ul>

<ul id='finished-projects'>
  <li>baz</li>
  <li>biz</li>
</ul>

编辑

  • abhinay khalatkar

我已经采用了这种返回方法,但我想知道的是,如果上述方式可行吗?我的意思是是否可以从不同的类 (b) 更改类 (a) 的属性如果在此类(a)中实例化类(b),则使用“bind()”和“this”?我不想要一种解决方法,而是一种直接的方法来做到这一点。如果不是,我将采用这种方式。感谢 A2A。

一个

  • 彼得·塞利格

当然可以......甚至有很多方法可以完成这项任务。但是为什么要在设计中增加更多的复杂性(这里......不太好阅读,更容易搞砸,因此更容易出错)而不是保持它的简洁和轻量级?

将上面给出的示例代码与接下来提供的示例代码进行比较。前者发生的事情比现在发生的事情更具可读性/清晰/可理解性......

// - a less favourable, function based, mixin approach
//
function ProjectItemQueryMixin() {
  if (!Array.isArray(this.list)) {
    this.list = [];
  } 
  this.queryAndPush = function (type) {
    document
      .querySelector(`#${ type }-projects`)
      .querySelectorAll("li")
      .forEach(elm => this.list.push(elm));
  }
}

class ActiveItems {
  constructor() {
    // this.list = [];

    // - Applying the mixin based `query` 
    //   method directly to an instance
    //   is the less favourable way.
    ProjectItemQueryMixin.call(this);

    this.queryAndPush("active");

    console.log('ActiveItems :: list : ', this.list);
  }
}

class FinishedItems {
  constructor() {
    // this.list = [];

    this.queryAndPush("finished");

    console.log('FinishedItems :: list : ', this.list);
  }
}
ProjectItemQueryMixin.call(FinishedItems.prototype);
// - Applying the mixin based `query` method to the
//   prototype was the choice for everyone that is
//   concerned about design and memory usage.
// - A lot of developers will find this confusing as well.

class App {
  static init() {
    const activeItemList = (new ActiveItems).list;
    const finishedItemList = (new FinishedItems).list;

    console.log('App :: init :: activeItemList : ', activeItemList);
    console.log('App :: init :: finishedItemList : ', finishedItemList);
  }
}
App.init();
.as-console-wrapper { min-height: 100%!important; top: 0; }
<ul id='active-projects'>
  <li>foo</li>
  <li>bar</li>
</ul>

<ul id='finished-projects'>
  <li>baz</li>
  <li>biz</li>
</ul>

第三次迭代,这次尽可能接近 OP 的代码

// ... Again, one does not need a class instance for this task.
//
// A simple function/method with `this` context called
// `queryAndPushProjectItems(type)` would already solve
// the OP's problem.
//
class ProjectItemQuery {
  queryAndPush(type) {
    document
      .querySelector(`#${ type }-projects`)
      .querySelectorAll("li")
      .forEach(elm => this.list.push(elm));
  }
}

class ProjectItems {
  // - The constructor's `type` argument prevents
  //   copying over and over the same item class
  //   related code that just differs in how items
  //   are going to be queried.
  constructor(type) {
    this.list = [];

    const itemQuery = new ProjectItemQuery;

    // - This code block answers th OP's question.
    // - Call `queryAndPush` of the above created
    //   `ProjectItemQuery` instance within the
    //   `this` context of any `ProjectItems`
    //   instance.
    // - Of course this is not a desirable design.
    itemQuery.queryAndPush.call(this, type);
    // - or ...
    // `queryAndPushProjectItems.call(this, type);`

    console.log('ProjectItems :: type, list : ', type, this.list);
  }
}

class App {
  static init() {
    const activeItems = new ProjectItems('active');
    const finishedItems = new ProjectItems('finished');

    console.log('App :: init :: activeItems.list : ', activeItems.list);
    console.log('App :: init :: finishedItems.list : ', finishedItems.list);
  }
}
App.init();
.as-console-wrapper { min-height: 100%!important; top: 0; }
<ul id='active-projects'>
  <li>foo</li>
  <li>bar</li>
</ul>

<ul id='finished-projects'>
  <li>baz</li>
  <li>biz</li>
</ul>

【讨论】:

  • 我已经采用了这种返回方法,但我想知道的是,如果上述方式可行吗?我的意思是是否可以将类 (a) 的属性从如果在此类(a)中实例化了类(b),则使用“bind()”和“this”使用不同的类(b)?我不想要一种解决方法,而是一种直接的方法来做到这一点。如果不是,我将采用这种方式。感谢您的 A2A。
  • 当然可以......甚至有很多方法可以完成这项任务。但是为什么要在设计中增加更多的复杂性(这里......不太好阅读,更容易搞砸,因此更容易出错)而不是保持它的简洁和轻量级?
  • 感谢您的快速响应。是的,我明白你的意思,如果有更多方法负责更改列表,直接方式只会使跟踪我的原始列表项变得更加困难,但只是为了练习,我怎样才能做到这一点?我的意思是使用 ElPush 直接更改元素 itemLog(不是从实例返回值,而是直接从 ElPush 类返回)。
  • 我不太明白......我的每一个给定方法都完全符合你的要求...... "......我想做的是为finishItems定义一个列表和 ActiveItems(表示相应类中的两个不同列表)。” ...是 (...两个不同的列表,每个列表都在其特定/各自的类中)。 顺便说一句,甚至不需要两个查询不同的类实现。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-03
  • 2021-05-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-06-15
相关资源
最近更新 更多