3

JavaScript でアプリケーションを作成しようとしています。JavaScript は、Web ページのスクリプト作成に何年も使用してきましたが、スコープとオブジェクト指向についての理解がやや不足していることに気付きました。私のバックグラウンドは主に C# や Ruby などのオブジェクト指向言語であるため、JavaScript の奇妙な疑似オブジェクト指向の機能的アプローチは、私を際限なく混乱させます。

私が問題を抱えているthisのは、クラス内のすべての参照で常にそれが必要な理由です。JS で役に立つ多くのことを書くために、途方もない量のタイピングが必要になるように思われます。

function MyClass()
{ 
  var a=1;
  this.b = 2;

  this.internalMethod= function()
  {
   console.log("a is: "+a); // returns "a is: 1"
   // console.log("b is: "+b); - this fails because b is undefined
   console.log("this.a is: "+this.a); // returns "this.a is: undefined" but doesn't crash.
   console.log("this.b is: "+this.b); // returns "this.b is: 2"
 }

}

MyClass.prototype.externalMethod = function()
{
//     console.log("a is: "+a); - fails
//     console.log("b is: "+b); - fails
       console.log("this.a is: "+this.a);  // "this.a is: undefined"
       console.log("this.b is: "+this.b);  // "this.b is: 2"
}

var m = new MyClass();
m.internalMethod();
m.externalMethod();

このことから私が理解していることは、このclass.prototypeアプローチで新しいパブリック メソッドを追加する場合、 で定義されたプロパティにしかアクセスできないということthisです。

クラス定義関数で内部メソッドを作成するvarと、クラス自体の任意の値にアクセスできthis.propertythis.

これは正しいです?prototypeメソッドを使用する関数のプロパティにアクセスするには、常に明示的なオブジェクト参照を含める必要がありますか? class.prototypeもしそうなら、関数を追加するためにパターンを使用するのではなく、親クラス関数内ですべての関数を宣言する必要がありますか?

本質的に、オブジェクト指向 Javascript を作成する際に変数スコープを管理するための標準的なアプローチを探しています。このトピックに関する記事のほとんどは、オブジェクト指向の基本的な紹介であるか、この分野について詳しく説明しているように見えます。私のクラスの多くはかなりデータ集約的であり、フォームで呼び出しを行わなければならないことはthis.myMethod( this.firstArray, this.secondArray, this.thirdArray, this.fourthArray )長いカットのように見え、コードの可読性を妨げます.

var that=this呼び出し元のスコープの問題を回避するためのトリックは知っていますが、私の質問に実際には関係ないことがわかっている限り、例を台無しにしたくありませんでした。)

4

5 に答える 5

2

このことから私が理解していることは、このclass.prototypeアプローチで新しいパブリック メソッドを追加する場合、 で定義されたプロパティにしかアクセスできないということthisです。

クラス定義関数で内部メソッドを作成するvarと、クラス自体の任意の値にアクセスできthis.propertythis.

「内部」および「外部」プロパティなどはなく、「所有」および「継承」プロパティのみがあります。あなたの例では、プロトタイプから継承されてinternalMethodいる間、新しいオブジェクトに直接割り当てられています。externalMethodそれらは決して異なるものでも特別なものでもありません。異なるスコープで定義された 2 つの関数は、常に異なります。

internalMethodクロージャーであるため、コンストラクター内のローカル変数にアクセスできます。

propertiesプロトタイプ メソッドを使用する関数にアクセスするには、常に明示的なオブジェクト参照を含める必要がありますか?

関数と「それらが割り当てられている」オブジェクトとの間に暗黙的な関係がないことを理解することが重要です。関数は独立したエンティティです。

接続は、それに応じて設定することにより、実行時にのみ決定されますthis。そうです、プロトタイプに割り当てられたものだけでなく、すべてのthis関数に対して が必要になります。の詳細をご覧くださいthis

class.prototypeもしそうなら、関数を追加するためにパターンを使用するのではなく、親クラス関数内ですべての関数を宣言する必要がありますか?

これについては、次の場所で詳しく説明しています。

本質的に、オブジェクト指向 Javascript を作成する際に変数スコープを管理するための標準的なアプローチを探しています。

私の主観的なアドバイス:

複雑にしないでおく。ローカル変数とクロージャーを介してプライベート変数/メソッドをシミュレートしようとしないでください。コンストラクターでインスタンス固有のデータを初期化して割り当て、インスタンス間で共有する必要があるもの (メソッドなど) をすべてプロトタイプに割り当てます。this.privateProperty_外部コードからアクセスする必要があるプロパティを示すなど、命名規則を使用します。

私のクラスの多くはかなりデータ集約的であり、フォームで呼び出しを行わなければならないことはthis.myMethod( this.firstArray, this.secondArray, this.thirdArray, this.fourthArray )長いカットのように見え、コードの可読性を妨げます.

この例では、thisinsideはオブジェクト自体を参照するため、関数で同じように、 などにmyMethodアクセスできます。それらを渡す必要はありません。this.firstArraythis.secondArray

于 2013-02-28T14:20:29.933 に答える
2
function MyClass()
{ 
  var a=1;
  this.b = 2;

  this.internalMethod= function()
  {
   console.log("a is: "+a); // returns "a is: 1"
   // console.log("b is: "+b); - this fails because b is undefined
   console.log("this.a is: "+this.a); // returns "this.a is: undefined" but doesn't crash.
   console.log("this.b is: "+this.b); // returns "this.b is: 2"
 }

}

