首頁 > web前端 > js教程 > js裡的this關鍵字的理解

js裡的this關鍵字的理解

怪我咯
發布: 2017-07-07 10:35:09
原創
1499 人瀏覽過

this關鍵字相信大家都非常熟悉,js中提供的this關鍵在要比oo語言中混亂,以下透過本文給大家介紹js裡this關鍵字的理解,需要的朋友可以參考下

this關鍵字在c++,java中都提供了這個關鍵字,在剛開始學習時覺得有難度,但是只要理解了,用起來就方便多了,下面透過本篇文章給大家詳解js裡this關鍵字的理解。

關於this,是很多前端面試必考的題目,有時候在網路上看到這些題目,自己試了一下,額,還真的錯了!在實際開發中,也會遇到this 的問題(雖然有些類別庫會幫我們處理),例如在使用一些框架的時候,例如:knockout,有時候不明白為什麼不直接使用this,而要把this 作為參數傳入。

   接下來你談談我對它的理解,也作為一個筆記,方便以後參閱。有不對的地方,歡迎指出批評。

   1. 不像C#,this一定是指向目前物件。

js的this指向是不確定的,也就是說是可以動態改變的。 call/apply 就是用來改變this指向的函數,這樣設計可以讓程式碼更有彈性,多用性更高。

   2. this 一般情況下,都是指向函數的擁有者。

這一點很重要!這一點很重要!這一點很重要!

   這也是一個常見的面試題,如下程式碼:

<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; this 指向的就是 obj 的屬性 number。

  同理,第二個 console.log 印刷的也是屬性 number。

   為什麼第二點說在一般情況下this都是指向函數的擁有者,因為有特殊情況。函數自執行就是特殊情況,在函數自執行裡,this 指向的是:window。所以第一個 console.log 印製的是 window 的屬性 number。

   所以要加一點:

   3. 在函數自執行裡,this 指向的是 window 物件。

   擴展,關於this,還有一個地方比較讓人模糊的是在dom 事件裡,通常有如下3種情況:

   如下:

# 1. 使用標籤屬性註冊事件,此時​​this 指向的是window 物件。

<input id="test" type="button" value="按钮" onClick="test()"/>
  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  
">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的window物件。這是因為EventHandler只是一個普通的函數,對於attachEvent後,腳本引擎對它的呼叫和p物件本身沒有任何的關係。同時你可以再看看EventHandler的caller屬性,它是等於null的。如果我們要在這個方法中獲得p物件引用,應該使用:this.event.srcElement。

  3、用DHTML方式在事件處理函數中使用this關鍵字:

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關鍵字指示的內容是p元素物件實例,在腳本中使用DHTML方式直接為p.onclick賦值一個EventHandler的方法,等於為p物件實例新增一個成員方法。這種方式和第一種方法的差異是,第一種方法是使用HTML方式,而這裡是DHTML方式,後者腳本解析引擎不會再產生匿名方法。

  4、類別定義中使用this關鍵字:

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中文網其他相關文章!

相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板