JavaScript 中的类与静态方法

IT技术 javascript oop
2021-02-04 09:07:15

我知道这会奏效:

function Foo() {};
Foo.prototype.talk = function () {
    alert('hello~\n');
};

var a = new Foo;
a.talk(); // 'hello~\n'

但如果我想打电话

Foo.talk() // this will not work
Foo.prototype.talk() // this works correctly

我找到了一些Foo.talk工作的方法

  1. Foo.__proto__ = Foo.prototype
  2. Foo.talk = Foo.prototype.talk

还有其他方法可以做到这一点吗?我不知道这样做是否正确。您在 JavaScript 代码中使用类方法还是静态方法?

6个回答

首先,请记住 JavaScript 主要是一种原型语言,而不是基于类的语言1Foo不是一个类,它是一个函数,它是一个对象。您可以使用关键字该函数实例化一个对象new这将允许您创建类似于标准 OOP 语言中的类的东西。

我建议__proto__大多数时候忽略它,因为它的跨浏览器支持很差,而是专注于了解prototype工作原理。

如果你有一个从函数2创建的对象的实例,并且你以任何方式访问它的一个成员(方法、属性、属性、常量等),访问将沿着原型层次向下流动,直到它(a)找到成员,或 (b) 没有找到另一个原型。

层次结构从被调用的对象开始,然后搜索其原型对象。如果原型对象有原型,则重复,如果不存在原型,undefined则返回。

例如:

foo = {bar: 'baz'};
console.log(foo.bar); // logs "baz"

foo = {};
console.log(foo.bar); // logs undefined

function Foo(){}
Foo.prototype = {bar: 'baz'};
f = new Foo();
console.log(f.bar);
// logs "baz" because the object f doesn't have an attribute "bar"
// so it checks the prototype
f.bar = 'buzz';
console.log( f.bar ); // logs "buzz" because f has an attribute "bar" set

在我看来,您至少已经对这些“基本”部分有所了解,但为了确定起见,我需要将它们明确化。

在 JavaScript 中,一切都是对象3

一切都是对象。

function Foo(){}不只是定义一个新函数,它还定义了一个可以使用Foo.

这就是为什么您可以使用 访问Foo的原型Foo.prototype

你也可以做的是设置更多的功能Foo

Foo.talk = function () {
  alert('hello world!');
};

可以使用以下方法访问此新功能:

Foo.talk();

我希望现在您已经注意到函数对象上的函数和静态方法之间的相似性。

可以将其f = new Foo();视为创建类实例、Foo.prototype.bar = function(){...}定义共享方法以及为类Foo.baz = function(){...}定义公共静态方法。


ECMAScript 2015 为这些类型的声明引入了各种语法糖,使它们更易于实现,同时也更易于阅读。因此,前面的示例可以写为:

class Foo {
  bar() {...}

  static baz() {...}
}

这允许bar被称为:

const f = new Foo()
f.bar()

并被baz称为:

Foo.baz()

1:class是 ECMAScript 5 规范中的“未来保留字”,但 ES6 引入了使用class关键字定义类的能力

2:本质上是一个由构造函数创建的类实例,但是有很多细微差别我不想误导你

3:原始值——包括undefinednull、布尔值、数字和字符串——在技术上不是对象,因为它们是低级语言实现。布尔值、数字和字符串仍然像对象一样与原型链交互,因此就本答案而言,即使它们不完全是“对象”,也更容易将它们视为“对象”。

@lostyzd - 好吧,他们可以通过Foo.talk(). 如果需要,您可以在构造函数中分配它:this.talk = Foo.talk- 或者,正如您所指出的,通过分配Foo.prototype.talk = Foo.talk. 但我不确定这是一个好主意 - 原则上,实例方法应该特定于实例。
2021-03-16 09:07:15
你们都缺少的基本点是静态方法被继承。Foo.talk = function ()...将不可用于有自己的类名的子类。这可以通过“扩展”子类来解决,但我仍在寻找一种更优雅的方式。
2021-03-16 09:07:15
PS null 是对象 typeof null == 'object'
2021-03-25 09:07:15
@nus,只有某些语言允许继承静态方法。如果需要继承,您不应该一开始就使用静态方法。
2021-03-27 09:07:15
@Doug Avery,Foo.talk()只是调用一个命名空间函数。您可以在类似于 Java/C# 等 OOP 语言中调用静态方法的情况下使用它。用例的一个很好的例子是像Array.isArray().
2021-04-04 09:07:15

你可以实现它如下:

function Foo() {};

Foo.talk = function() { alert('I am talking.'); };

您现在可以调用“talk”功能,如下所示:

Foo.talk();

您可以这样做,因为在 JavaScript 中,函数也是对象。

从实例调用静态方法:

function Clazz() {};
Clazz.staticMethod = function() {
    alert('STATIC!!!');
};

Clazz.prototype.func = function() {
    this.constructor.staticMethod();
}

var obj = new Clazz();
obj.func(); // <- Alert's "STATIC!!!"

简单的 Javascript 类项目:https : //github.com/redardo7/sjsClass

这不是静态调用。var obj = new Clazz(); 创建一个新的 Clazz实例然而, Clazz.staticMethod() 在没有所有其他东西的情况下实现了结果。
2021-03-16 09:07:15
@mpemburn:爱德华多的回答也是正确的。他向您展示的不仅是您可以通过“外部”调用静态方法,Clazz.staticMethod而且还向您展示了如何从实例化对象内部链接到这些静态方法。这在 Node.js 等环境中特别有用,在这种环境中,使用 require 可能无法直接访问原始构造函数。我唯一要补充的是this.constructor.staticMethod.apply(this, arguments);
2021-03-17 09:07:15
非常棒,甚至可以在咖啡脚本构造函数中工作:(constructor: (a) -> @constructor.add @几乎,无论如何)
2021-04-07 09:07:15

这是一个很好的示例,用于演示 Javascript 如何与静态/实例变量和方法一起工作。

function Animal(name) {
    Animal.count = Animal.count+1||1;// static variables, use function name "Animal"
    this.name = name; //instance variable, using "this"
}

Animal.showCount = function () {//static method
    alert(Animal.count)
}

Animal.prototype.showName=function(){//instance method
    alert(this.name);
}

var mouse = new Animal("Mickey");
var elephant = new Animal("Haddoop");

Animal.showCount();  // static method, count=2
mouse.showName();//instance method, alert "Mickey"
mouse.showCount();//Error!! mouse.showCount is not a function, which is different from  Java
感谢您的解决方案,这就是我正在寻找的解决方案,在哪种情况下可以访问this关键字
2021-03-26 09:07:15
优点:不能通过this.
2021-03-29 09:07:15

此外,现在可以使用classstatic

'use strict'

class Foo {
 static talk() {
     console.log('talk')
 };

 speak() {
     console.log('speak')
 };

};

会给

var a = new Foo();
Foo.talk();  // 'talk'
a.talk();    // err 'is not a function'
a.speak();   // 'speak'
Foo.speak(); // err 'is not a function'
这是最好的答案,因为例子值一千字。但是,它没有解释为什么a.talk()不起作用。接受的答案说原型链应该找到它,对吗?但事实并非如此
2021-04-10 09:07:15