使用 JavaScript 对象构建项目。

2025-06-08

使用 JavaScript 对象构建项目。

你好,世界!这篇文章是一个项目模板。它更像是一个完整的项目,只不过只包含 Javascript(即没有 HTML 或 CSS)。

我一直不太喜欢JavaScript 的对象和类,并非我不了解其基本原理,只是我觉得没必要太担心,因为我认为函数式编程更简单。我一直这么想,到目前为止,我所有的项目都是用函数式编程做的。但当我参加 CodeCademy 的 JavaScript 课程时,我发现了自己对面向对象编程的热爱,对我来说,它更简单,尤其是使用Getters 和 Setters的时候。

在我完成课程的JavaScript 对象模块后,他们(CodeCademy)准备开发一个叫做Meal Maker 的项目。虽然我无法以免费用户的身份访问它,但我理解开发这个项目的目的,即在实际项目中使用Getters 和 Setters 。

有一个问题,我不知道“餐食制作器”是做什么的,也不知道它通常是怎么工作的,但我有个好主意,可以练习一下“Getters 和 Setters”;一个预约应用程序。很棒吧?是的,我知道,它的功能很简单,就是为商务用户预约。

假设我是埃隆马斯克(但我不是),我可以使用此应用程序创建一个帐户,这样其他用户就可以与我预约。

现在,埃隆马斯克不会是唯一拥有商业账户的用户,我们将使用工厂功能(而不是)来复制并拥有我们想要的任意数量的商业账户。

这个应用可能很基础,但它包含了开发预约应用的所有难点。请记住,本文的目的并非向您展示开发预约应用的某种方法,而是向您展示如何在此类项目中使用Getter 和 Setter方法。

如果您不了解 JavaScript Getters 和 Setters 或JavaScript 对象,我建议您学习CodeCademy 的 JS 对象课程

写得够多了,我们开始写代码吧。向下滚动查看完整代码,或者直接访问GitHub 获取代码

// alert: am tired of using John Doe, i wanna use Elon Musk
const elonMusk = {
  _hoursfree: [10, 12, 9], // currently hard-coded, but will change in time
};
Enter fullscreen mode Exit fullscreen mode

_属性前加下划线 ( )的原因hoursFree是,我故意不想让该属性被直接访问。程序员应该了解并遵守这一点。但我们需要访问 Elon Musk 的空闲时间,为此,我们将使用 JavaScript Getters,即

const elonMusk = {
  _hoursFree: [10, 12, 9],

  get hoursFree() {
    return this._hoursFree; // can now be accessed legitimately
  },
};
Enter fullscreen mode Exit fullscreen mode

现在我们想向 elonMusk 对象添加更多属性

const elonMusk = {
  _hoursFree: [10, 12, 9],
  acceptedPurpose: 'any',
  pendingMeetongs: [], // meetings yet to be approved by Elon Musk
  declinedMeetings: [], // meetings not approved by Elon Musk
  approvedMeetings: [], // meetings approved by Elon Musk
  canceledMeetings: [], // meetings already approved but later canceled maybe something came up
  _feedback: '', // feedback to the booking user (user making the booking)

  get hoursFree() {
    return this._hoursFree;
  },

  get feedBack() {
    return this._feedback); // simply return a feedback
  },
};
Enter fullscreen mode Exit fullscreen mode

acceptedPurpose属性仅表示 Elon Musk 当前想要接受的目的。假设该应用程序的设计包含一个会议目的,可以根据具体情况每周或每天设置;由 Elon Musk 设定。假设acceptedPurpose该应用程序提供的选项是商务、家庭、娱乐或任何

因此,目前我们假设伊隆·马斯克可以参加任何类型的会议,无论是商务会议、娱乐会议还是家庭会议。目前的硬编码稍后会更改。

现在让我们开始使用Setters。假设我们想预约与 Elon Musk 的会面,该怎么做?

  // still in the elonMusk object, just under the feedBack getter
  set newMeeting(time) {
    if (this._hoursFree.indexOf(time) !== -1) {
      this.pendingMeetings.push(time);
      this._feedback =
        'Your meeting was sent successfully. Elon Musk can now review and approve or decline';
    } else {
      this._feedback = 'Time not suitable for Elon Musk';
    }
  },

// outside of the elonMusk object
elonMusk.newMeeting = 10
console.log(elonMusk.feedBack)
Enter fullscreen mode Exit fullscreen mode

这是非常基础的,关于安排会议还有很多内容,我们稍后再讨论。首先,我们来分析一下:

  • 我们通过将用户提供的时间与 Elon Musk 提供的空闲时间进行比较,检查了用户提供的时间是否适合 Elon Musk。
  • 如果为真,我们将时间添加到pendingMeetings数组中,并给出反馈。
  • 如果为假,我们只需向进行此预订的用户返回反馈。

会议不应该只包含时间,伊隆·马斯克当然需要更多关于这次会议的信息,即

创建会议:

// still in the elonMusk object, just under the feedBack getter
  set newMeeting(meeting) {
    const { name, time, purpose } = meeting;

    if (
      this._hoursFree.indexOf(time) !== -1 &&
      this.acceptedPurpose === 'any'
    ) {
      this.pendingMeetings.push(meeting);

      this._feedback = `${name}, your meeting was sent successfully. Elon Musk can now review and approve or decline`;
    } else if (this.acceptedPurpose === purpose.toLowerCase()) {
      this.pendingMeetings.push(meeting);

      this._feedback = `${name}, your meeting was sent successfully. Elon Musk can now review and approve or decline`;
    } else {
      this._feedback = `${name}, this meeting is not suitable for Elon Musk`;
    }
  },
  }

// outside of the elonMusk object
const clientMeeting = {id: 10, name: 'Bill Gates', time: 10, purpose: 'fun'};

elonMusk.newMeeting = clientMeeting;
console.log(elonMusk.feedBack);
Enter fullscreen mode Exit fullscreen mode

我们只是稍微加了点料,应该不难理解。我们把 ID、名称和目的添加到时间中,构成了会议对象。
如果满足以下条件,会议将成功发送:

  • 伊隆马斯克的设置acceptedPurpose为任意,并且如果预订用户的会议时间是hoursFree伊隆马斯克数组中的一项。
  • Elon Musk 的用途acceptedPurpose与预订用户提供的目的类似

现在让我们开始批准、拒绝和取消会议

批准会议:

// still in the elonMusk object, right under the newMeeting
  set approveMeeting(id) {
    const previewingMeeting = this.pendingMeetings.filter((meeting) => {
      return meeting.id === id; // filter out a meeting with its id and preview
    })[0];

    // approve previewing meeting and mark the previewingMeeting.time as a booked hour
    this.approvedMeetings.push(previewingMeeting); // note that approvedMeetings with a 'd' is the array while approveMeeting without a 'd' is the setter
    this._hoursFree.splice(this._hoursFree.indexOf(previewingMeeting.time), 1);

    this._feedback = `${previewingMeeting.name}, your meeting has been approved, time of meeting: ${previewingMeeting.time}`;
  },

// outside the elonMusk object;
elonMusk.newMeeting = clientMeeting //clientMeeting already declared before, scroll up
elonMusk.approveMeeting = clientMeeting.id;
console.log(elonMusk.feedBack);
Enter fullscreen mode Exit fullscreen mode

设置器approveMeeting没有任何条件语句,因为它的目的是直奔主题:批准会议。所以这可以归因于一个“批准会议”按钮,当 Elon 点击​​该按钮时,会议就被批准并发送到数组approvedMeetings

如果会议获得批准,则意味着伊隆·马斯克的某个特定时间已被预订。为此,我们应该尽量移除该预订时间,以避免在同一时间安排两场或两场以上的会议。为此,我们使用了 splice 方法移除了该时间。您可以hoursFree在控制台中记录当前日志以查看结果,即console.log(elonMusk.hoursFree)

拒绝会议:

// still in the elonMusk object, right under the approveMeeting
  set declineMeeting(id) {
    const previewingMeeting = this.pendingMeetings.filter((meeting) => {
      return meeting.id === id; // filter out a meeting with its id and preview
    })[0];


    this.declinedMeetings.push(previewingMeeting); // note that declinedMeetings with a 'd' is the array while declineMeeting without a 'd' is the setter

    this._feedback = `${previewingMeeting.name}, your meeting was declined for reasons best known to Elon Musk`;
  },

// outside the elonMusk object;
elonMusk.newMeeting = clientMeeting //clientMeeting already declared before, scroll up
elonMusk.declineMeeting = clientMeeting.id;
console.log(elonMusk.feedBack);
Enter fullscreen mode Exit fullscreen mode

需要注意的是,delineMeeting设置者是埃隆·马斯克手动拒绝的,自动拒绝从未添加到pendingBookings数组中。换句话说,添加到pendingBookings数组中的预订是需要企业帐户所有者(现为埃隆·马斯克)审核的预订。

hoursFree当数组和字符串中规定的时间或目的不适合 Elon Musk 时,就会自动拒绝acceptedPurpose

取消会议:

// still in the elonMusk object, right under the declineMeeting
    set cancelMeeting(id) {
    // the meeting has to be approved first
    const previewingMeeting = this.approvedMeetings.filter((meeting) => {
      return meeting.id === id;
    })[0];

    this._hoursFree.push(previewingMeeting.time); // make the hour of the canceled meeting a free hour
    this.canceledMeetings.push(previewingMeeting); // add canceled meeting to the array of canceled meetings
    this.approvedMeetings.splice(previewingMeeting, 1); // remove canceled meeting from approved meeting array

    this._feedback = `${previewingMeeting.name}, your meeting with Elon Musk scheduled at ${previewingMeeting.time} has been canceled by Elon Musk. Don't ask me why? am not Elon Musk.`;
  },

// outside the elonMusk object
elonMusk.newMeeting = clientMeeting; //clientMeeting already declared above
elonMusk.approveMeeting = clientMeeting.id; // approve meeting first
elonMusk.cancelMeeting = clientMeeting.id;
console.log(elonMusk.feedBack);
Enter fullscreen mode Exit fullscreen mode

非常简单。你可以添加一个 setter 函数,用于从hoursFree数组中删除空闲时间。如果会议取消,则该预定时间将自动被视为空闲时间;但如果 Elon Musk 不想让该时间继续空闲,他只需点击一个按钮即可(手动)删除该时间的空闲状态。

申请取消免费小时:

// still in the elonMusk object, right under the cancelMeeting
  set requestHourCancelation(hr) {
    if (this._hoursFree.indexOf(hr) !== -1) {
      this._hoursFree.splice(this._hoursFree.indexOf(hr), 1);
    }
  }

// outside of the elonMusk object
elonMusk.requestHourCancelation = 10;
console.log(elonMusk.hoursFree);
Enter fullscreen mode Exit fullscreen mode

伊隆·马斯克预订对象:

const elonMusk = {
  _hoursFree: [10, 12, 9],
  acceptedPurpose: 'family',
  pendingMeetings: [], // meetings yet to be approved by Elon Musk
  declinedMeetings: [], // meetings not approved by Elon Musk
  approvedMeetings: [], // meetings approved by Elon Musk
  canceledMeetings: [], // meetings already approved but later canceled maybe something came up
  _feedback: '', // feedback to the booking user (user making the booking)

  get hoursFree() {
    return this._hoursFree;
  },

  get feedBack() {
    this._feedback; // simply return a feedback.
  },

  set newMeeting(meeting) {
    const { name, time, purpose } = meeting;

    if (
      this._hoursFree.indexOf(time) !== -1 &&
      this.acceptedPurpose === 'any'
    ) {
      this.pendingMeetings.push(meeting);

      this._feedback = `${name}, your meeting was sent successfully. Elon Musk can now review and approve or decline`;
    } else if (this.acceptedPurpose === purpose.toLowerCase()) {
      this.pendingMeetings.push(meeting);

      this._feedback = `${name}, your meeting was sent successfully. Elon Musk can now review and approve or decline`;
    } else {
      this._feedback = `${name}, this meeting is not suitable for Elon Musk`;
    }
  },

  set approveMeeting(id) {
    const previewingMeeting = this.pendingMeetings.filter((meeting) => {
      return meeting.id === id;
    })[0];

    // approve previewing meeting and mark the previewingMeeting.time as a booked hour
    this.approvedMeetings.push(previewingMeeting); // note that approvedMeetings is the array while approveMeeting is the setter
    this._hoursFree.splice(this._hoursFree.indexOf(previewingMeeting.time), 1);

    this._feedback = `${previewingMeeting.name}, your meeting has been approved, time of meeting: ${previewingMeeting.time}`;
  },

  set declineMeeting(id) {
    const previewingMeeting = this.pendingMeetings.filter((meeting) => {
      return meeting.id === id;
    })[0];

    this.declinedMeetings.push(previewingMeeting); // note that declinedMeetings is the array while declineMeeting is the setter

    this._feedback = `${previewingMeeting.name}, your meeting was declined for reasons best known to Elon Musk`;
  },

  set cancelMeeting(id) {
    // the meeting has to be approved first
    const previewingMeeting = this.approvedMeetings.filter((meeting) => {
      return meeting.id === id;
    })[0];

    this._hoursFree.push(previewingMeeting.time); // make the hour of the canceled meeting a free hour
    this.canceledMeetings.push(previewingMeeting); // add canceled meeting to the array of canceled meetings
    this.approvedMeetings.splice(previewingMeeting, 1); // remove canceled meeting from approved meeting array

    this._feedback = `${previewingMeeting.name}, your meeting with Elon Musk scheduled at ${previewingMeeting.time} has been canceled by Elon Musk. Don't ask me why? am not Elon Musk.`;
  },

  set requestHourCancelation(hr) {
    if (this._hoursFree.indexOf(hr) !== -1) {
      this._hoursFree.splice(this._hoursFree.indexOf(hr), 1);
    }
  },
};
Enter fullscreen mode Exit fullscreen mode

拥有多个企业主:

假设我们希望比尔·盖茨和拉里·佩奇都拥有自己的商业账户,我们无需复制elonMusk对象中的代码并粘贴;这完全没必要。由于elonMusk对象中的 getter 和 setter 与其他方法类似(当然应该如此),我们只需为每个用户创建实例即可。

通常,这可以通过 JavaScript 类来实现,但这里我们不会使用类(但以后会用),而是使用我最近从Codecademy.com学到的工厂函数。
具体操作如下。

// make a function and return all properties, getters and setters in the elonMusk object
function businessUser(businessName, _hoursFree, acceptedPurpose) {
  // the three parameters above are properties of this object that are going to vary with different business users
  return {
    businessName,
    _hoursFree,
    acceptedPurpose,
    pendingMeetings: [], // meetings yet to be approved by Elon Musk
    declinedMeetings: [], // meetings not approved by Elon Musk
    approvedMeetings: [], // meetings approved by Elon Musk
    canceledMeetings: [], // meetings already approved but later canceled maybe something came up
    _feedback: '', // feedback to the booking user (user making the booking)

    get hoursFree() {
      return this._hoursFree;
    },

    get feedBack() {
      this._feedback; // simply return a feedback.
    },

    set newMeeting(meeting) {
      const { name, time, purpose } = meeting;

      if (
        this._hoursFree.indexOf(time) !== -1 &&
        this.acceptedPurpose === 'any'
      ) {
        this.pendingMeetings.push(meeting);

        this._feedback = `${name}, your meeting was sent successfully. ${this.businessName} can now review and approve or decline`;
      } else if (this.acceptedPurpose === purpose.toLowerCase()) {
        this.pendingMeetings.push(meeting);

        this._feedback = `${name}, your meeting was sent successfully. ${this.businessName} can now review and approve or decline`;
      } else {
        this._feedback = `${name}, this meeting is not suitable for ${this.businessName}`;
      }
    },

    set approveMeeting(id) {
      const previewingMeeting = this.pendingMeetings.filter((meeting) => {
        return meeting.id === id;
      })[0];

      // approve previewing meeting and mark the previewingMeeting.time as a booked hour
      this.approvedMeetings.push(previewingMeeting); // note that approvedMeetings is the array while approveMeeting is the setter
      this._hoursFree.splice(
        this._hoursFree.indexOf(previewingMeeting.time),
        1
      );

      this._feedback = `${previewingMeeting.name}, your meeting has been approved, time of meeting: ${previewingMeeting.time}`;
    },

    set declineMeeting(id) {
      const previewingMeeting = this.pendingMeetings.filter((meeting) => {
        return meeting.id === id;
      })[0];

      this.declinedMeetings.push(previewingMeeting); // note that declinedMeetings is the array while declineMeeting is the setter

      this._feedback = `${previewingMeeting.name}, your meeting was declined for reasons best known to ${this.businessName}`;
    },

    set cancelMeeting(id) {
      // the meeting has to be approved first
      const previewingMeeting = this.approvedMeetings.filter((meeting) => {
        return meeting.id === id;
      })[0];

      this._hoursFree.push(previewingMeeting.time); // make the hour of the canceled meeting a free hour
      this.canceledMeetings.push(previewingMeeting); // add canceled meeting to the array of canceled meetings
      this.approvedMeetings.splice(previewingMeeting, 1); // remove canceled meeting from approved meeting array

      this._feedback = `${previewingMeeting.name}, your meeting with ${this.businessName} scheduled at ${previewingMeeting.time} has been canceled by ${this.businessName}. Don't ask me why? am not ${this.businessName}.`;
    },

    set requestHourCancelation(hr) {
      if (this._hoursFree.indexOf(hr) !== -1) {
        this._hoursFree.splice(this._hoursFree.indexOf(hr), 1);
      }
    },
  };
}
Enter fullscreen mode Exit fullscreen mode

businessUser 函数中的所有内容,足以创建一百万个正常运行的企业账户。让我们尝试创建三个账户并访问它们的属性。

const larryPage = businessUser('Larry Page', [15, 12, 9], 'any');
console.log(larryPage.hoursFree);
const willSmith = businessUser('Will Smith', [9, 10], 'fun');
console.log(willSmith.hoursFree);
const billGates = businessUser(
  'Bill Gates',
  [11, 10, 9, 8, 7, 6, 5, 4, 3, 2],
  'any'
); // Mr. Gates is always free.
console.log(billGates.hoursFree);
Enter fullscreen mode Exit fullscreen mode

在 GitHub 上获取代码,使用 JavaScript 对象构建项目。别忘了点个星。

结论

值得注意的是,上面所有的 setter 函数都可以用方法替换,并且仍然能正常工作。不过既然我们主要讨论 setter,不妨从头到尾都用它。我打算在下一篇文章中用 JavaScript 类和方法创建一个库,它与这个完全不同,而且更高级、更有趣。一定会很有趣。

希望你和我一样学到了很多。注意,我很快就会有一个很棒的项目(一个开发者项目)给你,你一定会喜欢的。感谢阅读,如果你有任何抱怨或故事(我喜欢故事),别忘了在下方留言,也别忘了和你的同事分享。如果你想支持我,可以请我喝杯咖啡。非常感谢。

鏂囩珷鏉ユ簮锛�https://dev.to/elijahtrillionz/building-a-project-with-javascript-objects-1dn
PREV
清理 React useEffect Hook 中的异步函数(取消订阅)
NEXT
React 和 TypeScript:什么是 React.FC 以及为什么要使用它?