jsのthisキーワードの理解について

12162 ワード

このキーワードはc++,javaで提供されているので、勉強を始めたばかりの頃は難しいと思いましたが、理解すれば使いやすくなります.
これについては、フロントエンドの面接で必ず受けるテーマがたくさんあります.时にはネットでこれらのテーマを見て、自分でやってみました.ええ、本当に間違っています.実際の開発では、この問題にも遭遇します(一部のクラスライブラリでは処理されますが)、例えば、いくつかのフレームワークを使用する場合、例えば、knockout、なぜ直接thisを使用しないのか分からない場合がありますが、これをパラメータとして入力します.
次に私の理解について話して、メモとしても、後で参照するのに便利です.悪いところがあったら、批判を歓迎します.
   1. C#とは異なり、これは現在のオブジェクトを指しているに違いありません.
jsのthis指向は不確定であり,すなわち動的に変化できる.call/applyはthisが指す関数を変更するために使用され、コードをより柔軟にし、多重性を高めることができます.
   2. この場合、一般的には、関数の所有者を指します.
この点が重要です!この点が重要です!この点が重要です!
これもよくある面接問題で、次のコードがあります.


  var number = 1;
  var obj = {
     number: 2,
    showNumber: function(){
      this.number = 3;
      (function(){          
        console.log(this.number);
      })();
      console.log(this.number);
    }
  };
  obj.showNumber();

showNumberメソッドの所有者はobjであるため、this.number=3; これはobjのプロパティnumberを指します.
同じように2番目のconsole.log印刷もプロパティnumberです.
なぜ第二に、一般的にはthisは関数の所有者を指しているのか.特別な状況があるからだ.関数の自己実行は特殊な場合で、関数の自己実行の中で、thisはwindowを指します.だから最初のconsole.logはwindowのプロパティnumberを印刷します.
だから少し追加します.
   3. 関数の自己実行では、thisはwindowオブジェクトを指します.
拡張、thisについて、domイベントでは、通常次の3つのケースがあります.
次のようになります.
   1. ラベルプロパティを使用してイベントを登録します.この場合、thisはwindowオブジェクトを指します.


  function test(){alert(this)}

   2. 1の場合、thisをinputに向けるには、thisをパラメータとして渡すことができます.
   3. addEventListenerなどを使用して登録します.このときthisもinputを指します.

document.getElementById("test").addEventListener("click",test);

オブジェクト向けプログラミング言語では、thisキーワードについてよく知られています.例えばC++、C#、Javaなどがこのキーワードを提供しているので、勉強を始めるときは難しいと思いますが、理解さえすれば、とても便利で意味が確定します.JavaScriptもこのthisキーワードを提供していますが、古典的なOO言語よりも「混乱」しています.
次に、JavaScriptでのthisの使い方の乱れを見てみましょう.
1、HTML要素イベント属性においてinline方式でthisキーワードを使用する:

//        this  
">division element 
 //        this
 ">division element 

一般的によく使われる方法は、javascirpt:EventHandler(this)という形式です.しかし、ここでは合法的なJavaScript文を書くことができます.ここでクラスを定義してもいいです(ただし、内部クラスになります).ここでの原理は、スクリプトエンジンがdivインスタンスオブジェクトの匿名メンバーメソッドを生成し、onclickがこのメソッドを指すことである.
2、DOM方式でイベント処理関数にthisキーワードを使用する:

division element

 var div = document.getElementById('elmtDiv');  
 div.attachEvent('onclick', EventHandler);  
 
 function EventHandler()  
 {  
 //     this  
 }  
  
// --> 
 
division element

 var div = document.getElementById('elmtDiv');
 div.attachEvent('onclick', EventHandler);

 function EventHandler()
 {
 //     this
 }
 
// --> 

このときのEventHandler()メソッドのthisキーは,IEのwindowオブジェクトを示す.これはEventHandlerが一般的な関数にすぎず、attachEventの後、スクリプトエンジンはその呼び出しとdivオブジェクト自体に何の関係もないためです.また、nullに等しいEventHandlerのcallerプロパティも参照できます.この方法でdivオブジェクト参照を取得する場合は、thisを使用します.event.srcElement.
3、DHTML方式でイベント処理関数でthisキーワードを使用する:

division element
  
lt;mce:script language="javascript">
var div = document.getElementById('elmtDiv');  
div.onclick = function()  
{  
 //     this  
};  
 
/ --> 
 
division element

 var div = document.getElementById('elmtDiv');
 div.onclick = function()
 {
 //     this
 };
 
// --> 

ここでthisキーはdiv要素オブジェクトインスタンスを示し、スクリプトでDHTML方式を使用してdiv.onclickに直接EventHandlerを割り当てる方法であり、divオブジェクトインスタンスにメンバーメソッドを追加することに等しい.この方式と第1の方法の違いは、第1の方法はHTML方式を使用することであり、ここではDHTML方式であり、後者のスクリプト解析エンジンは匿名の方法を生成しない.
4、クラス定義でthisキーワードを使用する:

function JSClass()  
{  
var myName = 'jsclass';  
this.m_Name = 'JSClass';  
}  
 
JSClass.prototype.ToString = function()  
{  
alert(myName + ', ' + this.m_Name);  
};  
 
var jc = new JSClass();  
jc.ToString(); 
 function JSClass()
 {
 var myName = 'jsclass';
 this.m_Name = 'JSClass';
 }

 JSClass.prototype.ToString = function()
 {
 alert(myName + ', ' + this.m_Name);
 };

 var jc = new JSClass();
 jc.ToString(); 

これはJavaScriptシミュレーションクラス定義におけるthisの使用であり,これは他のOO言語の場合と非常によく知られている.ただし、ここではメンバーのプロパティとメソッドをthisキーで参照する必要があります.上記のプログラムを実行するとmyNameが定義されていないことが通知されます.
5、スクリプトエンジンの内部オブジェクトに原形メソッドのthisキーワードを追加する:

function.prototype.GetName = function()  
{  
var fnName = this.toString();  
fnName = fnName.substr(0, fnName.indexOf('('));  
fnName = fnName.replace(/^function/, '');  
return fnName.replace(/(^\s+)|(\s+$)/g, '');  
}  
function foo(){}  
alert(foo.GetName());  
 function.prototype.GetName = function()
 {
 var fnName = this.toString(); 
 fnName = fnName.substr(0, fnName.indexOf('(')); 
 fnName = fnName.replace(/^function/, ''); 
 return fnName.replace(/(^\s+)|(\s+$)/g, '');
 }
 function foo(){}
 alert(foo.GetName()); 

ここでthisとは、原形が追加されたクラスの例を指し、4のクラス定義と少し似ていて、あまり特別なところはありません.
6、2&4を組み合わせて、迷っているthisキーワードを使います.

view plaincopy to clipboardprint?
function JSClass()  
{  
this.m_Text = 'division element';  
this.m_Element = document.createElement('DIV');  
this.m_Element.innerHTML = this.m_Text;  
  
this.m_Element.attachEvent('onclick', this.ToString);  
}  
  
JSClass.prototype.Render = function()  
{  
document.body.appendChild(this.m_Element);  
}   
 
JSClass.prototype.ToString = function()  
{  
alert(this.m_Text);  
};  
 
var jc = new JSClass();  
jc.Render();  
jc.ToString(); 
 function JSClass()
 {
 this.m_Text = 'division element';
 this.m_Element = document.createElement('DIV');
 this.m_Element.innerHTML = this.m_Text;
  
 this.m_Element.attachEvent('onclick', this.ToString);
 }
  
 JSClass.prototype.Render = function()
 {
 document.body.appendChild(this.m_Element);
 } 

 JSClass.prototype.ToString = function()
 {
 alert(this.m_Text);
 };

 var jc = new JSClass();
 jc.Render(); 
 jc.ToString(); 

結果についてお話ししますと、ページが実行されると「division element」と表示され、確定したら「division element」という文字をクリックすると「undefined」と表示されます.
7、CSSのexpression式でthisキーワードを使用する:

height: expression(this.parentElement.height);">  
 division element  
  
 height: expression(this.parentElement.height);">
 division element

ここでthisは1と同様にすればよいと考えられ、div要素オブジェクトインスタンス自体を指す.
8、関数の内部関数でthisキーを使用する:

view plaincopy to clipboardprint?
function OuterFoo()  
{  
this.Name = 'Outer Name';  
 
function InnerFoo()  
{  
var Name = 'Inner Name';  
alert(Name + ', ' + this.Name);  
}  
return InnerFoo;  
}  
OuterFoo()(); 
 function OuterFoo()
 {
 this.Name = 'Outer Name';
 
 function InnerFoo()
 {
 var Name = 'Inner Name'; 
 alert(Name + ', ' + this.Name);
 }
 return InnerFoo;
 }
 OuterFoo()(); 

