JavaScript中的类与静态方法

los*_*yzd 254 javascript oop

我知道这会奏效:

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

var a = new Foo;
a.talk(); // 'hello~\n'
Run Code Online (Sandbox Code Playgroud)

但如果我想打电话

Foo.talk() // this will not work
Foo.prototype.talk() // this works correctly
Run Code Online (Sandbox Code Playgroud)

我找到一些方法来做Foo.talk工作,

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

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

zzz*_*Bov 388

首先,请记住,JavaScript主要是一种原型语言,而不是基于类的语言1.Foo不是一个类,它是一个函数,它是一个对象.您可以使用关键字该函数实例化对象,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
Run Code Online (Sandbox Code Playgroud)

在我看来,你已经至少在某种程度上理解了这些"基本"部分,但我需要明确它们才能确定.

在JavaScript中,一切都是对象3.

一切都是对象.

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

这就是你可以访问Foo原型的原因Foo.prototype.

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

Foo.talk = function () {
  alert('hello world!');
};
Run Code Online (Sandbox Code Playgroud)

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

Foo.talk();
Run Code Online (Sandbox Code Playgroud)

我希望现在你注意到函数对象和静态方法的函数之间的相似性.

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


ECMAScript 2015为这些类型的声明引入了各种语法糖,使其更易于实现,同时更易于阅读.之前的例子可以写成:

class Foo {
  bar() {...}

  static baz() {...}
}
Run Code Online (Sandbox Code Playgroud)

允许bar被称为:

const f = new Foo()
f.bar()
Run Code Online (Sandbox Code Playgroud)

并被baz称为:

Foo.baz()
Run Code Online (Sandbox Code Playgroud)

1:class是ECMAScript 5规范中的"Future Reserved Word",但ES6引入了使用class关键字定义类的能力.

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

3:原始值 - 包括undefined,null布尔值,数字和字符串 - 在技术上不是对象,因为它们是低级语言实现.布尔值,数字和字符串仍然与原型链相互作用,就像它们是对象一样,因此对于这个答案而言,即使它们不完整,也更容易将它们视为"对象".

  • PS null是对象typeof null =='object' (7认同)
  • @Doug Avery,`Foo.talk()`只是调用命名空间函数.您可以在类似于在Java/C#等OOP语言中调用静态方法的情况下使用它.用例的一个很好的例子是像[`Array.isArray()`](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/isArray)这样的函数. (2认同)

Bip*_*pul 67

你可以实现如下:

function Foo() {};

Foo.talk = function() { alert('I am talking.'); };
Run Code Online (Sandbox Code Playgroud)

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

Foo.talk();
Run Code Online (Sandbox Code Playgroud)

你可以这样做,因为在JavaScript中,函数也是对象."zzzzBov"也回答了它,但这是一个冗长的阅读.


Edu*_*omo 36

从实例调用静态方法:

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

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

var obj = new Clazz();
obj.func(); // <- Alert's "STATIC!!!"
Run Code Online (Sandbox Code Playgroud)

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

  • 这不是静态调用.var obj = new Clazz(); 创建一个新的_instance_ of Clazz.但是,Clazz.staticMethod()在没有其他所有东西的情况下实现了结果. (13认同)
  • @mpemburn:Eduardo的答案也是正确的.他向您展示的不仅是您可以通过`Clazz.staticMethod`从"外部"调用静态方法,而且他正在向您展示如何从实例化对象中链接到这些静态方法.这在Node.js等环境中特别有用,使用require,您可能无法直接访问原始构造函数.我要添加的唯一内容是`this.constructor.staticMethod.apply(this,arguments);` (4认同)

Jas*_*key 32

这是一个很好的例子来演示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
Run Code Online (Sandbox Code Playgroud)


Dim*_*min 27

另外,现在可以用classstatic

'use strict'

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

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

};
Run Code Online (Sandbox Code Playgroud)

会给

var a = new Foo();
Foo.talk();  // 'talk'
a.talk();    // err 'is not a function'
a.speak();   // 'speak'
Foo.speak(); // err 'is not a function'
Run Code Online (Sandbox Code Playgroud)


A-S*_*ani 11

我使用命名空间:

var Foo = {
     element: document.getElementById("id-here"),

     Talk: function(message) {
            alert("talking..." + message);
     },

     ChangeElement: function() {
            this.element.style.color = "red";
     }
};
Run Code Online (Sandbox Code Playgroud)

并使用它:

Foo.Talk("Testing");
Run Code Online (Sandbox Code Playgroud)

要么

Foo.ChangeElement();
Run Code Online (Sandbox Code Playgroud)


Abd*_*UMI 6

ES6支持现在classstatic关键字如魅力:

class Foo {
    constructor() {}

    talk() {
        console.log("i am not static");
    }

    static saying() {
        console.log(this.speech);
    }

    static get speech() {
        return "i am static method";
    }

}
Run Code Online (Sandbox Code Playgroud)