javascript - 在 JavaScript 中实现 Circle 构造函数,无需 ES6 类

标签 javascript ecmascript-6

Eric Faust 在以下有关 ES6 类的文章中输入了 Circle 构造函数:https://hacks.mozilla.org/2015/07/es6-in-depth-classes/

我想知道:

  1. 他为什么使用 defineProperty ?我们不能直接在构造函数中实现该行为吗?例如:Circle.draw = function draw() {..}
  2. 为什么使用 get/set而不仅仅是在正常属性中具有状态: Circle.circleCount
  3. 哪些属性应该直接在新实例对象上实现,通过this在构造函数中,vs on Constructor.prototype (考虑到两者如何使属性可用于新实例)?

埃里克的代码:

function Circle(radius) {
  this.radius = radius;
  Circle.circlesMade++;
}

Circle.draw = function draw(circle, canvas) { /* Canvas drawing code */ }

Object.defineProperty(Circle, "circlesMade", {
  get: function() {
    return !this._count ? 0 : this._count;
  },

  set: function(val) {
    this._count = val;
  }
});

Circle.prototype = {
  area: function area() {
    return Math.pow(this.radius, 2) * Math.PI;
  }
};

Object.defineProperty(Circle.prototype, "radius", {
  get: function() {
    return this._radius;
  },

  set: function(radius) {
    if (!Number.isInteger(radius))
      throw new Error("Circle radius must be an integer.");
    this._radius = radius;
  }
});

let c1 = new Circle(10);
console.log(c1.area());
console.log(Circle.circlesMade);

我的版本:

function Circle(_radius) {
  this.radius = _radius;

  Circle.draw = function draw(circle, canvas) {
    /* Canvas drawing code */
  };

  !Circle.circleCount ?
    (Circle.circleCount = 1) //First construction
    :
    (Circle.circleCount = Circle.circleCount + 1);

  this.area = function area() {
    return Math.pow(this.radius, 2) * Math.PI;
  };
}

let c1 = new Circle(10);
console.log(Circle.circleCount);
console.log(c1.area());

let c2 = new Circle(20);
console.log(Circle.circleCount);
console.log(c2.area());

最佳答案

我更喜欢将构造函数的原型(prototype)对象用于与实例共享的函数,而不是在每个实例上定义一个新函数。这可以节省内存,因为您只有该函数的一个实例,而不是为您创建的每个实例都有一个新副本。

您还可以在原型(prototype)上定义circleCount,因为所有实例都需要相同的数字。您只需要稍微小心地更改它,以确保不会在每个实例上创建隐藏属性。然后每个实例可以通过原型(prototype)链直接提供计数。

这样做会使函数变得复杂,但会简化其余代码:

function Circle(_radius) {
  this.radius = _radius;
  // creating an instance increments the count for everyone
  Circle.prototype.circleCount++ // not this.circleCount++ which will create a new property on instance
}
Circle.prototype.draw = function draw(circle, canvas) {
  /* Canvas drawing code */
};
Circle.prototype.area = function() {
  return Math.pow(this.radius, 2) * Math.PI;
}
Circle.prototype.circleCount = 0


let c1 = new Circle(10);
console.log(c1.circleCount);
console.log(c1.area());

let c2 = new Circle(20);
console.log(c2.circleCount);
console.log(c2.area());

另外,关于Object.defineProperty的问题。看起来他正在使用它,这样他就可以设置 getter 和 setter 函数,而不仅仅是返回属性。您可以使用 area 来做到这一点,例如:

Object.defineProperty(Circle.prototype, "area", {
    get: function() {
       return Math.pow(this.radius, 2) * Math.PI;
    }
});

这将允许您访问区域,就好像 ti 是每个实例上的属性一样:

c2.area // instead of a function c2.area()

您可以直接将面积设置为属性,但如果更改半径,则还需要更改面积。我想哪个最好取决于半径是否会改变。

关于javascript - 在 JavaScript 中实现 Circle 构造函数,无需 ES6 类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51732175/

相关文章:

javascript - 使用 javascript 切换主 div 内其他 div 的显示

Javascript 奇怪的生成器 yield 子函数行为

javascript - 有没有办法使用 SSG 使用 Nextjs 构建特定页面?

javascript - 为什么我们能够在 React 组件的构造函数中绑定(bind)函数?

javascript - TypeScript:找不到变量名称(在条件语句中设置)

javascript - 切换 Div Javascript

javascript - 使用 Angular 检查出生日期

Javascript for .. of 循环 (ECMAScript 6)

javascript - For-Loop 调用时未运行

javascript - Magento 中的调用函数