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

關於js裡的this關鍵字的理解_javascript技巧

WBOY
WBOY原創
2016-05-16 15:44:411118瀏覽

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  
">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物件本身沒有任何的關係。同時你可以再看看EventHandler的caller屬性,它是等於null的。如果我們要在這個方法中獲得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物件實例新增一個成員方法。這種方式和第一種方法的差異是,第一種方法是使用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&#63;
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&#63;
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

      其中可分为两种方式

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

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

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

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

view plaincopy to clipboardprint&#63;

var variableName;    //变量定义  
//作用域:函数定义范围内  
//使用方法:直接使用variableName  
this.varName;      //成员变量定义  
//作用域:函数对象定义范围内及其成员函数中  
//使用方法:this.varName 
var variableName;    //变量定义
//作用域:函数定义范围内
//使用方法:直接使用variableName
this.varName;      //成员变量定义
//作用域:函数对象定义范围内及其成员函数中
//使用方法:this.varName

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

view plaincopy to clipboardprint&#63;

    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!")

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn