web-dev-qa-db-ja.com

JavaScriptのクラスと静的メソッド

私はこれがうまくいくことを知っています:

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コードでクラスメソッドと静的メソッドのどちらを使用しますか?

249
lostyzd

まず、JavaScriptは主に クラスベース言語 ではなく プロトタイプ言語 です。1Fooはクラスではなく、関数で、オブジェクトです。標準のOOP言語のクラスに似たものを作成できるようにするnewキーワードを使用して、その関数 from をインスタンス化できます。

私はほとんどの場合__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

everythingはオブジェクトです。

function Foo(){}は新しい関数を定義するだけではなく、Fooを使ってアクセスできる新しい関数オブジェクトを定義します。

Foo.prototypeを使ってFooのプロトタイプにアクセスできるのはこのためです。

Foo more functions を設定することもできます。

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仕様の「Future Reserved Word」 ですが、ES6ではclassキーワードを使用してクラスを定義する機能が導入されました。

2:基本的にコンストラクタによって作成されたクラスインスタンスですが、誤解させたくない微妙な違いがたくさんあります

3: プリミティブな値 - undefinednull、booleans、number、およびstringsを含みます。これらは低レベルの言語実装であるため、技術的には目的とされていません。ブール値、数値、および文字列は、あたかもオブジェクトであるかのようにプロトタイプチェーンと対話します。したがって、この回答の目的のためには、たとえそれらが「オブジェクト」であると考えてもしなくても簡単です。

380
zzzzBov

あなたは以下のようにそれを達成することができます:

function Foo() {};

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

以下のようにして、 "talk"機能を呼び出すことができます。

Foo.talk();

JavaScriptでは、関数もオブジェクトであるため、これを実行できます。 "zzzzBov"もそれに答えました、しかしそれは長い読みです。

67
Bipul

インスタンスから静的メソッドを呼び出します。

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/reduardo7/sjsClass

36
Eduardo Cuomo

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
31
Jaskey

さらに、今では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'
26
Dima Fomin

私は名前空間を使います:

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

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

     ChangeElement: function() {
            this.element.style.color = "red";
     }
};

そしてそれを使う:

Foo.Talk("Testing");

または

Foo.ChangeElement();
11
A-Sharabiani

ES6は魅力のようにclassおよびstaticキーワードをサポートするようになりました。

class Foo {
    constructor() {}

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

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

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

}
6
Abdennour TOUMI

ES5で静的メソッドを作成する必要がある場合は、そのための素晴らしいチュートリアルが見つかりました。

//Constructor
var Person = function (name, age){
//private properties
var priv = {};

//Public properties
this.name = name;
this.age = age;

//Public methods
this.sayHi = function(){
    alert('hello');
}
}


// A static method; this method only 
// exists on the class and doesn't exist  
// on child objects
Person.sayName = function() {
   alert("I am a Person object ;)");  
};

@ https://abdulapopoola.com/2013/03/30/static-and-instance-methods-in-javascript/ を参照してください。

3
Combine

ちょっとしたメモ。 ES6クラスを使用して、スタティックメソッドを作成した場合.. Javacsriptエンジンは、ディスクリプタ属性を古い学校の "static"メソッドとは少し異なる設定にしました

function Car() {

}

Car.brand = function() {
  console.log('Honda');
}

console.log(
  Object.getOwnPropertyDescriptors(Car)
);

brand()の内部属性(descriptorプロパティ)を

..
brand: [object Object] {
    configurable: true,
    enumerable: true,
    value: ..
    writable: true

}
..

に比べ

class Car2 {
   static brand() {
     console.log('Honda');
   }
}

console.log(
  Object.getOwnPropertyDescriptors(Car2)
);

brand()の内部属性を

..
brand: [object Object] {
    configurable: true,
    enumerable: false,
    value:..
    writable: true
  }

..

eS6の静的メソッドでは、enumerablefalseに設定されていることを確認してください。

つまり、for-inループを使ってオブジェクトをチェックすることはできません。

for (let prop in Car) {
  console.log(prop); // brand
}

for (let prop in Car2) {
  console.log(prop); // nothing here
}

eS6の静的メソッドは、他のクラスのプライベートプロパティ(名前、長さ、コンストラクタ)と同様に扱われます。ただし、静的メソッドはまだ書き込み可能であるため、ディスクリプタ書き込み可能true{ writable: true }に設定されます。それはまた私達がそれを無効にできることを意味します

Car2.brand = function() {
   console.log('Toyota');
};

console.log(
  Car2.brand() // is now changed to toyota
);
2
ngakak

Foo.talkを呼び出そうとすると、JSは__proto__を介して関数talkを検索しようとしますが、もちろん、見つかりません。

Foo.__proto__Function.prototypeです。

1
Issac Young

そのような状況に直面したとき、私はこのようなことをしました:

Logger = {
    info: function (message, tag) {
        var fullMessage = '';        
        fullMessage = this._getFormatedMessage(message, tag);
        if (loggerEnabled) {
            console.log(fullMessage);
        }
    },
    warning: function (message, tag) {
        var fullMessage = '';
        fullMessage = this._getFormatedMessage(message, tag);
        if (loggerEnabled) {
            console.warn(fullMessage);`enter code here`
        }
    },
    _getFormatedMessage: function () {}
};

だから今私はLogger.info("my Msg", "Tag");としてinfoメソッドを呼び出すことができます

0
Vishnu

静的メソッド呼び出しはクラスで直接行われ、クラスのインスタンスでは呼び出せません。多くの場合、静的メソッドは効用関数を作成するために使用されます

かなり明確な説明

mozilla.orgから直接取得

Fooはあなたのクラスに束縛される必要がありますそれであなたが新しいインスタンスを作成するときあなたはmyNewInstance.foo()を呼び出すことができますあなたがあなたのクラスをインポートするならあなたは静的メソッドを呼び出すことができます

0
Dave Keane

Javascriptには実際のクラスはなく、むしろプロトタイプチェーンを介して他のオブジェクトからオブジェクトを「継承」するプロトタイプ継承システムを使用しています。これはコード自体で最もよく説明されます。

function Foo() {};
// creates a new function object

Foo.prototype.talk = function () {
    console.log('hello~\n');
};
// put a new function (object) on the prototype (object) of the Foo function object

var a = new Foo;
// When foo is created using the new keyword it automatically has a reference 
// to the prototype property of the Foo function

// We can show this with the following code
console.log(Object.getPrototypeOf(a) === Foo.prototype); 

a.talk(); // 'hello~\n'
// When the talk method is invoked it will first look on the object a for the talk method,
// when this is not present it will look on the prototype of a (i.e. Foo.prototype)

// When you want to call
// Foo.talk();
// this will not work because you haven't put the talk() property on the Foo
// function object. Rather it is located on the prototype property of Foo.

// We could make it work like this:
Foo.sayhi = function () {
    console.log('hello there');
};

Foo.sayhi();
// This works now. However it will not be present on the prototype chain 
// of objects we create out of Foo
0

あなたのケースでは、あなたがFoo.talk()したい場合:

function Foo() {};
// But use Foo.talk would be inefficient
Foo.talk = function () {
    alert('hello~\n');
};

Foo.talk(); // 'hello~\n'

しかし、prototypeを使用するのがより効果的です。


別の方法では、私の方法は静的クラスとして定義されています。

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

Foo.talk(); // 'hello~\n'

上記の静的クラスはprototypeを使用する必要はありません。静的な使用法として一度だけ作成されるからです。

https://github.com/yidas/js-design-patterns/tree/master/class

0
Nick Tsai