【问题标题】:Creating a prototype for a function in JavaScript?在 JavaScript 中为函数创建原型?
【发布时间】:2016-03-10 09:06:18
【问题描述】:

我可能做错了,但它似乎是使用原型的好地方。

我有一个电子邮件表格。将被验证的该表单的每个输入都有一个对象。该对象的原型是...

var contactInput = function(placeholder, validateFuntion) {
  this.placeholder = placeholder;
  this.value = "";
  var error = true;
  this.setError = function(errorValue) {
    if(typeof(errorValue) === "boolean") {
      error = errorValue;
    } else {
      return false;
      console.log(".setError argument must be boolean.");
    }
  };
  this.getError = function() {
     return error;
  }
  var errorMessage = "";
    this.setErrorMessage = function(errorMessageValue) {
    if(typeof(errorMessageValue) === "string") {
      errorMessage = errorMessageValue;
    } else {
      return false;
      console.log(".setErrorMessage argument must be string.");
    }
  };
  this.getErrorMessage = function() {
     return errorMessage;
  }
  this.validateFunction = validateFunction;
}

我在这里遇到的问题与validateFunction 属性有关。其中有三个输入。它们的每一个验证功能都非常相似。它们仅在验证值的操作以及它们在错误时产生的错误消息方面有所不同。

其中一个看起来像这样......

function(inputValue) {
    if (inputValue === "") {
      this.error = true;
      this.errorMessage = "You did not provide a name.";
      return "error.png";
    } else if (inputValue.length > 50) {
      this.error = true;
      this.errorMessage = "Name must be under 50 characters.";
      return "error.png";
    } else {
      this.error = false;
      return "tick.png";
    }
      }

另一个看起来像这样......

function(inputValue) {
    if (inputValue === "") {
      this.error = true;
      this.errorMessage = "You did not provide an email.";
      return "error.png";
    } else if ( !/(.+)@(.+){2,}\.(.+){2,}/.test(inputValue) ) {
      this.error = true;
      this.errorMessage = "The email you provided was invalid.";
      return "error.png";
    } else {
      this.error = false;
      return "tick.png";
    }
      }

我想为验证函数创建一个原型,然后我可以使用它创建三个验证函数实例。然后我将使用输入的原型(我已经拥有的那个)来创建三个输入实例,使用我创建的验证函数的实例来设置我的输入实例的validateFunction 方法。

我想不出一个人将如何完成它,或者是否应该以这种方式完成。即使不应该这样做,我该如何做到这一点?

【问题讨论】:

  • 我不认为您以典型的方式使用术语prototype。这听起来更像是您只需要一个通用/共享函数,您可以将一些参数传递给它,而不是将大部分代码复制到几个基本相同但略有不同的函数中。在 Javascript 中,这只是一个共享函数,而不是 prototype
  • @jfriend00 这也可以。但是,我想这样做有几个原因。如果这是可能的,那么各个功能将“持续存在”。这将使我能够调用每个函数而无需提供多个参数。在这种情况下,它使我的论点从 5 倒数到 1。不得不把论点拖到周围毁了整个观点。
  • 您可以创建一个包含 98% 功能的通用函数体,然后创建三个 shell 函数,它们只将正确的参数传递给您的通用函数。然后,您将获得两全其美。在一个共享函数中调用每个验证器和公共代码的简单函数。仅供参考,这是基本的编程结构(将公共代码分解为共享函数)。如果这是您不熟悉的内容,那么您可能会从某种编程课程中受益,因为它确实会帮助您了解更多此类内容。
  • @jfriend00 我是在家教的,现在已经在这个行业工作了几年。我才刚刚开始走出自己的外壳并成为一名真正的开发人员。这似乎可以使用类来完成,或者类似于类的东西。如果您发布答案,我将很乐意接受。感谢您的帮助。

标签: javascript function oop object prototype


【解决方案1】:

首先,您的术语有些混乱,我不会在这里称任何东西为“函数原型”。

Prototype 是一个对象,它被用作创建其他对象的原型。 在 javascript 中,恰好您使用 function 作为对象的构造函数。

关于您的实施的一些通知:

  1. 返回后的代码永远不会被执行。而console.log 是通知错误的不好方法(最好抛出错误):

    } else {
      return false;
      console.log(".setError argument must be boolean.");
    }
    
  2. 就 OOP 而言,拥有 getter 和 setter 并不好,这样您就可以将对象状态暴露给世界。更好的方法是将对象视为一台微型计算机,一个您可以要求它做一些工作的黑匣子。 所有初始化数据都传入构造函数,所以不需要setter,对象内部的数据相关的工作都是由对象完成的,所以你也不应该需要getter。

  3. 有两种方法可以实现略有不同的行为 - 继承,其中子类实现差异或组合,其中差异被移动到另一个对象。 使用什么视情况而定。

使用继承实现输入的一种可能方法是:

function ContactInput(selector, placeholder) {
  // properties are prefixed with underscore to notify the programmer that they are
  // 'private' (should not be accessed outside of this class or subclasses)
  this._element = document.querySelector(selector);
  this._placeholder = placeholder;
}

ContactInput.prototype.validate() {
    // this should be implemented in child classes
    throw 'Not implemented';
}

// Private method (prefixed with underscore), also to be used only by this object
ContactInput.prototype._renderSuccess(message, image) {
    message = message || "";
    image = image || "tick.png";
    // show the success div near the element (actually it is better to use css, 
    // so it will be not necessary to pass the `tick.png` and `error.png`
    // around, you could just change the element's css class here to show the tick)
}

// Private
ContactInput.prototype._renderError(message, image) {
    message = message || "Validation error";
    image = image || "error.png";
    // show the error div near the element
}

// Private
ContactInput.prototype._getValue() {
    return this._element.value;
}

function NameInput(placeholder) {
    ContactInput.call(this, placeholder);
}
NameInput.prototype = Object.create(ContactInput.prototype);

NameInput.prototype.validate() {
    var value = this._getValue();
    if (!value) {
        return this.renderError("You did not provide a name.", 'error.png');
    }
    if (value.length > 50) {
        return this.renderError("Name must be under 50 characters.", 'error.png');
    }
    return this.renderSuccess();
}

function EmailInput(placeholder) {
    ContactInput.call(this, placeholder);
}
EmailInput.prototype = Object.create(ContactInput.prototype);

EmailInput.prototype.validate() {
    var value = this._getValue();
    if (!value) {
        return this.renderError("You did not provide an email.", 'error.png');
    }
    if ( !/(.+)@(.+){2,}\.(.+){2,}/.test(value) ) {
        return this.renderError("The email you provided was invalid.", 'error.png');
    }
    return this.renderSuccess();
}

我不确定你如何使用placeholder,所以我把它留在了基类中。 根据使用情况,它可以是仅NameInput 的属性(或EmailInput)。

现在你可以这样做了:

var inputs = [
    new NameInput('x'),
    new EmailInput('y')
];
inputs.forEach(function(input) {
    input.validate();
});

请注意,您不必在其他地方执行input->setError('xxx')input->getError('xxx') 之类的操作。 您只需创建对象,给它一些数据,然后让它根据这些数据工作。

【讨论】:

    猜你喜欢
    • 2012-10-03
    • 1970-01-01
    • 2016-12-02
    • 2015-03-24
    • 2013-05-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多