js の this キーワードを理解する

怪我咯
リリース: 2017-07-07 10:35:09
オリジナル
1461 人が閲覧しました

このキーワードは誰もがよく知っていると思いますが、js で提供される this キーは oo 言語で提供されるものよりも複雑です。この記事では、js でのこのキーワードの理解を紹介します

このキーワードは C++ と Java の両方で提供されています。最初に理解すると難しいですが、一度理解すると使いやすくなります。js でのこのキーワードの理解について詳しく説明します。この記事を通して。

これについては、多くのフロントエンド面接で必須の質問ですが、時々インターネットでこれらの質問を見て、自分で試してみることがあります。実際の開発でも、この問題に遭遇します (ただし、一部のクラス ライブラリがこの問題に対処するのに役立ちます)。たとえば、ノックアウトなどのフレームワークを使用する場合、なぜこれを直接使用しないのか理解できないことがあります。ですが、パラメータが渡されるのでこれを使用します。

次に、私の理解をお話しいただき、今後の参考のためのメモとしても活用させていただきます。間違っているところがあれば指摘、批判してください。

1. C# とは異なり、これは現在のオブジェクトを指す必要があります。

js の this 点は不確実なので、動的に変更できる可能性があります。 call/apply は、これが指すポイントを変更するために使用される関数です。この設計により、コードがより柔軟で再利用可能になります。

2. これは通常、関数の所有者を指します。

これはとても重要です!この点は非常に重要です!この点は非常に重要です!

次のコードに示すように、これは面接でよくある質問でもあります:

<script type="text/javascript">
  var number = 1;
  var obj = {
     number: 2,
    showNumber: function(){
      this.number = 3;
      (function(){          
        console.log(this.number);
      })();
      console.log(this.number);
    }
  };
  obj.showNumber();
</script>
ログイン後にコピー

showNumber メソッドの所有者は obj であるため、this.number=3; これは obj の属性番号を指します。

同様に、2 番目の console.log にも属性番号が出力されます。

2 番目の点で一般にこれが関数の所有者を指すとしているのは、特別な事情があるためです。関数の自己実行は特殊なケースであり、関数の自己実行では、これはウィンドウを指します。したがって、最初の console.log にはウィンドウの属性番号が出力されます。

そこで、何かを追加する必要があります:

3. 関数の自己実行では、これはウィンドウ オブジェクトを指します。

拡張機能ですが、これについてもう 1 つの混乱を招くのは、dom イベントには通常 3 つの状況があるということです:

次のように:

1. label 属性を使用してイベントを登録します。この時点では、これは を指します。ウィンドウオブジェクト。

<input id="test" type="button" value="按钮" onClick="test()"/>
  function test(){alert(this)}
ログイン後にコピー

2. 1 の場合、これを入力にポイントするために、これをパラメーターとして渡すことができます。

3. addEventListener を使用して登録します。このとき、これも入力を指します。

document.getElementById("test").addEventListener("click",test);
ログイン後にコピー

オブジェクト指向 プログラミング言語 では、this キーワードによく馴染みます。たとえば、C++、C#、Java にはすべてこのキーワードがありますが、学習の初めは難しくても、一度理解すると非常に便利で有意義です。 JavaScript にもこのキーワードはありますが、その使用法は古典的な OO 言語よりもはるかに「混乱」します。

JavaScript でこれを使用するさまざまな方法の何が混乱しているのかを見てみましょう。

1. HTML 要素のイベント属性で this キーワードをインラインで使用します:

// 可以在里面使用this  
">pision element 
 // 可以在里面使用this
 ">pision element
ログイン後にコピー

最も一般的に使用される方法は、javascirpt: EventHandler(this) の形式で使用することです。ただし、必要に応じて、実際にはここに任意の正当な JavaScript ステートメントを記述することができます (ただし、これは内部クラスになります)。ここでの原則は、スクリプト エンジンが p インスタンス オブジェクトの匿名 メンバー メソッド を生成し、onclick がこのメソッドを指すということです。

2. DOM メソッドを使用して、イベント処理 関数で this キーワードを使用します。

pision element

 var p = document.getElementById(&#39;elmtp&#39;);  
 p.attachEvent(&#39;onclick&#39;, EventHandler);  
 
 function EventHandler()  
 {  
 // 在此使用this  
 }  
  
// --> 
 
pision element

 var p = document.getElementById(&#39;elmtp&#39;);
 p.attachEvent(&#39;onclick&#39;, EventHandler);

 function EventHandler()
 {
 // 在此使用this
 }
 
// -->
ログイン後にコピー

この時点で、EventHandler() メソッドの this キーワードは、オブジェクトが IE ウィンドウ オブジェクトであることを示します。これは、EventHandler が単なる通常の関数であるため、attachEvent の後のスクリプト エンジンの呼び出しは p オブジェクト自体とは何の関係もありません。同時に、EventHandler の caller 属性 (null に等しい) を確認できます。このメソッドで p オブジェクト参照を取得したい場合は、this.event.srcElement を使用する必要があります。

3. イベント処理関数でこのキーワードを使用するには、DHTML を使用します。

pision element
  
lt;mce:script language="javascript">
var p = document.getElementById(&#39;elmtp&#39;);  
p.onclick = function()  
{  
 // 在此使用this  
};  
 
/ --> 
 
pision element

 var p = document.getElementById(&#39;elmtp&#39;);
 p.onclick = function()
 {
 // 在此使用this
 };
 
// -->
ログイン後にコピー

ここでの this キーワードで示されるコンテンツは、DHTML を使用して、スクリプト内の p.onclick に EventHandler を直接割り当てます。 .メソッドは、p オブジェクト インスタンスにメンバー メソッドを追加することと同じです。このメソッドと最初のメソッドの違いは、最初のメソッドは HTML メソッドを使用し、後者のスクリプト解析エンジンは匿名メソッドを生成しなくなることです。

4. クラス定義で次のキーワードを使用します:

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

 JSClass.prototype.ToString = function()
 {
 alert(myName + &#39;, &#39; + 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(&#39;(&#39;));  
fnName = fnName.replace(/^function/, &#39;&#39;);  
return fnName.replace(/(^\s+)|(\s+$)/g, &#39;&#39;);  
}  
function foo(){}  
alert(foo.GetName());  
 function.prototype.GetName = function()
 {
 var fnName = this.toString(); 
 fnName = fnName.substr(0, fnName.indexOf(&#39;(&#39;)); 
 fnName = fnName.replace(/^function/, &#39;&#39;); 
 return fnName.replace(/(^\s+)|(\s+$)/g, &#39;&#39;);
 }
 function foo(){}
 alert(foo.GetName());
ログイン後にコピー

这里的this指代的是被添加原形的类的实例,和4中类定义有些相似,没有什么太特别的地方。

6、结合2&4,说一个比较迷惑的this关键字使用:

view plaincopy to clipboardprint?
function JSClass()  
{  
this.m_Text = &#39;pision element&#39;;  
this.m_Element = document.createElement(&#39;p&#39;);  
this.m_Element.innerHTML = this.m_Text;  
  
this.m_Element.attachEvent(&#39;onclick&#39;, 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 = &#39;pision element&#39;;
 this.m_Element = document.createElement(&#39;p&#39;);
 this.m_Element.innerHTML = this.m_Text;
  
 this.m_Element.attachEvent(&#39;onclick&#39;, 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();
ログイン後にコピー

我就说说结果,页面运行后会显示:"pision element",确定后点击文字"pision element",将会显示:"undefined"。

7、CSS的expression表达式中使用this关键字:

height: expression(this.parentElement.height);">  
 pision element  
  
 height: expression(this.parentElement.height);">
 pision element
ログイン後にコピー

这里的this看作和1中的一样就可以了,它也是指代p元素对象实例本身。

8、函数中的内部函数中使用this关键字:

view plaincopy to clipboardprint?
function OuterFoo()  
{  
this.Name = &#39;Outer Name&#39;;  
 
function InnerFoo()  
{  
var Name = &#39;Inner Name&#39;;  
alert(Name + &#39;, &#39; + this.Name);  
}  
return InnerFoo;  
}  
OuterFoo()(); 
 function OuterFoo()
 {
 this.Name = &#39;Outer Name&#39;;
 
 function InnerFoo()
 {
 var Name = &#39;Inner Name&#39;; 
 alert(Name + &#39;, &#39; + 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

其中可分为两种方式

(1)DOM方式——此种方式的结果是this指向窗口(window)对象

(2)DHTML方式——此种方式的结果是this指向p元素对象实例

3.在类定义中使用this关键字并在其 内部函数 或 成员函数(主要是prototype产生)中使用——对应原文的4、5、8

需要说明的是,在函数也是个对象,因此需要区分 变量定义 和 成员变量定义,如下:

view plaincopy to clipboardprint?

var variableName;    //变量定义  
//作用域:函数定义范围内  
//使用方法:直接使用variableName  
this.varName;      //成员变量定义  
//作用域:函数对象定义范围内及其成员函数中  
//使用方法:this.varName 
var variableName;    //变量定义
//作用域:函数定义范围内
//使用方法:直接使用variableName
this.varName;      //成员变量定义
//作用域:函数对象定义范围内及其成员函数中
//使用方法:this.varName
ログイン後にコピー

以上归纳出的三类this的使用方法中,第一种比较容易理解,这里对原文中第6点提到的程序进行了测试和改进如下,以说明上述后两种使用方法:

view plaincopy to clipboardprint?

    function JSClass()  
    {  
      var varText = "func variable!";                 //函数中的普通变量  
      this.m_Text = &#39;func member!&#39;;                    //函数类的成员变量  
      this.m_Element = document.createElement(&#39;p&#39;);   //成员变量,创建一个p对象  
      this.m_Element.innerHTML = varText;             //使用函数的普通变量  
      this.m_Element.attachEvent(&#39;onclick&#39;, this.ToString);  //给这个对象的事件连上处理函数  
      this.newElement = document.createElement(&#39;p&#39;);  
      this.newElement.innerHTML = "new element";   
      this.newElement.m_Text = "new element text!";      //给创建的对象建个成员  
      this.newElement.onclick = function()  
      {  
        alert(this.m_Text);                       //指向p对象的成员  
      };  
    }  
   
    JSClass.prototype.Render = function()  
    {  
      document.body.appendChild(this.m_Element);       //把p对象挂在窗口上  
      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 = &#39;func member!&#39;;     //函数类的成员变量
    this.m_Element = document.createElement(&#39;p&#39;); //成员变量,创建一个p对象
    this.m_Element.innerHTML = varText;    //使用函数的普通变量
    this.m_Element.attachEvent(&#39;onclick&#39;, this.ToString); //给这个对象的事件连上处理函数
    this.newElement = document.createElement(&#39;p&#39;);
    this.newElement.innerHTML = "new element"; 
    this.newElement.m_Text = "new element text!";  //给创建的对象建个成员
    this.newElement.onclick = function()
   {
     alert(this.m_Text);      //指向p对象的成员
   };
  }
  
  JSClass.prototype.Render = function()
  {
    document.body.appendChild(this.m_Element);  //把p对象挂在窗口上
    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指针指向p元素,而该元素已经定义了m_Text成员(this.newElement.m_Text = "new element text!")

以上がjs の this キーワードを理解するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート