欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Javascript中神奇的this

 更新時間:2016年01月20日 17:11:32   作者:小草原上的大羊駝  
這篇文章主要為大家介紹了Javascript中神奇的this,何為this?this的作用有哪些、以及this神奇的綁定規(guī)則,感興趣的小伙伴們可以參考一下

Javascript 當中的 this 與其他語言是完全不同的機制,很有可能會讓一些編寫其他語言的工程師迷惑。

1. 誤以為 this 指向函數(shù)自身

根據(jù) this 的英語語法,很容易將函數(shù)中出現(xiàn)的 this 理解為函數(shù)自身。在 javascript 當中函數(shù)作為一等公民,確實可以在調(diào)用的時候?qū)傩灾荡鎯ζ饋?。但是如果使用方法不對,就會發(fā)生與實際預(yù)期不一致的情況。具體情況,請看下面代碼

  function fn(num){
    this.count++;
  }
  
  fn.count = 0;
  
  for(var i=0;i<3;i++){
    fn(i);
  }
  console.log(fn.count); // 0

如果 fn 函數(shù)里面的 this 指向自身函數(shù),那么 count 屬性的屬性值就應(yīng)該產(chǎn)生變化,但實際上卻是紋絲不動。對于這個問題,有些人會利用作用域來解決,比如這么寫

  var data = {
    count:0
  };
  
  function fn(num){
    data.count++;
  }
  
  for(var i=0;i<3;i++){
    fn(i);
  }
  
  console.log(data.count);  //3

又或者更直接的這么寫

  function fn(num){
    fn.count++;
  }
  
  fn.count = 0;
  
  for(var i=0;i<3;i++){
    fn(i);
  }
  
  console.log(fn.count);//3

雖然這兩種方式都輸出了正確的結(jié)果,但是卻避開了 this 到底綁定在哪里的問題。如果對一個事物的工作原理不清晰,就往往會產(chǎn)生頭痛治頭,腳痛治腳的問題,從而導(dǎo)致代碼變得的丑陋,而且維護性也會變得很差。

2. this神奇的綁定規(guī)則

2.1 默認綁定規(guī)則

第一種是最常見的 this 的綁定,看一下下面的代碼

  function fn(){
    console.log(window === this); //瀏覽器環(huán)境
  }
  fn(); //true

函數(shù)fn 是直接在全局作用域下調(diào)用的,沒有帶其他任何修飾,這種情況下,函數(shù)調(diào)用的時候使用了 this 的默認綁定,指向了全局對象。

這樣就清楚了第一個例子中的 this 指向, fn 函數(shù)中的 this 指向了全局變量,所以 this.count++ 相當于 window.count++(瀏覽器環(huán)境下),當然不會對 fn 函數(shù)的count屬性產(chǎn)生影響。

有一點要說明的是,上面種情況只能在非嚴格模式(strict mode)下才能發(fā)生,在嚴格模式下,會將 this 默認綁定為 undefined。以避免全局變量的污染。

2.2 隱式綁定規(guī)則

如果函數(shù)在以對象為上下文進行調(diào)用,那么 this 的綁定就會產(chǎn)生變化。this 會綁定到調(diào)用這個函數(shù)的對象,查看下面代碼:

  var obj = {
    a:1,
    fn:function(){
      console.log(this.a);
    }
  }
  
  obj.fn(); //1

即使函數(shù)聲明不在對象當中,this 指向仍會產(chǎn)生變化

  function fn(){
    console.log(this.a);
  }
  var obj = {
    a:1,
    fn:fn
  }
  obj.fn(); //1

由此可見,this 的綁定,不與函數(shù)定義的位置有關(guān),而是與調(diào)用者和調(diào)用方式有關(guān)。

在隱式的綁定規(guī)則下,有一些特殊的地方,需要注意。

2.2.1 多層對象調(diào)用 this 的指向

  function fn(){
    console.log(this.a);
  }
  var obj = {
    a:1,
    obj2:obj2
  }
  var obj2 = {
    a:2,
    obj3:obj3
  }
  var obj3 = {
    a:3,
    fn:fn
  }
  
  obj.obj2.obj3.fn(); //3

在多層對象引用下,this 指向的是調(diào)用的函數(shù)的那個對象。

2.2.2 隱式賦值可能存在丟失現(xiàn)象

查看下面代碼

  function fn(){
    console.log(this);
  }
  var  obj = {
    fn:fn
  }
  
  var fun = obj.fn;
  fun(); //window

雖然 fn 引用了 obj.fun ,但是函數(shù)的調(diào)用方式,仍是不帶任何修飾的,所以 this 還是綁定在了 window 上。
還有一種情況,容易讓大家忽略,那就是傳參的時候,其實會進行隱式賦值。

 function fn(){
    console.log(this);
  }
  
  function doFn(fn){
    fn();
  }
  
  var obj = {
    fn:fn
  }
  
  doFn(obj.fn); //window