実行結果は、「Inner Name,Outer Name」と表示されます.2の説明では、ここの結果が「Inner Name,undefined」ならもっと合理的なようですね?しかし、正確な結果は確かに前者であり、これはJavaScript変数の役割ドメインの問題によって決定されたものであり、「元のJscriptのキーワード「var」には文章があるのか」の一文と返事を詳しく理解することを推奨する.
まとめてみると、JavaScriptのthisの使い方は、以下の3つあります(詳しくは原文参照).
    1.HTML要素イベント属性またはCSSのexpression式でinline方式でthisキーワードを使用――原文の1、7に対応
    2.イベント処理関数にthisキーを使用――原文に対応する2,3
このうち2つの方法に分けることができます
(1)DOM方式――この方式の結果はthisがウィンドウオブジェクトを指す
(2)DHTML方式――この方式の結果、thisがdiv要素オブジェクトを指す例
    3.クラス定義でthisキーワードを使用し、その内部関数またはメンバー関数(主にprototype生成)で使用します.原文の4、5、8に対応します.
なお、関数でもオブジェクトであるため、次のように変数定義とメンバー変数定義を区別する必要があります.

view plaincopy to clipboardprint?

var variableName;    //      
//   :         
//    :    variableName  
this.varName;      //        
//   :                  
//    :this.varName 
var variableName;    //    
//   :       
//    :    variableName
this.varName;      //      
//   :                
//    :this.varName

以上まとめた3種類のthisの使用方法のうち、1つ目は比較的理解しやすく、ここでは原文の6点に記載のプログラムをテストし、以下のように改善し、上記の2つの使用方法を説明した.

view plaincopy to clipboardprint?

    function JSClass()  
    {  
      var varText = "func variable!";                 //          
      this.m_Text = 'func member!';                    //          
      this.m_Element = document.createElement('DIV');   //    ,    div    
      this.m_Element.innerHTML = varText;             //           
      this.m_Element.attachEvent('onclick', this.ToString);  //                
      this.newElement = document.createElement('DIV');  
      this.newElement.innerHTML = "new element";   
      this.newElement.m_Text = "new element text!";      //            
      this.newElement.onclick = function()  
      {  
        alert(this.m_Text);                       //  div       
      };  
    }  
   
    JSClass.prototype.Render = function()  
    {  
      document.body.appendChild(this.m_Element);       // div         
      document.body.appendChild(this.newElement);  
    }    
 
    JSClass.prototype.ToString = function()  
    {  
      alert(this.m_Text);                         //    (window)    
    };  
 
    function initialize(){  
      var jc = new JSClass();  
      jc.Render();  
      jc.ToString();                             //   this  JSClass    ,   m_Text    
    }  
    
// -->  

    initialize();  
    
// -->  
  
 function JSClass()
  {
   var varText = "func variable!";     //        
    this.m_Text = 'func member!';     //        
    this.m_Element = document.createElement('DIV'); //    ,    div  
    this.m_Element.innerHTML = varText;    //         
    this.m_Element.attachEvent('onclick', this.ToString); //              
    this.newElement = document.createElement('DIV');
    this.newElement.innerHTML = "new element"; 
    this.newElement.m_Text = "new element text!";  //          
    this.newElement.onclick = function()
   {
     alert(this.m_Text);      //  div     
   };
  }
  
  JSClass.prototype.Render = function()
  {
    document.body.appendChild(this.m_Element);  // div       
    document.body.appendChild(this.newElement);
  }   

  JSClass.prototype.ToString = function()
  {
    alert(this.m_Text);       //    (window)  
  };

 function initialize(){
   var jc = new JSClass();
   jc.Render(); 
   jc.ToString();        //   this  JSClass    ,   m_Text  
  }
  
// -->

   initialize();
  
// -->

上記のコードの実行結果は、次のとおりです.
ページがロードされると、ダイアログボックスがポップアップされ、func memberが出力されます.
ページに表示

 func variable!
 new element

func variableをクリックすると、ポップアップダイアログボックスが開き、undefinedが表示されます.
――このときtoString関数のthisポインタがwindowを指しているため
new elementをクリックすると、ポップアップダイアログボックスにnew element textが表示されます.
――toString関数のthisポインタがdiv要素を指しているため、この要素はm_を定義しています.Textメンバー(this.newElement.m_Text="new element text!")