You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为函数添加属性并设置原型:Vector类代码处理技术问询

完善Vector类:静态属性/方法与原型方法的最佳实践

Hey there! Looks like you're building a 2D Vector class and have already laid down a constructor plus some static utility methods, though the prototype set method is incomplete. Let me walk you through how to properly add static properties/methods to the function, fix the prototype chain setup, and make this class robust and easy to work with.

一、First: Understand Static vs. Prototype Methods

It's key to keep these two straight for clean, maintainable code:

  • Static methods (like your Vector.add): Attached directly to the Vector constructor. Use these for generic operations that don't depend on a specific instance's state (e.g., adding two vectors, generating a random vector).
  • Prototype methods: Mounted to Vector.prototype, so every Vector instance inherits them. Use these for operations that modify or read the current instance's state (e.g., updating x/y values, cloning the vector).

二、Polish Your Existing Static Methods

Your static methods are off to a good start—we just need to make sure they play nicely with the prototype methods we'll add later. Here's the cleaned-up constructor and static method code:

function Vector(x, y) {
  this.x = x || 0;
  this.y = y || 0;
}

// Static: Add two vectors, return a new Vector
Vector.add = function(a, b) {
  return new Vector(a.x + b.x, a.y + b.y);
};

// Static: Subtract vector b from a, return a new Vector
Vector.sub = function(a, b) {
  return new Vector(a.x - b.x, a.y - b.y);
};

// Static: Scale a vector, return a new scaled instance
Vector.scale = function(v, s) {
  return v.clone().scale(s);
};

// Static: Generate a random vector with x/y in [-1, 1]
Vector.random = function() {
  return new Vector(Math.random() * 2 - 1, Math.random() * 2 - 1);
};

三、Set Up the Prototype Correctly (And Finish That set Method!)

When you assign a new object to Vector.prototype, you overwrite the default constructor reference—so we need to manually point it back to Vector to avoid bugs with instance type checks. Let's also finish the set method and add essential prototype methods:

Vector.prototype = {
  // Critical: Restore the constructor reference
  constructor: Vector,

  // Finish the set method: Support both object and individual x/y arguments
  set: function(x, y) {
    if (typeof x === 'object') {
      // Handle object input (e.g., {x: 5, y: 3})
      this.x = x.x || 0;
      this.y = x.y || 0;
    } else {
      // Handle individual x/y values
      this.x = x || 0;
      this.y = y || 0;
    }
    return this; // Enable method chaining
  },

  // Clone the current vector, return a new instance
  clone: function() {
    return new Vector(this.x, this.y);
  },

  // Scale the current vector (modifies the instance itself)
  scale: function(s) {
    this.x *= s;
    this.y *= s;
    return this; // Enable method chaining
  },

  // Calculate the vector's magnitude (length)
  magnitude: function() {
    return Math.sqrt(this.x * this.x + this.y * this.y);
  },

  // Normalize the vector to a length of 1
  normalize: function() {
    const mag = this.magnitude();
    if (mag !== 0) {
      this.scale(1 / mag);
    }
    return this; // Enable method chaining
  },

  // For easy debugging
  toString: function() {
    return `Vector(${this.x}, ${this.y})`;
  }
};

四、How to Use Your Vector Class

Now your class is ready to go! Here are some quick examples to show it in action:

// Create instances
const v1 = new Vector(2, 3);
const v2 = new Vector(4, 1);

// Use static methods
const sum = Vector.add(v1, v2);
console.log(sum.toString()); // Output: "Vector(6, 4)"

// Use prototype methods with chaining
const v3 = new Vector().set({x: 5, y: 5}).scale(2);
console.log(v3.magnitude()); // Output: ~14.142

// Generate a random vector
const randomVec = Vector.random();
console.log(randomVec); // Output: e.g., Vector(-0.32, 0.87)

五、Optional: ES6+ Class Refactor

If your environment supports ES6+, rewriting this with class syntax makes the code more readable and automatically handles the constructor reference:

class Vector {
  constructor(x = 0, y = 0) {
    this.x = x;
    this.y = y;
  }

  static add(a, b) {
    return new Vector(a.x + b.x, a.y + b.y);
  }

  static sub(a, b) {
    return new Vector(a.x - b.x, a.y - b.y);
  }

  static scale(v, s) {
    return v.clone().scale(s);
  }

  static random() {
    return new Vector(Math.random() * 2 - 1, Math.random() * 2 - 1);
  }

  set(x, y) {
    if (typeof x === 'object') {
      this.x = x.x ?? 0; // Use nullish coalescing for stricter checks
      this.y = x.y ?? 0;
    } else {
      this.x = x ?? 0;
      this.y = y ?? 0;
    }
    return this;
  }

  clone() {
    return new Vector(this.x, this.y);
  }

  scale(s) {
    this.x *= s;
    this.y *= s;
    return this;
  }

  magnitude() {
    return Math.hypot(this.x, this.y); // Cleaner alternative to sqrt
  }

  normalize() {
    const mag = this.magnitude();
    mag && this.scale(1 / mag);
    return this;
  }

  toString() {
    return `Vector(${this.x}, ${this.y})`;
  }
}

Note: Using ?? (nullish coalescing) instead of || prevents unintended overwrites of valid 0 values.

内容的提问来源于stack exchange,提问作者Pavlin Petkov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 09:48:34