隱式綁定 this 不是一種很推薦的方式,因為很有可能就發(fā)生丟失的情況,如果業(yè)務(wù)當中對 this 的綁定有要求,建議還是使用顯示綁定的方式。

2.3 顯式綁定規(guī)則

顯示綁定就是利用函數(shù)原型上的 apply 與 call 方法來對 this 進行綁定。用法就是把想要綁定的對象作為第一個參數(shù)傳進去。

  function fn(){
    console.log(this);
  }
  
  var obj = {};
  
  fn.call(obj); //{}    

有些時候會想將函數(shù)的 this 綁定在某個對象上,但是不需要立即調(diào)用,這樣的話,直接利用 call 或者 apply 是無法做的。

  function fn(){
    console.log(this);
  }
  
  function bind(fn){
    fn();
  }
  
  var obj = {
    fn:fn
  }
  
  bind.call(obj,fn); //window

上面這個例子,看似好像可以,但實際上是 bind 函數(shù)的 this 綁定到了 obj 這個對象,但是 fn 仍然是沒有任何修飾的調(diào)用,所以 fn 仍然是默認的綁定方式。

  function fn(){
    console.log(this);
  }
  
  function bind(fn,obj){
    return function(){
      fn.apply(obj,arguments);
    }
  }
  
  var obj = {
    fn:fn
  }
  
  var fun = bind(fn,obj);
  fun(); //obj

這樣調(diào)用,就可以將靈活多變的 this ,牢牢的控制住了,因為 fn 的調(diào)用方式為 apply 調(diào)用。所以,this 就被綁定在傳入的 obj 對象上,在 ES5 當中,函數(shù)的原型方法上多了一個 bind。效果與上面的函數(shù)基本一致,具體用法限于篇幅就不多說了。

2.4 new 綁定

new 是一個被很多人誤解的一個關(guān)鍵字,但實際上 javascript 的 new 與傳統(tǒng)面向?qū)ο蟮恼Z言完全不同。
個人把 new 理解為一種特殊的函數(shù)調(diào)用,當使用 new 關(guān)鍵字來調(diào)用函數(shù)的時候,會執(zhí)行下面操作,

  • 創(chuàng)建一個全新的對象
  • 將空對象的 __proto__ 指向構(gòu)造函數(shù)的 prototype
  • 將新對象的 this 綁定到調(diào)用的函數(shù)上
  • 如果函數(shù)返回值為基本類型或者為 this又或者不返回任何值,那么將會返回這個創(chuàng)建的新對象,如果返回了一個對象,那么則會返回這個對象,而不會返回創(chuàng)建的新對象。
  function fn(a){
    this.a = a;
  }
  fn.prototype.hi = function(){
    console.log('hi')
  }
  
  var obj = new fn(2);
  
  console.log(obj);


  function fn(a){
    this.a = a;
    return {};
  }
  
  var obj = new fn(2);
  
  console.log(obj); //{}

2.5 特殊的傳參

null 和 undefined 也是可以作為 this 的綁定對象的,但是實際上應(yīng)用的是默認的綁定。
但是這種傳參的實際效用是什么呢?
常見的用法是將一個數(shù)組展開,作為參數(shù)傳入?yún)?shù)。比如

  function fn(a,b){
    console.log('a:',a,'b:',b);
  }
  
  fn.apply(null,[1,2]); // a: 1 b: 2

但是這種用法會有一個坑,那就是如果函數(shù)存在了 this ,那么就會應(yīng)用默認的綁定規(guī)則,將 this 綁定在全局對象上,發(fā)生于預(yù)期不一致的情況。為了代碼更加穩(wěn)健,可以使創(chuàng)建一個比空對象更空的對象。

var obj = Object.create(null);
console.log(obj.__proto__); //undefined

var obj2 = {}
console.log(obj2.__proto__); //Object {}

Object原型上有一個 create 方法,這個方法會創(chuàng)建一個對象,然后將對象的原型指向傳入的參數(shù),所以傳入 null 的話,產(chǎn)生一個沒有 prototype 的對象,所以會比空對象更加"空"。

所以傳入這個對象,會比傳入 null 更加安全。

var obj = Object.create(null);

fn.apply(obj,[1,2]);

2.6 根據(jù)作用域來決定 this 的綁定

在 ES6 當中,出現(xiàn)了一個新的函數(shù)類型,箭頭函數(shù)。

如果使用箭頭函數(shù),那么就不會使用上面提到的四種 this 綁定方式,而是根據(jù)作用域來決定

比較常見的是用于事件函數(shù)和定時器的情況。

下面是比較常見的傳統(tǒng) this 寫法

  function fn(){
    var _this = this;
    setTimeout(function(){
      console.log(_this.a);
    },100)
  }

  var obj = {
    a:2
  }
  
  fn.call(obj); //2
  

