1

私のコードはとてもシンプルです。私にとっては、うまくいくはずです。

var preview = WinJS.Class.define(
   function (el, options) {
       el.winControl = this;
       this.el = el;

       this.textarea = d.getElementById('preview-input');
       this.preview = d.getElementById('preview-text');
       this.form = d.getElementById('perview-form');

       this.preview.addEventListener('click', this.click, false);
       //WinJS.Utilities.query("button", this.form)
       //this.preview.addEventListener('', this.save, false);

   },

   {
       click: function (e) {
           this.form.style('display', 'block');
       }
   }
);

WinJS.Namespace.define('RegCtrl', { preview: preview });

しかし、クリックが発生したときthis.formはnullの未定義のようです。なんで?クラスのすべてのメソッドでオブジェクトを初期化する必要はありません。

新しいテスト

追加のテストを非常に小さくしました

var preview = WinJS.Class.define(
   function (el, options) {
       var test = 1;
       this.test = 1;
       this.test1();
   },

   {
       test1: function () {
           console.log(this.form, test);
       }
   }

); WinJS.Namespace.define('RegCtrl'、{プレビュー:プレビュー});

このテストはオンラインで失敗しますthis.test1();RegCtrl.preview()このクラスはではなく呼ばれていると私は思いますnew RegCtrl.preview()

これが呼び出した関数の内部をどのように確認しnewますか?単純な関数ではありませんか?

4

3 に答える 3

3

他の答えは何が起こっているのかを説明しておらず、そのため間違ったアドバイスをしています。

JavaScriptにはファーストクラスの関数オブジェクトがあります-それらを値として渡すことができます。これは、このコールバックを設定するときに行っていることとまったく同じです。

this.preview.addEventListener('click', this.click, false);

たまたま関数であるthis.clickプロパティの内容を取得し、それをaddEventListener関数に渡して、必要な処理を実行します。

私はそこでの用語について非常に具体的でした-私が具体的に言ったのはメソッドではなく関数であることに注意してください。JavaScriptには実際にはメソッド構造がなく、オブジェクトのプロパティとしてメソッドがあるだけです。

では、「この」メンバーはどこから来たのでしょうか。これは、呼び出し元(「。」の左側で使用するオブジェクト)で決定されます。これの値になるものです。例えば、

function exampleFunc() { console.log("this.myName = " + this.myName); }

var a = { myName: "Chris", doSomething: exampleFunc };
var b = { myName: "Bob", doSomething: exampleFunc };

doSomethingプロパティにまったく同じ関数を割り当てたことに注意してください。何が起こるか:

a.doSomething(); // Outputs "this.myName = Chris"
b.doSomething(); // Outputs "this.myName = Bob"

2つの異なるオブジェクトを介して呼び出されるまったく同じ関数オブジェクトには、異なるthisポインターがあります。

exampleFuncはグローバル関数です。それを呼び出しましょう:

exampleFunc() // Outputs "this.myName = undefined"

では、未定義はどこから来たのでしょうか?グローバル関数では、「this」はmyNameプロパティが定義されていないwindow(グローバルスコープ)に設定されます。これは、代わりにこれを実行できることも意味します。

myName = "Global Name"; // note, no var - we want this global
exampleFunc(); // Outputs "this.myName = Global Name"

では、元の質問はどうなっているのでしょうか。基本的に、コールバックとなる関数this.clickを渡しましたが、呼び出したい「this」ポインターを渡していません。実際、addEventListenerには、このポインターを渡す方法がありません。その結果、関数が呼び出されたとき、これはオブジェクトを指していません。頭のてっぺんから何を指しているのか覚えていません。ウィンドウまたはクリックされた要素のいずれかです。DOMのドキュメントを確認してください。

適切なコンテキスト(コンテキスト=正しい「this」)で適切な関数を呼び出すための従来のアプローチは、クロージャを使用することです。「this」を変数にキャプチャしてから、右のthisポインタを使用して実際のコールバックを呼び出す無名関数を渡します。コードは次のようになります。

var preview = WinJS.Class.define(
   function (el, options) {

       // Capture your current this pointer in a global variable
       // Using "that" as the name comes from JavaScript: The Good Parts book
       var that = this;

       el.winControl = this;
       this.el = el;

       this.textarea = d.getElementById('preview-input');
       this.preview = d.getElementById('preview-text');
       this.form = d.getElementById('perview-form');

       // Note what gets passed instead of this.click:
       this.preview.addEventListener('click', 
           function (e) {
               // NOTE: Calling through "that": "this" isn't pointing to the right object anymore
               // Calling through "that" resets "this" inside the call to click
               that.click(e);
           }, false);    
   },

   {
       click: function (e) {
           this.form.style('display', 'block');
       }
   }
);

これは、ECMAScript 5にこれらのラッパーを作成するためのユーティリティ関数(function.bind)があるのに十分な一般的なパターンです。これを行う:

       this.preview.addEventListener('click', 
           this.click.bind(this),
           false);    

コンストラクトthis.click.bind(this)は、呼び出されると、渡したもの(この場合は「this」)に「this」参照を設定する新しい関数を作成し、呼び出した関数を呼び出します。

はい、「this」にはさまざまな値が浮かんでいます。「これ」が何を指しているのかを追跡することは、JavaScriptプログラミングを習得する上で重要な部分です。

于 2012-11-04T18:44:35.333 に答える
2

グローバルJavaScript変数を次のように定義することをお勧めします。

     var myForm = document.getElementById('perview-form');

またはjestはvar myForm;、内部function (el, options)を次のように定義して初期化します。

     myForm = d.getElementById('perview-form');

これで、この変数を関数で次のように使用できます。

     myForm.style('display', 'block');

編集:この変数をインスタンスレベルの変数にするために、この変数を最初の行として 定義すると、次のようになります。WinJS.Class.define

     var preview = WinJS.Class.define(
         var myForm;
         function (el, options) {
           ....
           ....
           myForm = d.getElementById('perview-form');
           ...
         },

         {
            click: function (e) {
            myForm.style('display', 'block');
         }
       });
于 2012-11-04T04:21:24.800 に答える
1

何を探すべきかわからない場合、これを調査するのは非常に困難です。1行追加し、別の行を変更しました。これで問題は解決するはずです。

thisつまり、新しい関数を入力するたびにキーワードがリセットされます。これは、関数this内の値が外部スコープの値と同じではありません。あなたが望むこれを保存してください。の名前はかなり一般的なようです。clickthisthat

OPが提供するリンクに基づいて編集。
このコードはテストされていません。使用thisがうまくいかない場合は、試してみます。this2
申し訳ありませんが、これをテストすることはできませんが、フレームワークがどこにもないため、知識に基づいた推測を行っています。

var preview = WinJS.Class.define(

  function (el, options) {
    that = this; // No var should be needed since it is declared already
    el.winControl = this;
    this.el = el;

    this.textarea = d.getElementById('preview-input');
    this.preview = d.getElementById('preview-text');
    this.form = d.getElementById('perview-form');

    this.preview.addEventListener('click', this.click, false);
    //WinJS.Utilities.query("button", this.form)
    //this.preview.addEventListener('', this.save, false);

  },
  // This is the section for instance vars
  {
    click: function (e) {
      that.form.style('display', 'block'); // AND THIS ONE
    },
    that: null // Added instance variable
  },

  // And these are static variables
  {
    that2: null
  }
);
于 2012-11-04T04:20:37.000 に答える