そのコードでは、変数 aを宣言してから関数を宣言したため、最初の console.log は正しい値を返します。これは、環境を取得し、すべてをクロージャーと呼ばれるものに保存します (この説明は少しずれている可能性があります)。ここで起こるのは、 を呼び出すとinternalMethod、その環境内のその関数にも の定義があるということですa。これconsole.logは、a変数が の属性ではなくthis、 のスコープに対する単なるグローバル変数であるためinternalMethodです。

MyClass.prototype.externalMethod = function()
{
//     console.log("a is: "+a); - fails
//     console.log("b is: "+b); - fails
       console.log("this.a is: "+this.a);  // "this.a is: undefined"
       console.log("this.b is: "+this.b);  // "this.b is: 2"
}

そのコードでaは、メソッドを宣言したときに存在しなかったため、定義されていませんが、this.b作業中の MyClass の属性の一部であるため、定義されています。

つまり、要約するthisと、「クラス」に内部属性を追加または使用するときにキーワードを使用する必要があります (クラスはここに存在しないため、クラスと呼ぶべきではありません)。面倒かもしれませんが、メソッド内からオブジェクトの内部属性を参照する唯一の方法です。

さらに、これらの 2 つの記事は、JS の OOP テクニックといくつかのよくある間違いについて少し説明しているので、読むのが面白いと思うかもしれません。

ご不明な点がございましたら、お気軽にお問い合わせください。

于 2013-02-28T14:23:34.400 に答える
1

クラス内の何かへのすべての参照で、常にそれが必要なようです。JSで役立つものをたくさん書くために、途方もない量のタイピングが必要になるようです

あなたのやり方は間違っていません。私のコメントでは、コンストラクターを作成するすべての段階を説明しようとするこの回答を参照しました。それを読んだ後、使用するのが間違っていない理由を理解できますthisが、JavaScriptは別のステートメントを提供しwithます。プロパティが初期化された後に入力する必要があります。

function MyConstructor() {
    this.a = 1; // initialise properties with `this`
    this.b = 2;
    this.c = 3;
    this.d = 4;
}
MyConstructor.prototype = {};
MyConstructor.prototype.foobar = function() {
    var c = 5, e = null;
    with (this) { // `with` now means you can do `a` instead of `this.a`
        var d = 6;
        console.log(a, b, c, d, e);
        a = 0 - a; // in `this`, property gets set to property
        b = -2; // in `this`
        c = -c; // in `this`, var'd outside `with`, property gets set to property
        d = -d; // in `this`, var'd inside `with`, property gets set to var
        e = 100; // not in `this`, var'd, var gets set (not var'd => global set)
    }
};
x = new MyConstructor(); // new instance
console.log(x.a, x.b, x.c, x.d, x.e);
//  1  2  3  4 undefined -- undefined as no property `e`
x.foobar();
//  1  2  3  6      null -- 6 from var, null from `var e = null`
console.log(x.a, x.b, x.c, x.d, x.e);
// -1 -2 -3 -6 undefined -- undefined as still no property `e`
于 2013-02-28T15:39:33.413 に答える
1

JavaScript は従来の継承言語ではないため、オブジェクト内の変数を検索しません。これは、レキシカルスコープを備えたSchemeに基づいています。

あなたの例は2つのことを示しています:

  • thisインスタンス化されているオブジェクトを参照します
  • aは単なる変数です

では、internalMethodまだコンストラクター関数にいます。したがって、コンストラクターで定義された変数 (関数スコープと字句スコープ) にアクセスできます。ただし、コンストラクターを終了すると、a到達できなくなります。

this.bは、インスタンス化されたオブジェクトにプロパティをアタッチすることを意味しますb。これは基本的にこれと同等です:

function Foo() {}
var foo = {
    b: ''
};
foo.constructor.prototype = Foo.prototype;

基本的。でインスタンス化するとnew、もう少し多くのことができます。

したがって、インスタンス化されたオブジェクトにアクセスする場合は、 を使用する必要がありますthis。レキシカル スコープの力を使いたいだけなら、単純な変数とクロージャで遊ぶこともできます。

たとえば、このコンストラクターは、呼び出されるたびに新しいオブジェクトをインスタンス化しますが、次のようなものはありませんthis

function Foo() {
    var a = 1;
    var b = 2;
    return {
        internalMethod: function() {
            return a;
        },

        incB: function() {
            return ++b;
        }
    };
}

var foo = Foo();
foo.internalMethod(); // 1
foo.incB(); // 3
foo.incB(); // 4

var bar = new Foo();
bar.incB(); // 3

このパターンを「モジュールパターン」と呼びます。

オブジェクトの使用を制限している場合は、すぐに実行される関数を使用してオブジェクトを返すことができます (したがって、別のスコープで遊ぶことができます)。

function Foo() {
    var a = 1;
    var b = 2;
    return function() {
        var c = 3;
        return {
            a: a,
            c: c
        };
    }();
}
于 2013-02-28T14:23:49.683 に答える
0

パブリック/ローカル属性とスコープについて学ぶために、Javascript モジュール パターンについて読むことをお勧めします。

var現在の関数と内部の関数でアクセスできる変数を宣言します。オブジェクトにアタッチされたメソッド/属性は、どこからでもアクセスできるため、「パブリック」と呼ばれます。クロージャーに「トラップ」されたローカル変数は、プライベート メンバーをエミュレートするために使用されます。

パブリック メソッドをプロトタイプにアタッチすることは、異なるインスタンスでそれらのメソッドを再利用するためのメモリ効率の良い方法です。これらのプロトタイプ メソッドでクロージャーを使用することもできます。

1 つの注意点: クロージャーは「プライベート」変数をエミュレートしますが、「保護された」変数はエミュレートしないため、必要な場合に継承が非常に難しくなります。

于 2013-02-28T14:22:04.557 に答える