如果使用箭頭函數(shù)則可以這么寫

  function fn(){
    setTimeout(()=>{
      //this 來源于 fn 函數(shù)的作用域
      console.log(this.a);
    },100)
  }

  var obj = {
    a:2
  }
  
  fn.call(obj); //2

2.7 事件函數(shù)當中 this 的綁定機制

如果是在事件函數(shù)當中,this 的綁定是指向觸發(fā)事件的 DOM 元素的,

$('body')[0].addEventListener('click',function(){
  console.log(this);
},false);

點擊 body 元素之后,控制臺則會顯示 body 元素

3. 小結(jié)

如果想判斷一個函數(shù)的 this 綁定在哪里,首先是找到函數(shù)的調(diào)用位置,之后是按照規(guī)則來判斷。

  • 如果函數(shù)調(diào)用時沒有任何修飾條件,那么在嚴格模式下則會綁定到 undefined ,非嚴格模式下會綁定到全局。
  • 如果是用對象做上下文,來對函數(shù)進行調(diào)用,那么則會綁定到調(diào)用的這個對象上。
  • 如果是用 call 或者 apply 方法來進行調(diào)用的,則會綁定到第一個傳入?yún)?shù)上。
  • 如果是使用 new 關(guān)鍵字來調(diào)用函數(shù)的,則會綁定到新創(chuàng)建的那個對象上.
  • 如果是在事件函數(shù)內(nèi),則會綁定到觸發(fā)事件的那個DOM元素上。

以上就是關(guān)于Javascript中神奇的this的相關(guān)介紹,希望對大家的學(xué)習有所幫助。

相關(guān)文章

  • Javascript筆記一 js以及json基礎(chǔ)使用說明

    Javascript筆記一 js以及json基礎(chǔ)使用說明

    JavaScript中的數(shù)據(jù)很簡潔的。簡單數(shù)據(jù)只有 undefined, null, boolean, number和string這五種,而復(fù)雜數(shù)據(jù)只有一種,即object。
    2010-05-05
  • 嘗試在讓script的type屬性等于text/html

    嘗試在讓script的type屬性等于text/html

    我們可以在script片斷中定義一個被JS調(diào)用的代碼,但代碼又不在頁面上顯示,這時,我們可以使用下面的方法;當script中的type等于text/html時我們可以做些什么呢?感興趣的朋友可以了解下啊
    2013-01-01
  • 小程序模實現(xiàn)糊搜索功能

    小程序模實現(xiàn)糊搜索功能

    這篇文章主要為大家詳細介紹了小程序模實現(xiàn)糊搜索功能,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-06-06
  • JavaScript裝箱及拆箱boxing及unBoxing用法解析

    JavaScript裝箱及拆箱boxing及unBoxing用法解析

    這篇文章主要介紹了JavaScript裝箱及拆箱boxing及unBoxing用法解析,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習或者工作具有一定的參考學(xué)習價值,需要的朋友可以參考下
    2020-06-06
  • javascript之循環(huán)停頓上下滾動

    javascript之循環(huán)停頓上下滾動

    javascript之循環(huán)停頓上下滾動...
    2007-08-08
  • javascript 高級語法之繼承的基本使用方法示例

    javascript 高級語法之繼承的基本使用方法示例

    這篇文章主要介紹了javascript 高級語法之繼承的基本使用方法,結(jié)合實例形式分析了JavaScript繼承的基本使用方法與操作注意事項,需要的朋友可以參考下
    2019-11-11
  • Bootstrap每天必學(xué)之工具提示(Tooltip)插件

    Bootstrap每天必學(xué)之工具提示(Tooltip)插件

    Bootstrap每天必學(xué)之工具提示(Tooltip)插件,工具提示就是通過鼠標移動選定在特定的元素上時,顯示相關(guān)的提示語,感興趣的小伙伴們可以參考一下
    2016-04-04
  • javascript 數(shù)據(jù)存儲的常用函數(shù)總結(jié)

    javascript 數(shù)據(jù)存儲的常用函數(shù)總結(jié)

    這篇文章主要介紹了javascript 數(shù)據(jù)存儲的常用函數(shù)總結(jié)的相關(guān)資料,需要的朋友可以參考下
    2017-06-06
  • TypeScript 泛型的使用

    TypeScript 泛型的使用

    這篇文章主要介紹了TypeScript 泛型的使用,在JavaScript中,封裝一個API可以具有多種用途,因為其實弱類型語言,但是就因為是弱類型可以最終得到的結(jié)果并不是我們想要的,下面我們就來看看具體TypeScript 泛型的使用吧
    2021-12-12
  • js正則匹配出所有圖片及圖片地址src的方法

    js正則匹配出所有圖片及圖片地址src的方法

    這篇文章主要介紹了js正則匹配出所有圖片及圖片地址src的方法,涉及javascript正則匹配及頁面元素操作的相關(guān)技巧,需要的朋友可以參考下
    2015-06-06

最新評論