不使用原型定义方法

时间:2015-12-25 02:57:35

标签: javascript

是否可以使用如下所示的语句来定义不使用prototype的方法?

Person.sayHello = function () {...}

在这个例子中

var Person = function (firstName) {
  this.firstName = firstName;
};

Person.prototype.sayHello = function() {
  console.log("Hello, I'm " + this.firstName);
};

var person1 = new Person("Alice");
var person2 = new Person("Bob");

4 个答案:

答案 0 :(得分:4)

简而言之,没有。

Person.sayHello = function () {...};

这一行将向Person类本身添加一个名为“sayHello”的函数,而不是Person类的实例。所以,它只能由

调用
Person.sayHello();

而不是

var matt = new Person('Matt');
matt.sayHello();
// sayHello is not defined on matt

如果您熟悉Java或C#,以这种方式向Person添加方法就像创建静态方法一样。

但是,我们可以在不向原型添加方法的情况下向实例添加方法。

方法1:在Person的构造函数中创建“sayHello”函数

var Person = function (firstName) {
  this.firstName = firstName;

  this.sayHello = sayHello() {...};
};

此方法的缺点是为Person的每个实例创建了一个新函数。也就是说,

var frank = new Person('Frank');
var matt = new Person('Matt');
// frank.sayHello != matt.sayHello;

因此,这种方法对记忆力很难。但是,它确实允许通过闭包进行封装(例如私有状态)。在下面的示例中,如果不调用“sayHello”函数,则无法修改Person类之外的“count”变量。

var Person = function (firstName) {
  this.firstName = firstName;

  this.sayHello = sayHello() {
    count++;
    console.log("Hello has been said " + count + "times".
  };

  var count = 0;
};

方法2:在Person的构造函数外创建“sayHello”函数,并在Person的构造函数中指定它

var Person = function (firstName) {
  this.firstName = firstName;

  this.sayHello = sayHello;
};

function sayHello() {...}

此方法具有内存使用率较低的优点; sayHello函数只有一个实例,它在Person的实例之间共享。也就是说,

var frank = new Person('Frank');
var matt = new Person('Matt');
// frank.sayHello == matt.sayHello;

这使它类似于原型方法。但是,为每个实例分配函数仍然比原型方法消耗更多的内存,而原型方法只将函数分配给原型对象。

但是,与原型方法一样,此方法不允许私有状态。必须通过this关键字公开的公共状态访问所有州。

更新:澄清方法1和方法2之间内存使用量的差异。

方法1是这样的:

var function1 = function() { console.log('Hello'); };
var function2 = function() { console.log('Hello'); };

函数具有相同的行为,但不相等。 JavaScript不知道它们在功能上是相似的,因此它在内存中创建了两个函数来表示它们。

方法2是这样的:

var sayHello = function() { console.log('Hello'); };
var function1 = sayHello;
var function2 = sayHello;

现在,function1和function2实际上是同一个函数,因为它们都只是持有对sayHello的引用。

更新:模块模式的示例用法,以避免在方法2中向全局范围添加“sayHello”。

此模块在由匿名闭包(自执行函数)定义的模块中定义Person类,并将其导出到全局范围。因为“sayHello”是在模块的闭包中定义的而不是导出的,所以它不会被添加到全局范围。

var Person = (function () {
    function Person(firstName) {
      this.firstName = firstName;

      this.sayHello = sayHello;
    };

    function sayHello() {...}

    return Person;
}());

答案 1 :(得分:0)

是的,你可以。如果你来自传统的OO背景,那么可能有助于将其视为有效地表现为类上的公共静态属性。

正如jsdeveloper在上述评论中所说。函数只是可以执行的对象。您可以像添加任何其他对象一样向它们添加属性。实际上,这种技术用于记忆或干扰等模式。

在您的情况下sayHello可以在任何可以访问Person功能的地方访问。它与继承/原型并不真正相关,因为它与通过遍历原型链解析属性无关,但它是另一种使数据可访问的方法。

我确信它会因开发人员的不同而有所不同,但我经常把不引用this的纯函数作为静态方法,因为它们更容易测试,并且明确其他意图开发者

答案 2 :(得分:-1)

这很奇怪,但是如果你真的需要这样做,你可以将函数分配给它自己的原型一次,然后将所有函数添加到main函数中。

var Person = function (firstName) {
  this.firstName = firstName;
};
Person.prototype = Person;

Person.sayHello = function() {
  console.log("Hello, I'm " + this.firstName);
};

答案 3 :(得分:-3)

是的,你可以,但是sayhello函数将无法访问任何对象属性(即this.myvar),你只能像静态方法一样调用它:

Person.sayhello()    

(而不是mypersonobject.sayhello)。

扩展原型时,sayhello函数可用于以通常方式使用“new”关键字创建的所有Person对象。

https://jsfiddle.net/jsheridan390/kL7arrqs/